Merge "Allow for different rects when animating to a single task stack view and a multiple task stack view."
This commit is contained in:
@ -43,7 +43,11 @@
|
||||
android:textSize="24sp"
|
||||
android:textColor="#ffffffff"
|
||||
android:text="@string/recents_empty_message"
|
||||
android:fontFamily="sans-serif-thin" />
|
||||
android:fontFamily="sans-serif-thin"
|
||||
android:singleLine="true"
|
||||
android:maxLines="2"
|
||||
android:ellipsize="marquee"
|
||||
android:fadingEdge="horizontal" />
|
||||
<ImageView
|
||||
android:id="@+id/activity_icon"
|
||||
android:layout_width="@dimen/recents_task_view_activity_icon_size"
|
||||
|
@ -112,5 +112,7 @@
|
||||
<integer name="recents_filter_animate_current_views_min_duration">175</integer>
|
||||
<!-- The min animation duration for animating views that are newly visible. -->
|
||||
<integer name="recents_filter_animate_new_views_min_duration">125</integer>
|
||||
<!-- The min animation duration for animating views that are newly visible. -->
|
||||
<integer name="recents_animate_task_bar_enter_duration">200</integer>
|
||||
</resources>
|
||||
|
||||
|
@ -44,6 +44,7 @@ import android.view.View;
|
||||
import android.view.WindowManager;
|
||||
import com.android.systemui.R;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
/** A proxy implementation for the recents component */
|
||||
@ -57,8 +58,11 @@ public class AlternateRecentsComponent {
|
||||
Resources res = mContext.getResources();
|
||||
float statusBarHeight = res.getDimensionPixelSize(
|
||||
com.android.internal.R.dimen.status_bar_height);
|
||||
mFirstTaskRect = (Rect) msg.getData().getParcelable("taskRect");
|
||||
mFirstTaskRect.offset(0, (int) statusBarHeight);
|
||||
Bundle replyData = msg.getData().getParcelable("replyData");
|
||||
mSingleCountFirstTaskRect = replyData.getParcelable("singleCountTaskRect");
|
||||
mSingleCountFirstTaskRect.offset(0, (int) statusBarHeight);
|
||||
mMultipleCountFirstTaskRect = replyData.getParcelable("multipleCountTaskRect");
|
||||
mMultipleCountFirstTaskRect.offset(0, (int) statusBarHeight);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -114,7 +118,8 @@ public class AlternateRecentsComponent {
|
||||
RecentsServiceConnection mConnection = new RecentsServiceConnection();
|
||||
|
||||
View mStatusBarView;
|
||||
Rect mFirstTaskRect = new Rect();
|
||||
Rect mSingleCountFirstTaskRect = new Rect();
|
||||
Rect mMultipleCountFirstTaskRect = new Rect();
|
||||
long mLastToggleTime;
|
||||
|
||||
public AlternateRecentsComponent(Context context) {
|
||||
@ -227,20 +232,24 @@ public class AlternateRecentsComponent {
|
||||
return null;
|
||||
}
|
||||
|
||||
/** Returns whether there is a first task */
|
||||
boolean hasFirstTask() {
|
||||
/** Returns whether there is are multiple recents tasks */
|
||||
boolean hasMultipleRecentsTask() {
|
||||
// NOTE: Currently there's no method to get the number of non-home tasks, so we have to
|
||||
// compute this ourselves
|
||||
SystemServicesProxy ssp = mSystemServicesProxy;
|
||||
List<ActivityManager.RecentTaskInfo> tasks = ssp.getRecentTasks(1,
|
||||
List<ActivityManager.RecentTaskInfo> tasks = ssp.getRecentTasks(4,
|
||||
UserHandle.CURRENT.getIdentifier());
|
||||
for (ActivityManager.RecentTaskInfo t : tasks) {
|
||||
Iterator<ActivityManager.RecentTaskInfo> iter = tasks.iterator();
|
||||
while (iter.hasNext()) {
|
||||
ActivityManager.RecentTaskInfo t = iter.next();
|
||||
|
||||
// Skip tasks in the home stack
|
||||
if (ssp.isInHomeStack(t.persistentId)) {
|
||||
iter.remove();
|
||||
continue;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return (tasks.size() > 1);
|
||||
}
|
||||
|
||||
/** Converts from the device rotation to the degree */
|
||||
@ -287,8 +296,10 @@ public class AlternateRecentsComponent {
|
||||
// to launch the first task or dismiss itself
|
||||
SystemServicesProxy ssp = mSystemServicesProxy;
|
||||
List<ActivityManager.RunningTaskInfo> tasks = ssp.getRunningTasks(1);
|
||||
boolean isTopTaskHome = false;
|
||||
if (!tasks.isEmpty()) {
|
||||
ComponentName topActivity = tasks.get(0).topActivity;
|
||||
ActivityManager.RunningTaskInfo topTask = tasks.get(0);
|
||||
ComponentName topActivity = topTask.topActivity;
|
||||
|
||||
// Check if the front most activity is recents
|
||||
if (topActivity.getPackageName().equals(sRecentsPackage) &&
|
||||
@ -311,16 +322,30 @@ public class AlternateRecentsComponent {
|
||||
mLastToggleTime = System.currentTimeMillis();
|
||||
return;
|
||||
}
|
||||
|
||||
// Determine whether the top task is currently home
|
||||
isTopTaskHome = ssp.isInHomeStack(topTask.id);
|
||||
}
|
||||
|
||||
// Otherwise, Recents is not the front-most activity and we should animate into it
|
||||
Rect taskRect = mFirstTaskRect;
|
||||
if (taskRect != null && taskRect.width() > 0 && taskRect.height() > 0 && hasFirstTask()) {
|
||||
boolean hasMultipleTasks = hasMultipleRecentsTask();
|
||||
Rect taskRect = hasMultipleTasks ? mMultipleCountFirstTaskRect : mSingleCountFirstTaskRect;
|
||||
if (!isTopTaskHome && taskRect != null && taskRect.width() > 0 && taskRect.height() > 0) {
|
||||
// Loading from thumbnail
|
||||
Bitmap thumbnail;
|
||||
Bitmap firstThumbnail = loadFirstTaskThumbnail();
|
||||
if (firstThumbnail == null) {
|
||||
// Load the thumbnail from the screenshot
|
||||
if (firstThumbnail != null) {// Create the thumbnail
|
||||
thumbnail = Bitmap.createBitmap(taskRect.width(), taskRect.height(),
|
||||
Bitmap.Config.ARGB_8888);
|
||||
int size = Math.min(firstThumbnail.getWidth(), firstThumbnail.getHeight());
|
||||
Canvas c = new Canvas(thumbnail);
|
||||
c.drawBitmap(firstThumbnail, new Rect(0, 0, size, size),
|
||||
new Rect(0, 0, taskRect.width(), taskRect.height()), null);
|
||||
c.setBitmap(null);
|
||||
// Recycle the old thumbnail
|
||||
firstThumbnail.recycle();
|
||||
} else {
|
||||
// Load the thumbnail from the screenshot if can't get one from the system
|
||||
WindowManager wm = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
|
||||
Display display = wm.getDefaultDisplay();
|
||||
Bitmap screenshot = takeScreenshot(display);
|
||||
@ -328,29 +353,18 @@ public class AlternateRecentsComponent {
|
||||
int size = Math.min(screenshot.getWidth(), screenshot.getHeight());
|
||||
int statusBarHeight = res.getDimensionPixelSize(
|
||||
com.android.internal.R.dimen.status_bar_height);
|
||||
thumbnail = Bitmap.createBitmap(mFirstTaskRect.width(), mFirstTaskRect.height(),
|
||||
thumbnail = Bitmap.createBitmap(taskRect.width(), taskRect.height(),
|
||||
Bitmap.Config.ARGB_8888);
|
||||
Canvas c = new Canvas(thumbnail);
|
||||
c.drawBitmap(screenshot, new Rect(0, statusBarHeight, size, statusBarHeight + size),
|
||||
new Rect(0, 0, mFirstTaskRect.width(), mFirstTaskRect.height()), null);
|
||||
new Rect(0, 0, taskRect.width(), taskRect.height()), null);
|
||||
c.setBitmap(null);
|
||||
// Recycle the old screenshot
|
||||
// Recycle the temporary screenshot
|
||||
screenshot.recycle();
|
||||
} else {
|
||||
// Create the thumbnail
|
||||
thumbnail = Bitmap.createBitmap(mFirstTaskRect.width(), mFirstTaskRect.height(),
|
||||
Bitmap.Config.ARGB_8888);
|
||||
int size = Math.min(firstThumbnail.getWidth(), firstThumbnail.getHeight());
|
||||
Canvas c = new Canvas(thumbnail);
|
||||
c.drawBitmap(firstThumbnail, new Rect(0, 0, size, size),
|
||||
new Rect(0, 0, mFirstTaskRect.width(), mFirstTaskRect.height()), null);
|
||||
c.setBitmap(null);
|
||||
// Recycle the old thumbnail
|
||||
firstThumbnail.recycle();
|
||||
}
|
||||
|
||||
ActivityOptions opts = ActivityOptions.makeThumbnailScaleDownAnimation(mStatusBarView,
|
||||
thumbnail, mFirstTaskRect.left, mFirstTaskRect.top, null);
|
||||
thumbnail, taskRect.left, taskRect.top, null);
|
||||
startAlternateRecentsActivity(opts);
|
||||
} else {
|
||||
ActivityOptions opts = ActivityOptions.makeCustomAnimation(mContext,
|
||||
|
@ -72,8 +72,6 @@ public class Constants {
|
||||
public static class Window {
|
||||
// The dark background dim is set behind the empty recents view
|
||||
public static final float DarkBackgroundDim = 0.5f;
|
||||
// The background dim is set behind the card stack
|
||||
public static final float BackgroundDim = 0.35f;
|
||||
}
|
||||
|
||||
public static class RecentsTaskLoader {
|
||||
@ -100,9 +98,6 @@ public class Constants {
|
||||
public static class TaskView {
|
||||
public static final boolean AnimateFrontTaskIconOnEnterRecents = true;
|
||||
public static final boolean AnimateFrontTaskIconOnLeavingRecents = true;
|
||||
|
||||
public static final boolean UseRoundedCorners = false;
|
||||
public static final float RoundedCornerRadiusDps = 3;
|
||||
}
|
||||
}
|
||||
}
|
@ -39,6 +39,7 @@ public class RecentsConfiguration {
|
||||
|
||||
public int filteringCurrentViewsMinAnimDuration;
|
||||
public int filteringNewViewsMinAnimDuration;
|
||||
public int taskBarEnterAnimDuration;
|
||||
|
||||
/** Private constructor */
|
||||
private RecentsConfiguration() {}
|
||||
@ -76,6 +77,8 @@ public class RecentsConfiguration {
|
||||
res.getInteger(R.integer.recents_filter_animate_current_views_min_duration);
|
||||
filteringNewViewsMinAnimDuration =
|
||||
res.getInteger(R.integer.recents_filter_animate_new_views_min_duration);
|
||||
taskBarEnterAnimDuration =
|
||||
res.getInteger(R.integer.recents_animate_task_bar_enter_duration);
|
||||
}
|
||||
|
||||
public void updateSystemInsets(Rect insets) {
|
||||
|
@ -26,6 +26,7 @@ import android.os.IBinder;
|
||||
import android.os.Message;
|
||||
import android.os.Messenger;
|
||||
import android.os.RemoteException;
|
||||
import com.android.systemui.recents.model.Task;
|
||||
import com.android.systemui.recents.model.TaskStack;
|
||||
import com.android.systemui.recents.views.TaskStackView;
|
||||
import com.android.systemui.recents.views.TaskViewTransform;
|
||||
@ -62,14 +63,27 @@ class SystemUIMessageHandler extends Handler {
|
||||
// Create a dummy task stack & compute the rect for the thumbnail to animate to
|
||||
TaskStack stack = new TaskStack(context);
|
||||
TaskStackView tsv = new TaskStackView(context, stack);
|
||||
// Since the nav bar height is already accounted for in the windowRect, don't pass
|
||||
// in a bottom inset
|
||||
Bundle replyData = new Bundle();
|
||||
TaskViewTransform transform;
|
||||
|
||||
// Calculate the target task rect for when there is one task
|
||||
// NOTE: Since the nav bar height is already accounted for in the windowRect, don't
|
||||
// pass in a bottom inset
|
||||
stack.addTask(new Task());
|
||||
tsv.computeRects(windowRect.width(), windowRect.height() - systemInsets.top, 0);
|
||||
tsv.boundScroll();
|
||||
TaskViewTransform transform = tsv.getStackTransform(0, tsv.getStackScroll());
|
||||
Rect taskRect = new Rect(transform.rect);
|
||||
transform = tsv.getStackTransform(0, tsv.getStackScroll());
|
||||
replyData.putParcelable("singleCountTaskRect", new Rect(transform.rect));
|
||||
|
||||
data.putParcelable("taskRect", taskRect);
|
||||
// Also calculate the target task rect when there are multiple tasks
|
||||
stack.addTask(new Task());
|
||||
tsv.computeRects(windowRect.width(), windowRect.height() - systemInsets.top, 0);
|
||||
tsv.setStackScrollRaw(Integer.MAX_VALUE);
|
||||
tsv.boundScroll();
|
||||
transform = tsv.getStackTransform(1, tsv.getStackScroll());
|
||||
replyData.putParcelable("multipleCountTaskRect", new Rect(transform.rect));
|
||||
|
||||
data.putParcelable("replyData", replyData);
|
||||
Message reply = Message.obtain(null,
|
||||
RecentsService.MSG_UPDATE_RECENTS_FOR_CONFIGURATION, 0, 0);
|
||||
reply.setData(data);
|
||||
|
@ -358,18 +358,9 @@ public class RecentsTaskLoader {
|
||||
return mSystemServicesProxy;
|
||||
}
|
||||
|
||||
/** Reload the set of recent tasks */
|
||||
SpaceNode reload(Context context, int preloadCount) {
|
||||
Console.log(Constants.DebugFlags.App.TaskDataLoader, "[RecentsTaskLoader|reload]");
|
||||
Resources res = context.getResources();
|
||||
ArrayList<Task> tasksToForceLoad = new ArrayList<Task>();
|
||||
TaskStack stack = new TaskStack(context);
|
||||
SpaceNode root = new SpaceNode(context);
|
||||
root.setStack(stack);
|
||||
|
||||
private List<ActivityManager.RecentTaskInfo> getRecentTasks(Context context) {
|
||||
long t1 = System.currentTimeMillis();
|
||||
|
||||
// Get the recent tasks
|
||||
SystemServicesProxy ssp = mSystemServicesProxy;
|
||||
List<ActivityManager.RecentTaskInfo> tasks =
|
||||
ssp.getRecentTasks(25, UserHandle.CURRENT.getIdentifier());
|
||||
@ -397,6 +388,24 @@ public class RecentsTaskLoader {
|
||||
}
|
||||
}
|
||||
|
||||
return tasks;
|
||||
}
|
||||
|
||||
/** Reload the set of recent tasks */
|
||||
SpaceNode reload(Context context, int preloadCount) {
|
||||
long t1 = System.currentTimeMillis();
|
||||
|
||||
Console.log(Constants.DebugFlags.App.TaskDataLoader, "[RecentsTaskLoader|reload]");
|
||||
Resources res = context.getResources();
|
||||
ArrayList<Task> tasksToForceLoad = new ArrayList<Task>();
|
||||
TaskStack stack = new TaskStack(context);
|
||||
SpaceNode root = new SpaceNode(context);
|
||||
root.setStack(stack);
|
||||
|
||||
// Get the recent tasks
|
||||
SystemServicesProxy ssp = mSystemServicesProxy;
|
||||
List<ActivityManager.RecentTaskInfo> tasks = getRecentTasks(context);
|
||||
|
||||
// Add each task to the task stack
|
||||
t1 = System.currentTimeMillis();
|
||||
int taskCount = tasks.size();
|
||||
|
@ -69,6 +69,10 @@ public class Task {
|
||||
|
||||
TaskCallbacks mCb;
|
||||
|
||||
public Task() {
|
||||
// Only used by RecentsService for task rect calculations.
|
||||
}
|
||||
|
||||
public Task(int id, boolean isActive, Intent intent, String activityTitle,
|
||||
Bitmap activityIcon, int userId) {
|
||||
this.key = new TaskKey(id, intent);
|
||||
|
@ -171,7 +171,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
|
||||
transform.visible = false;
|
||||
} else {
|
||||
transform.rect.offset(0, transform.translationY);
|
||||
Utilities.scaleRectAboutCenter(transform.rect, scale);
|
||||
Utilities.scaleRectAboutCenter(transform.rect, transform.scale);
|
||||
transform.visible = Rect.intersects(mRect, transform.rect);
|
||||
}
|
||||
transform.t = t;
|
||||
@ -388,8 +388,14 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
|
||||
int stackHeight = mStackRectSansPeek.height();
|
||||
int maxScrollHeight = taskHeight + (int) ((numTasks - 1) *
|
||||
Constants.Values.TaskStackView.StackOverlapPct * taskHeight);
|
||||
mMinScroll = Math.min(stackHeight, maxScrollHeight) - stackHeight;
|
||||
mMaxScroll = maxScrollHeight - stackHeight;
|
||||
|
||||
if (numTasks <= 1) {
|
||||
// If there is only one task, then center the task in the stack rect (sans peek)
|
||||
mMinScroll = mMaxScroll = -(stackHeight - taskHeight) / 2;
|
||||
} else {
|
||||
mMinScroll = Math.min(stackHeight, maxScrollHeight) - stackHeight;
|
||||
mMaxScroll = maxScrollHeight - stackHeight;
|
||||
}
|
||||
|
||||
// Debug logging
|
||||
if (Constants.DebugFlags.UI.MeasureAndLayout) {
|
||||
@ -479,8 +485,8 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
|
||||
// Clip against the next view (if we aren't animating its alpha)
|
||||
nextTv = (TaskView) getChildAt(curIndex + 1);
|
||||
if (nextTv.getAlpha() == 1f) {
|
||||
Rect curRect = tv.getClippingRect(mTmpRect, false);
|
||||
Rect nextRect = nextTv.getClippingRect(mTmpRect2, true);
|
||||
Rect curRect = tv.getClippingRect(mTmpRect);
|
||||
Rect nextRect = nextTv.getClippingRect(mTmpRect2);
|
||||
RecentsConfiguration config = RecentsConfiguration.getInstance();
|
||||
// The hit rects are relative to the task view, which needs to be offset by the
|
||||
// system bar height
|
||||
@ -523,7 +529,6 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
|
||||
int minHeight = (int) (mStackRect.height() -
|
||||
(Constants.Values.TaskStackView.StackPeekHeightPct * mStackRect.height()));
|
||||
int size = Math.min(minHeight, Math.min(mStackRect.width(), mStackRect.height()));
|
||||
int centerX = mStackRect.centerX();
|
||||
mTaskRect.set(mStackRect.left, mStackRectSansPeek.top,
|
||||
mStackRect.right, mStackRectSansPeek.top + size);
|
||||
|
||||
|
@ -20,9 +20,8 @@ import android.animation.Animator;
|
||||
import android.animation.AnimatorSet;
|
||||
import android.animation.ObjectAnimator;
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Outline;
|
||||
import android.graphics.Path;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.RectF;
|
||||
@ -36,8 +35,6 @@ import com.android.systemui.recents.RecentsConfiguration;
|
||||
import com.android.systemui.recents.Utilities;
|
||||
import com.android.systemui.recents.model.Task;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
|
||||
/* A task view */
|
||||
public class TaskView extends FrameLayout implements View.OnClickListener, Task.TaskCallbacks {
|
||||
@ -54,8 +51,6 @@ public class TaskView extends FrameLayout implements View.OnClickListener, Task.
|
||||
TaskBarView mBarView;
|
||||
TaskViewCallbacks mCb;
|
||||
|
||||
Path mRoundedRectClipPath = new Path();
|
||||
|
||||
|
||||
public TaskView(Context context) {
|
||||
this(context, null);
|
||||
@ -71,7 +66,6 @@ public class TaskView extends FrameLayout implements View.OnClickListener, Task.
|
||||
|
||||
public TaskView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
|
||||
super(context, attrs, defStyleAttr, defStyleRes);
|
||||
setWillNotDraw(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -85,31 +79,6 @@ public class TaskView extends FrameLayout implements View.OnClickListener, Task.
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
||||
|
||||
// Update the rounded rect clip path
|
||||
RecentsConfiguration config = RecentsConfiguration.getInstance();
|
||||
float radius = config.pxFromDp(Constants.Values.TaskView.RoundedCornerRadiusDps);
|
||||
mRoundedRectClipPath.reset();
|
||||
mRoundedRectClipPath.addRoundRect(new RectF(0, 0, getMeasuredWidth(), getMeasuredHeight()),
|
||||
radius, radius, Path.Direction.CW);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void dispatchDraw(Canvas canvas) {
|
||||
int restoreCount = 0;
|
||||
if (Constants.Values.TaskView.UseRoundedCorners) {
|
||||
restoreCount = canvas.save();
|
||||
canvas.clipPath(mRoundedRectClipPath);
|
||||
}
|
||||
super.dispatchDraw(canvas);
|
||||
if (Constants.Values.TaskView.UseRoundedCorners) {
|
||||
canvas.restoreToCount(restoreCount);
|
||||
}
|
||||
}
|
||||
|
||||
/** Set callback */
|
||||
void setCallbacks(TaskViewCallbacks cb) {
|
||||
mCb = cb;
|
||||
@ -195,7 +164,7 @@ public class TaskView extends FrameLayout implements View.OnClickListener, Task.
|
||||
.translationY(0)
|
||||
.setStartDelay(235)
|
||||
.setInterpolator(BakedBezierInterpolator.INSTANCE)
|
||||
.setDuration(Utilities.calculateTranslationAnimationDuration(translate))
|
||||
.setDuration(config.taskBarEnterAnimDuration)
|
||||
.withLayer()
|
||||
.start();
|
||||
}
|
||||
@ -214,23 +183,21 @@ public class TaskView extends FrameLayout implements View.OnClickListener, Task.
|
||||
.setInterpolator(BakedBezierInterpolator.INSTANCE)
|
||||
.setDuration(Utilities.calculateTranslationAnimationDuration(translate))
|
||||
.withLayer()
|
||||
.withEndAction(r)
|
||||
.withEndAction(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
post(r);
|
||||
}
|
||||
})
|
||||
.start();
|
||||
}
|
||||
|
||||
/** Returns the rect we want to clip (it may not be the full rect) */
|
||||
Rect getClippingRect(Rect outRect, boolean accountForRoundedRects) {
|
||||
Rect getClippingRect(Rect outRect) {
|
||||
getHitRect(outRect);
|
||||
// XXX: We should get the hit rect of the thumbnail view and intersect, but this is faster
|
||||
outRect.right = outRect.left + mThumbnailView.getRight();
|
||||
outRect.bottom = outRect.top + mThumbnailView.getBottom();
|
||||
// We need to shrink the next rect by the rounded corners since those are draw on
|
||||
// top of the current view
|
||||
if (accountForRoundedRects) {
|
||||
RecentsConfiguration config = RecentsConfiguration.getInstance();
|
||||
float radius = config.pxFromDp(Constants.Values.TaskView.RoundedCornerRadiusDps);
|
||||
outRect.inset((int) radius, (int) radius);
|
||||
}
|
||||
return outRect;
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user