Merge "Make entering recents a lot faster" into mnc-dev
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Recents.java b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
index bbd3e60..7d2b5c87 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Recents.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
@@ -32,6 +32,7 @@
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Rect;
+import android.os.AsyncTask;
import android.os.Handler;
import android.os.SystemClock;
import android.os.UserHandle;
@@ -40,6 +41,7 @@
import android.view.Display;
import android.view.LayoutInflater;
import android.view.View;
+
import com.android.systemui.R;
import com.android.systemui.RecentsComponent;
import com.android.systemui.SystemUI;
@@ -184,12 +186,16 @@
// Header (for transition)
TaskViewHeader mHeaderBar;
+ final Object mHeaderBarLock = new Object();
TaskStackView mDummyStackView;
// Variables to keep track of if we need to start recents after binding
boolean mTriggeredFromAltTab;
long mLastToggleTime;
+ Bitmap mThumbnailTransitionBitmapCache;
+ Task mThumbnailTransitionBitmapCacheKey;
+
public Recents() {
}
@@ -360,13 +366,16 @@
void preloadRecentsInternal() {
// Preload only the raw task list into a new load plan (which will be consumed by the
// RecentsActivity)
+ ActivityManager.RunningTaskInfo topTask = mSystemServicesProxy.getTopMostTask();
+ MutableBoolean topTaskHome = new MutableBoolean(true);
RecentsTaskLoader loader = RecentsTaskLoader.getInstance();
sInstanceLoadPlan = loader.createLoadPlan(mContext);
-
- ActivityManager.RunningTaskInfo topTask = mSystemServicesProxy.getTopMostTask();
- MutableBoolean isTopTaskHome = new MutableBoolean(true);
- if (topTask != null && mSystemServicesProxy.isRecentsTopMost(topTask, isTopTaskHome)) {
- sInstanceLoadPlan.preloadRawTasks(isTopTaskHome.value);
+ if (topTask != null && !mSystemServicesProxy.isRecentsTopMost(topTask, topTaskHome)) {
+ sInstanceLoadPlan.preloadRawTasks(topTaskHome.value);
+ loader.preloadTasks(sInstanceLoadPlan, topTaskHome.value);
+ TaskStack top = sInstanceLoadPlan.getAllTaskStacks().get(0);
+ preCacheThumbnailTransitionBitmapAsync(topTask, top, mDummyStackView,
+ topTaskHome.value);
}
}
@@ -513,12 +522,14 @@
algo.computeRects(mWindowRect.width(), mWindowRect.height(), taskStackBounds);
Rect taskViewSize = algo.getUntransformedTaskViewSize();
int taskBarHeight = res.getDimensionPixelSize(R.dimen.recents_task_bar_height);
- mHeaderBar = (TaskViewHeader) mInflater.inflate(R.layout.recents_task_view_header, null,
- false);
- mHeaderBar.measure(
- View.MeasureSpec.makeMeasureSpec(taskViewSize.width(), View.MeasureSpec.EXACTLY),
- View.MeasureSpec.makeMeasureSpec(taskBarHeight, View.MeasureSpec.EXACTLY));
- mHeaderBar.layout(0, 0, taskViewSize.width(), taskBarHeight);
+ synchronized (mHeaderBarLock) {
+ mHeaderBar = (TaskViewHeader) mInflater.inflate(R.layout.recents_task_view_header, null,
+ false);
+ mHeaderBar.measure(
+ View.MeasureSpec.makeMeasureSpec(taskViewSize.width(), View.MeasureSpec.EXACTLY),
+ View.MeasureSpec.makeMeasureSpec(taskBarHeight, View.MeasureSpec.EXACTLY));
+ mHeaderBar.layout(0, 0, taskViewSize.width(), taskBarHeight);
+ }
}
/** Prepares the search bar app widget */
@@ -607,30 +618,27 @@
*/
ActivityOptions getThumbnailTransitionActivityOptions(ActivityManager.RunningTaskInfo topTask,
TaskStack stack, TaskStackView stackView) {
+
// Update the destination rect
Task toTask = new Task();
TaskViewTransform toTransform = getThumbnailTransitionTransform(stack, stackView,
topTask.id, toTask);
- if (toTransform != null && toTask.key != null) {
- Rect toTaskRect = toTransform.rect;
- int toHeaderWidth = (int) (mHeaderBar.getMeasuredWidth() * toTransform.scale);
- int toHeaderHeight = (int) (mHeaderBar.getMeasuredHeight() * toTransform.scale);
- Bitmap thumbnail = Bitmap.createBitmap(toHeaderWidth, toHeaderHeight,
- Bitmap.Config.ARGB_8888);
- if (Constants.DebugFlags.App.EnableTransitionThumbnailDebugMode) {
- thumbnail.eraseColor(0xFFff0000);
- } else {
- Canvas c = new Canvas(thumbnail);
- c.scale(toTransform.scale, toTransform.scale);
- mHeaderBar.rebindToTask(toTask);
- mHeaderBar.draw(c);
- c.setBitmap(null);
- }
- Bitmap thumbnailImmutable = thumbnail.createAshmemBitmap();
-
+ Rect toTaskRect = toTransform.rect;
+ Bitmap thumbnail;
+ if (mThumbnailTransitionBitmapCacheKey != null
+ && mThumbnailTransitionBitmapCacheKey.key != null
+ && mThumbnailTransitionBitmapCacheKey.key.equals(toTask.key)) {
+ thumbnail = mThumbnailTransitionBitmapCache;
+ mThumbnailTransitionBitmapCacheKey = null;
+ mThumbnailTransitionBitmapCache = null;
+ } else {
+ preloadIcon(topTask);
+ thumbnail = drawThumbnailTransitionBitmap(toTask, toTransform);
+ }
+ if (thumbnail != null) {
mStartAnimationTriggered = false;
return ActivityOptions.makeThumbnailAspectScaleDownAnimation(mDummyStackView,
- thumbnailImmutable, toTaskRect.left, toTaskRect.top, toTaskRect.width(),
+ thumbnail, toTaskRect.left, toTaskRect.top, toTaskRect.width(),
toTaskRect.height(), mHandler, this);
}
@@ -638,6 +646,72 @@
return getUnknownTransitionActivityOptions();
}
+ /**
+ * Preloads the icon of a task.
+ */
+ void preloadIcon(ActivityManager.RunningTaskInfo task) {
+
+ // Ensure that we load the running task's icon
+ RecentsTaskLoadPlan.Options launchOpts = new RecentsTaskLoadPlan.Options();
+ launchOpts.runningTaskId = task.id;
+ launchOpts.loadThumbnails = false;
+ launchOpts.onlyLoadForCache = true;
+ RecentsTaskLoader.getInstance().loadTasks(mContext, sInstanceLoadPlan, launchOpts);
+ }
+
+ /**
+ * Caches the header thumbnail used for a window animation asynchronously into
+ * {@link #mThumbnailTransitionBitmapCache}.
+ */
+ void preCacheThumbnailTransitionBitmapAsync(ActivityManager.RunningTaskInfo topTask,
+ TaskStack stack, TaskStackView stackView, boolean isTopTaskHome) {
+ preloadIcon(topTask);
+
+ // Update the destination rect
+ mDummyStackView.updateMinMaxScrollForStack(stack, mTriggeredFromAltTab, isTopTaskHome);
+ final Task toTask = new Task();
+ final TaskViewTransform toTransform = getThumbnailTransitionTransform(stack, stackView,
+ topTask.id, toTask);
+ new AsyncTask<Void, Void, Bitmap>() {
+ @Override
+ protected Bitmap doInBackground(Void... params) {
+ return drawThumbnailTransitionBitmap(toTask, toTransform);
+ }
+
+ @Override
+ protected void onPostExecute(Bitmap bitmap) {
+ mThumbnailTransitionBitmapCache = bitmap;
+ mThumbnailTransitionBitmapCacheKey = toTask;
+ }
+ }.execute();
+ }
+
+ /**
+ * Draws the header of a task used for the window animation into a bitmap.
+ */
+ Bitmap drawThumbnailTransitionBitmap(Task toTask, TaskViewTransform toTransform) {
+ if (toTransform != null && toTask.key != null) {
+ Bitmap thumbnail;
+ synchronized (mHeaderBarLock) {
+ int toHeaderWidth = (int) (mHeaderBar.getMeasuredWidth() * toTransform.scale);
+ int toHeaderHeight = (int) (mHeaderBar.getMeasuredHeight() * toTransform.scale);
+ thumbnail = Bitmap.createBitmap(toHeaderWidth, toHeaderHeight,
+ Bitmap.Config.ARGB_8888);
+ if (Constants.DebugFlags.App.EnableTransitionThumbnailDebugMode) {
+ thumbnail.eraseColor(0xFFff0000);
+ } else {
+ Canvas c = new Canvas(thumbnail);
+ c.scale(toTransform.scale, toTransform.scale);
+ mHeaderBar.rebindToTask(toTask);
+ mHeaderBar.draw(c);
+ c.setBitmap(null);
+ }
+ }
+ return thumbnail.createAshmemBitmap();
+ }
+ return null;
+ }
+
/** Returns the transition rect for the given task id. */
TaskViewTransform getThumbnailTransitionTransform(TaskStack stack, TaskStackView stackView,
int runningTaskId, Task runningTaskOut) {
@@ -694,7 +768,9 @@
return;
}
- loader.preloadTasks(sInstanceLoadPlan, isTopTaskHome);
+ if (!sInstanceLoadPlan.hasTasks()) {
+ loader.preloadTasks(sInstanceLoadPlan, isTopTaskHome);
+ }
ArrayList<TaskStack> stacks = sInstanceLoadPlan.getAllTaskStacks();
TaskStack stack = stacks.get(0);
@@ -706,12 +782,6 @@
boolean useThumbnailTransition = (topTask != null) && !isTopTaskHome && hasRecentTasks;
if (useThumbnailTransition) {
- // Ensure that we load the running task's icon
- RecentsTaskLoadPlan.Options launchOpts = new RecentsTaskLoadPlan.Options();
- launchOpts.runningTaskId = topTask.id;
- launchOpts.loadThumbnails = false;
- launchOpts.onlyLoadForCache = true;
- loader.loadTasks(mContext, sInstanceLoadPlan, launchOpts);
// Try starting with a thumbnail transition
ActivityOptions opts = getThumbnailTransitionActivityOptions(topTask, stack,
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
index ad97f91..9404dcb 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
@@ -441,6 +441,10 @@
if (mConfig.launchedHasConfigurationChanged) {
onEnterAnimationTriggered();
}
+
+ if (!mConfig.launchedHasConfigurationChanged) {
+ mRecentsView.disableLayersForOneFrame();
+ }
}
@Override
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 cec613c..1a21d8a 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
@@ -431,6 +431,13 @@
return false;
}
+ public void disableLayersForOneFrame() {
+ List<TaskStackView> stackViews = getTaskStackViews();
+ for (int i = 0; i < stackViews.size(); i++) {
+ stackViews.get(i).disableLayersForOneFrame();
+ }
+ }
+
/**** TaskStackView.TaskStackCallbacks Implementation ****/
@Override
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 5f151e8..5711cd6 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
@@ -19,6 +19,7 @@
import android.animation.ValueAnimator;
import android.content.ComponentName;
import android.content.Context;
+import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Rect;
import android.view.LayoutInflater;
@@ -63,7 +64,6 @@
public void onTaskResize(Task t);
}
-
RecentsConfiguration mConfig;
TaskStack mStack;
@@ -81,7 +81,6 @@
boolean mDismissAllButtonAnimating;
int mFocusedTaskIndex = -1;
int mPrevAccessibilityFocusedIndex = -1;
-
// Optimizations
int mStackViewsAnimationDuration;
boolean mStackViewsDirty = true;
@@ -99,6 +98,7 @@
ArrayList<TaskView> mTaskViews = new ArrayList<TaskView>();
List<TaskView> mImmutableTaskViews = new ArrayList<TaskView>();
LayoutInflater mInflater;
+ boolean mLayersDisabled;
// A convenience update listener to request updating clipping of tasks
ValueAnimator.AnimatorUpdateListener mRequestUpdateClippingListener =
@@ -375,7 +375,9 @@
if (tv == null) {
tv = mViewPool.pickUpViewFromPool(task, task);
-
+ if (mLayersDisabled) {
+ tv.disableLayersForOneFrame();
+ }
if (mStackViewsAnimationDuration > 0) {
// For items in the list, put them in start animating them from the
// approriate ends of the list where they are expected to appear
@@ -1031,6 +1033,20 @@
mUIDozeTrigger.poke();
}
+ @Override
+ protected void dispatchDraw(Canvas canvas) {
+ mLayersDisabled = false;
+ super.dispatchDraw(canvas);
+ }
+
+ public void disableLayersForOneFrame() {
+ mLayersDisabled = true;
+ List<TaskView> taskViews = getTaskViews();
+ for (int i = 0; i < taskViews.size(); i++) {
+ taskViews.get(i).disableLayersForOneFrame();
+ }
+ }
+
/**** TaskStackCallbacks Implementation ****/
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
index 4a5fef3..b0247cb 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
@@ -651,6 +651,10 @@
}
}
+ public void disableLayersForOneFrame() {
+ mHeaderView.disableLayersForOneFrame();
+ }
+
/**** TaskCallbacks Implementation ****/
/** Binds this task view to the task */
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
index 82f0f31..1a22cae 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
@@ -80,6 +80,8 @@
Paint mDimLayerPaint = new Paint();
PorterDuffColorFilter mDimColorFilter = new PorterDuffColorFilter(0, PorterDuff.Mode.SRC_ATOP);
+ boolean mLayersDisabled;
+
public TaskViewHeader(Context context) {
this(context, null);
}
@@ -172,7 +174,9 @@
void setDimAlpha(int alpha) {
mDimColorFilter.setColor(Color.argb(alpha, 0, 0, 0));
mDimLayerPaint.setColorFilter(mDimColorFilter);
- setLayerType(LAYER_TYPE_HARDWARE, mDimLayerPaint);
+ if (!mLayersDisabled) {
+ setLayerType(LAYER_TYPE_HARDWARE, mDimLayerPaint);
+ }
}
/** Returns the secondary color for a primary color. */
@@ -304,6 +308,28 @@
return new int[] {};
}
+ @Override
+ protected void dispatchDraw(Canvas canvas) {
+ super.dispatchDraw(canvas);
+ if (mLayersDisabled) {
+ mLayersDisabled = false;
+ postOnAnimation(new Runnable() {
+ @Override
+ public void run() {
+ mLayersDisabled = false;
+ setLayerType(LAYER_TYPE_HARDWARE, mDimLayerPaint);
+ }
+ });
+ }
+ }
+
+ public void disableLayersForOneFrame() {
+ mLayersDisabled = true;
+
+ // Disable layer for a frame so we can draw our first frame faster.
+ setLayerType(LAYER_TYPE_NONE, null);
+ }
+
/** Notifies the associated TaskView has been focused. */
void onTaskViewFocusChanged(boolean focused, boolean animateFocusedState) {
// If we are not animating the visible state, just return
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index fa172a4..f05ac1a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -1030,9 +1030,7 @@
@Override
public void toggleRecentApps() {
- int msg = MSG_TOGGLE_RECENTS_APPS;
- mHandler.removeMessages(msg);
- mHandler.sendEmptyMessage(msg);
+ toggleRecents();
}
@Override