Fixing regression in stack task clipping.
- Removing expensive calls to map coordinates of front task to the tasks
behind it, instead relying on the precalculated task rects that we
already compute on each stack change update. To prevent rounding
issues, the task rects are now float rects.
- Also fixing crash when RecentsActivity starts before the SystemUI
component (only an issue when pushing SysUI apks)
Change-Id: Ia84e9b9d165c0ce171c7fe3797e561ef24157a0a
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
index 0f23d82..331a124 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
@@ -74,6 +74,7 @@
RecentsConfiguration mConfig;
RecentsPackageMonitor mPackageMonitor;
long mLastTabKeyEventTime;
+ boolean mFinishedOnStartup;
// Top level views
RecentsView mRecentsView;
@@ -298,6 +299,16 @@
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ mFinishedOnStartup = false;
+
+ // In the case that the activity starts up before the Recents component has initialized
+ // (usually when debugging/pushing the SysUI apk), just finish this activity.
+ SystemServicesProxy ssp = Recents.getSystemServices();
+ if (ssp == null) {
+ mFinishedOnStartup = true;
+ finish();
+ return;
+ }
// Register this activity with the event bus
EventBus.getDefault().register(this, EVENT_BUS_PRIORITY);
@@ -319,7 +330,6 @@
mScrimViews = new SystemBarScrimViews(this);
// Bind the search app widget when we first start up
- SystemServicesProxy ssp = Recents.getSystemServices();
mSearchWidgetInfo = ssp.getOrBindSearchAppWidget(this, mAppWidgetHost);
// Register the broadcast receiver to handle messages when the screen is turned off
@@ -398,6 +408,11 @@
protected void onDestroy() {
super.onDestroy();
+ // In the case that the activity finished on startup, just skip the unregistration below
+ if (mFinishedOnStartup) {
+ return;
+ }
+
// Unregister the system broadcast receivers
unregisterReceiver(mSystemBroadcastReceiver);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
index 03097ea..aaeb10c 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
@@ -26,10 +26,10 @@
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Rect;
+import android.graphics.RectF;
import android.os.Handler;
import android.os.SystemClock;
import android.os.UserHandle;
-import android.util.Log;
import android.util.MutableBoolean;
import android.view.LayoutInflater;
import android.view.View;
@@ -540,7 +540,7 @@
Task toTask = new Task();
TaskViewTransform toTransform = getThumbnailTransitionTransform(stack, stackView,
topTask.id, toTask);
- Rect toTaskRect = toTransform.rect;
+ RectF toTaskRect = toTransform.rect;
Bitmap thumbnail;
if (mThumbnailTransitionBitmapCacheKey != null
&& mThumbnailTransitionBitmapCacheKey.key != null
@@ -554,8 +554,8 @@
}
if (thumbnail != null) {
return ActivityOptions.makeThumbnailAspectScaleDownAnimation(mDummyStackView,
- thumbnail, toTaskRect.left, toTaskRect.top, toTaskRect.width(),
- toTaskRect.height(), mHandler, this);
+ thumbnail, (int) toTaskRect.left, (int) toTaskRect.top,
+ (int) toTaskRect.width(), (int) toTaskRect.height(), mHandler, this);
}
// If both the screenshot and thumbnail fails, then just fall back to the default transition
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java b/packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java
index 93c5ee7..2bf2ccb 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java
@@ -18,13 +18,10 @@
import android.animation.Animator;
import android.graphics.Color;
-import android.graphics.Matrix;
-import android.graphics.Rect;
+import android.graphics.RectF;
import android.view.View;
import android.view.ViewParent;
-import java.util.ArrayList;
-
/* Common code */
public class Utilities {
@@ -45,93 +42,19 @@
}
/** Scales a rect about its centroid */
- public static void scaleRectAboutCenter(Rect r, float scale) {
+ public static void scaleRectAboutCenter(RectF r, float scale) {
if (scale != 1.0f) {
- int cx = r.centerX();
- int cy = r.centerY();
+ float cx = r.centerX();
+ float cy = r.centerY();
r.offset(-cx, -cy);
- r.left = (int) (r.left * scale + 0.5f);
- r.top = (int) (r.top * scale + 0.5f);
- r.right = (int) (r.right * scale + 0.5f);
- r.bottom = (int) (r.bottom * scale + 0.5f);
+ r.left *= scale;
+ r.top *= scale;
+ r.right *= scale;
+ r.bottom *= scale;
r.offset(cx, cy);
}
}
- /** Maps a coorindate in a descendant view into the parent. */
- public static float mapCoordInDescendentToSelf(View descendant, View root,
- float[] coord, boolean includeRootScroll) {
- ArrayList<View> ancestorChain = new ArrayList<View>();
-
- float[] pt = {coord[0], coord[1]};
-
- View v = descendant;
- while(v != root && v != null) {
- ancestorChain.add(v);
- v = (View) v.getParent();
- }
- ancestorChain.add(root);
-
- float scale = 1.0f;
- int count = ancestorChain.size();
- for (int i = 0; i < count; i++) {
- View v0 = ancestorChain.get(i);
- // For TextViews, scroll has a meaning which relates to the text position
- // which is very strange... ignore the scroll.
- if (v0 != descendant || includeRootScroll) {
- pt[0] -= v0.getScrollX();
- pt[1] -= v0.getScrollY();
- }
-
- v0.getMatrix().mapPoints(pt);
- pt[0] += v0.getLeft();
- pt[1] += v0.getTop();
- scale *= v0.getScaleX();
- }
-
- coord[0] = pt[0];
- coord[1] = pt[1];
- return scale;
- }
-
- /** Maps a coordinate in the root to a descendent. */
- public static float mapCoordInSelfToDescendent(View descendant, View root,
- float[] coord, Matrix tmpInverseMatrix) {
- ArrayList<View> ancestorChain = new ArrayList<View>();
-
- float[] pt = {coord[0], coord[1]};
-
- View v = descendant;
- while(v != root) {
- ancestorChain.add(v);
- v = (View) v.getParent();
- }
- ancestorChain.add(root);
-
- float scale = 1.0f;
- int count = ancestorChain.size();
- tmpInverseMatrix.set(Matrix.IDENTITY_MATRIX);
- for (int i = count - 1; i >= 0; i--) {
- View ancestor = ancestorChain.get(i);
- View next = i > 0 ? ancestorChain.get(i-1) : null;
-
- pt[0] += ancestor.getScrollX();
- pt[1] += ancestor.getScrollY();
-
- if (next != null) {
- pt[0] -= next.getLeft();
- pt[1] -= next.getTop();
- next.getMatrix().invert(tmpInverseMatrix);
- tmpInverseMatrix.mapPoints(pt);
- scale *= next.getScaleX();
- }
- }
-
- coord[0] = pt[0];
- coord[1] = pt[1];
- return scale;
- }
-
/** Calculates the constrast between two colors, using the algorithm provided by the WCAG v2. */
public static float computeContrastBetweenColors(int bg, int fg) {
float bgR = Color.red(bg) / 255f;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
index 6bdd7de..7f618e3 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
@@ -594,8 +594,8 @@
final int left = pts[0] + offsetX;
final int top = pts[1] + offsetY;
- final Rect rect = new Rect(left, top, left + transform.rect.width(),
- top + transform.rect.height());
+ final Rect rect = new Rect(left, top, left + (int) transform.rect.width(),
+ top + (int) transform.rect.height());
return new AppTransitionAnimationSpec(taskId, b, rect);
}
@@ -622,7 +622,7 @@
// and then offset to the expected transform rect, but bound this to just
// outside the display rect (to ensure we don't animate from too far away)
sourceView = stackView;
- offsetX = transform.rect.left;
+ offsetX = (int) transform.rect.left;
offsetY = getMeasuredHeight();
} else {
sourceView = tv.mThumbnailView;
@@ -656,7 +656,7 @@
animStartedListener, destinationStack);
opts = ActivityOptions.makeThumbnailAspectScaleUpAnimation(sourceView,
Bitmap.createBitmap(1, 1, Bitmap.Config.ALPHA_8).createAshmemBitmap(),
- offsetX, offsetY, transform.rect.width(), transform.rect.height(),
+ offsetX, offsetY, (int) transform.rect.width(), (int) transform.rect.height(),
sourceView.getHandler(), animStartedListener);
} else {
opts = ActivityOptions.makeBasic();
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
index 74125f9..5928854 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
@@ -20,8 +20,8 @@
import android.content.ComponentName;
import android.content.Context;
import android.graphics.Canvas;
-import android.graphics.Matrix;
import android.graphics.Rect;
+import android.graphics.RectF;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.MotionEvent;
@@ -89,11 +89,11 @@
boolean mStartEnterAnimationRequestedAfterLayout;
boolean mStartEnterAnimationCompleted;
ViewAnimation.TaskViewEnterContext mStartEnterAnimationContext;
+
Rect mTaskStackBounds = new Rect();
int[] mTmpVisibleRange = new int[2];
- float[] mTmpCoord = new float[2];
- Matrix mTmpMatrix = new Matrix();
Rect mTmpRect = new Rect();
+ RectF mTmpTaskRect = new RectF();
TaskViewTransform mTmpTransform = new TaskViewTransform();
HashMap<Task, TaskView> mTmpTaskViewMap = new HashMap<>();
ArrayList<TaskView> mTaskViews = new ArrayList<>();
@@ -412,23 +412,24 @@
return false;
}
- /** Updates the clip for each of the task views. */
+ /**
+ * Updates the clip for each of the task views from back to front.
+ */
void clipTaskViews() {
// Update the clip on each task child
List<TaskView> taskViews = getTaskViews();
+ TaskView tmpTv = null;
int taskViewCount = taskViews.size();
- for (int i = 0; i < taskViewCount - 1; i++) {
+ for (int i = 0; i < taskViewCount; i++) {
TaskView tv = taskViews.get(i);
- TaskView nextTv = null;
- TaskView tmpTv = null;
+ TaskView frontTv = null;
int clipBottom = 0;
- if (tv.shouldClipViewInStack()) {
+ if (i < (taskViewCount - 1) && tv.shouldClipViewInStack()) {
// Find the next view to clip against
- int nextIndex = i;
- while (nextIndex < (taskViewCount - 1)) {
- tmpTv = taskViews.get(++nextIndex);
- if (tmpTv != null && tmpTv.shouldClipViewInStack()) {
- nextTv = tmpTv;
+ for (int j = i + 1; j < taskViewCount; j++) {
+ tmpTv = taskViews.get(j);
+ if (tmpTv.shouldClipViewInStack()) {
+ frontTv = tmpTv;
break;
}
}
@@ -436,23 +437,23 @@
// Clip against the next view, this is just an approximation since we are
// stacked and we can make assumptions about the visibility of the this
// task relative to the ones in front of it.
- if (nextTv != null) {
- // Map the top edge of next task view into the local space of the current
- // task view to find the clip amount in local space
- mTmpCoord[0] = mTmpCoord[1] = 0;
- Utilities.mapCoordInDescendentToSelf(nextTv, this, mTmpCoord, false);
- Utilities.mapCoordInSelfToDescendent(tv, this, mTmpCoord, mTmpMatrix);
- clipBottom = (int) Math.floor(tv.getMeasuredHeight() - mTmpCoord[1]
- - nextTv.getPaddingTop() - 1);
+ if (frontTv != null) {
+ mTmpTaskRect.set(mLayoutAlgorithm.mTaskRect);
+ mTmpTaskRect.offset(0, tv.getTranslationY());
+ Utilities.scaleRectAboutCenter(mTmpTaskRect, tv.getScaleX());
+ float taskBottom = mTmpTaskRect.bottom;
+ mTmpTaskRect.set(mLayoutAlgorithm.mTaskRect);
+ mTmpTaskRect.offset(0, frontTv.getTranslationY());
+ Utilities.scaleRectAboutCenter(mTmpTaskRect, frontTv.getScaleX());
+ float frontTaskTop = mTmpTaskRect.top;
+ if (frontTaskTop < taskBottom) {
+ // Map the stack view space coordinate (the rects) to view space
+ clipBottom = (int) ((taskBottom - frontTaskTop) / tv.getScaleX()) - 1;
+ }
}
}
tv.getViewBounds().setClipBottom(clipBottom);
}
- if (taskViewCount > 0) {
- // The front most task should never be clipped
- TaskView tv = taskViews.get(taskViewCount - 1);
- tv.getViewBounds().setClipBottom(0);
- }
mStackViewsClipDirty = false;
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java
index f8f7052..ec50eb6 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java
@@ -17,7 +17,7 @@
package com.android.systemui.recents.views;
import android.animation.ValueAnimator;
-import android.graphics.Rect;
+import android.graphics.RectF;
import android.view.View;
import android.view.ViewPropertyAnimator;
import android.view.animation.Interpolator;
@@ -35,7 +35,7 @@
// This is a window-space rect that is purely used for coordinating the animation of an app
// window into Recents.
- public Rect rect = new Rect();
+ public RectF rect = new RectF();
public TaskViewTransform() {
// Do nothing