Loading packages/SystemUI/src/com/android/systemui/recents/Recents.java +106 −36 Original line number Diff line number Diff line Loading @@ -32,6 +32,7 @@ import android.content.res.Resources; 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; Loading @@ -40,6 +41,7 @@ import android.util.Pair; 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; Loading Loading @@ -184,12 +186,16 @@ public class Recents extends SystemUI // 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() { } Loading Loading @@ -360,13 +366,16 @@ public class Recents extends SystemUI 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); } } Loading Loading @@ -513,6 +522,7 @@ public class Recents extends SystemUI algo.computeRects(mWindowRect.width(), mWindowRect.height(), taskStackBounds); Rect taskViewSize = algo.getUntransformedTaskViewSize(); int taskBarHeight = res.getDimensionPixelSize(R.dimen.recents_task_bar_height); synchronized (mHeaderBarLock) { mHeaderBar = (TaskViewHeader) mInflater.inflate(R.layout.recents_task_view_header, null, false); mHeaderBar.measure( Loading @@ -520,6 +530,7 @@ public class Recents extends SystemUI View.MeasureSpec.makeMeasureSpec(taskBarHeight, View.MeasureSpec.EXACTLY)); mHeaderBar.layout(0, 0, taskViewSize.width(), taskBarHeight); } } /** Prepares the search bar app widget */ void reloadSearchBarAppWidget(Context context, SystemServicesProxy ssp) { Loading Loading @@ -607,15 +618,84 @@ public class Recents extends SystemUI */ 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; 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, thumbnail, toTaskRect.left, toTaskRect.top, toTaskRect.width(), toTaskRect.height(), mHandler, this); } // If both the screenshot and thumbnail fails, then just fall back to the default transition 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); Bitmap thumbnail = Bitmap.createBitmap(toHeaderWidth, toHeaderHeight, thumbnail = Bitmap.createBitmap(toHeaderWidth, toHeaderHeight, Bitmap.Config.ARGB_8888); if (Constants.DebugFlags.App.EnableTransitionThumbnailDebugMode) { thumbnail.eraseColor(0xFFff0000); Loading @@ -626,16 +706,10 @@ public class Recents extends SystemUI mHeaderBar.draw(c); c.setBitmap(null); } Bitmap thumbnailImmutable = thumbnail.createAshmemBitmap(); mStartAnimationTriggered = false; return ActivityOptions.makeThumbnailAspectScaleDownAnimation(mDummyStackView, thumbnailImmutable, toTaskRect.left, toTaskRect.top, toTaskRect.width(), toTaskRect.height(), mHandler, this); } // If both the screenshot and thumbnail fails, then just fall back to the default transition return getUnknownTransitionActivityOptions(); return thumbnail.createAshmemBitmap(); } return null; } /** Returns the transition rect for the given task id. */ Loading Loading @@ -694,7 +768,9 @@ public class Recents extends SystemUI return; } if (!sInstanceLoadPlan.hasTasks()) { loader.preloadTasks(sInstanceLoadPlan, isTopTaskHome); } ArrayList<TaskStack> stacks = sInstanceLoadPlan.getAllTaskStacks(); TaskStack stack = stacks.get(0); Loading @@ -706,12 +782,6 @@ public class Recents extends SystemUI 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, Loading packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java +4 −0 Original line number Diff line number Diff line Loading @@ -441,6 +441,10 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView if (mConfig.launchedHasConfigurationChanged) { onEnterAnimationTriggered(); } if (!mConfig.launchedHasConfigurationChanged) { mRecentsView.disableLayersForOneFrame(); } } @Override Loading packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java +7 −0 Original line number Diff line number Diff line Loading @@ -431,6 +431,13 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV 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 Loading packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java +19 −3 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ package com.android.systemui.recents.views; 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; Loading Loading @@ -63,7 +64,6 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal public void onTaskResize(Task t); } RecentsConfiguration mConfig; TaskStack mStack; Loading @@ -81,7 +81,6 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal boolean mDismissAllButtonAnimating; int mFocusedTaskIndex = -1; int mPrevAccessibilityFocusedIndex = -1; // Optimizations int mStackViewsAnimationDuration; boolean mStackViewsDirty = true; Loading @@ -99,6 +98,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal 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 = Loading Loading @@ -375,7 +375,9 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal 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 Loading Loading @@ -1031,6 +1033,20 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal 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 Loading packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java +4 −0 Original line number Diff line number Diff line Loading @@ -651,6 +651,10 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, } } public void disableLayersForOneFrame() { mHeaderView.disableLayersForOneFrame(); } /**** TaskCallbacks Implementation ****/ /** Binds this task view to the task */ Loading Loading
packages/SystemUI/src/com/android/systemui/recents/Recents.java +106 −36 Original line number Diff line number Diff line Loading @@ -32,6 +32,7 @@ import android.content.res.Resources; 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; Loading @@ -40,6 +41,7 @@ import android.util.Pair; 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; Loading Loading @@ -184,12 +186,16 @@ public class Recents extends SystemUI // 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() { } Loading Loading @@ -360,13 +366,16 @@ public class Recents extends SystemUI 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); } } Loading Loading @@ -513,6 +522,7 @@ public class Recents extends SystemUI algo.computeRects(mWindowRect.width(), mWindowRect.height(), taskStackBounds); Rect taskViewSize = algo.getUntransformedTaskViewSize(); int taskBarHeight = res.getDimensionPixelSize(R.dimen.recents_task_bar_height); synchronized (mHeaderBarLock) { mHeaderBar = (TaskViewHeader) mInflater.inflate(R.layout.recents_task_view_header, null, false); mHeaderBar.measure( Loading @@ -520,6 +530,7 @@ public class Recents extends SystemUI View.MeasureSpec.makeMeasureSpec(taskBarHeight, View.MeasureSpec.EXACTLY)); mHeaderBar.layout(0, 0, taskViewSize.width(), taskBarHeight); } } /** Prepares the search bar app widget */ void reloadSearchBarAppWidget(Context context, SystemServicesProxy ssp) { Loading Loading @@ -607,15 +618,84 @@ public class Recents extends SystemUI */ 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; 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, thumbnail, toTaskRect.left, toTaskRect.top, toTaskRect.width(), toTaskRect.height(), mHandler, this); } // If both the screenshot and thumbnail fails, then just fall back to the default transition 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); Bitmap thumbnail = Bitmap.createBitmap(toHeaderWidth, toHeaderHeight, thumbnail = Bitmap.createBitmap(toHeaderWidth, toHeaderHeight, Bitmap.Config.ARGB_8888); if (Constants.DebugFlags.App.EnableTransitionThumbnailDebugMode) { thumbnail.eraseColor(0xFFff0000); Loading @@ -626,16 +706,10 @@ public class Recents extends SystemUI mHeaderBar.draw(c); c.setBitmap(null); } Bitmap thumbnailImmutable = thumbnail.createAshmemBitmap(); mStartAnimationTriggered = false; return ActivityOptions.makeThumbnailAspectScaleDownAnimation(mDummyStackView, thumbnailImmutable, toTaskRect.left, toTaskRect.top, toTaskRect.width(), toTaskRect.height(), mHandler, this); } // If both the screenshot and thumbnail fails, then just fall back to the default transition return getUnknownTransitionActivityOptions(); return thumbnail.createAshmemBitmap(); } return null; } /** Returns the transition rect for the given task id. */ Loading Loading @@ -694,7 +768,9 @@ public class Recents extends SystemUI return; } if (!sInstanceLoadPlan.hasTasks()) { loader.preloadTasks(sInstanceLoadPlan, isTopTaskHome); } ArrayList<TaskStack> stacks = sInstanceLoadPlan.getAllTaskStacks(); TaskStack stack = stacks.get(0); Loading @@ -706,12 +782,6 @@ public class Recents extends SystemUI 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, Loading
packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java +4 −0 Original line number Diff line number Diff line Loading @@ -441,6 +441,10 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView if (mConfig.launchedHasConfigurationChanged) { onEnterAnimationTriggered(); } if (!mConfig.launchedHasConfigurationChanged) { mRecentsView.disableLayersForOneFrame(); } } @Override Loading
packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java +7 −0 Original line number Diff line number Diff line Loading @@ -431,6 +431,13 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV 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 Loading
packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java +19 −3 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ package com.android.systemui.recents.views; 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; Loading Loading @@ -63,7 +64,6 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal public void onTaskResize(Task t); } RecentsConfiguration mConfig; TaskStack mStack; Loading @@ -81,7 +81,6 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal boolean mDismissAllButtonAnimating; int mFocusedTaskIndex = -1; int mPrevAccessibilityFocusedIndex = -1; // Optimizations int mStackViewsAnimationDuration; boolean mStackViewsDirty = true; Loading @@ -99,6 +98,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal 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 = Loading Loading @@ -375,7 +375,9 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal 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 Loading Loading @@ -1031,6 +1033,20 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal 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 Loading
packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java +4 −0 Original line number Diff line number Diff line Loading @@ -651,6 +651,10 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, } } public void disableLayersForOneFrame() { mHeaderView.disableLayersForOneFrame(); } /**** TaskCallbacks Implementation ****/ /** Binds this task view to the task */ Loading