From b63b44c3d55cc49423b9c70d37f2e1d9a0799ea4 Mon Sep 17 00:00:00 2001 From: Winson Chung Date: Fri, 10 Nov 2017 17:54:44 -0800 Subject: [PATCH] Load some recent tasks Bug: 69166452 Test: Build quickstep Change-Id: Id4b0172256d6920616a6b9529d61abd1fe0c1a36 --- quickstep/libs/sysui_shared.jar | Bin 86425 -> 89285 bytes .../drawable/task_thumbnail_background.xml | 2 +- quickstep/res/layout/overview_panel.xml | 35 +---- quickstep/res/layout/task.xml | 5 +- .../launcher3/uioverrides/OverviewState.java | 6 +- .../NavBarSwipeInteractionHandler.java | 109 ++++++++++---- .../com/android/quickstep/RecentsView.java | 139 +++++++++++++++--- .../android/quickstep/SnapshotDragView.java | 9 ++ .../android/quickstep/TaskThumbnailView.java | 47 +++--- .../src/com/android/quickstep/TaskView.java | 61 +++++++- .../quickstep/TouchInteractionService.java | 72 ++++++++- res/values/config.xml | 4 + res/values/dimens.xml | 3 + src/com/android/launcher3/DeviceProfile.java | 5 +- src/com/android/launcher3/Launcher.java | 6 +- .../states/InternalStateHandler.java | 31 +++- 16 files changed, 399 insertions(+), 135 deletions(-) diff --git a/quickstep/libs/sysui_shared.jar b/quickstep/libs/sysui_shared.jar index a76f4f9e0e2e8c39a8bd4e280217643e9d7f4657..ef50ac4326f983f7c7ce7bba2d248c01b11852ef 100644 GIT binary patch delta 20344 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 CKVi)P delta 17704 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 diff --git a/quickstep/res/drawable/task_thumbnail_background.xml b/quickstep/res/drawable/task_thumbnail_background.xml index 27efd6c68e..603380e753 100644 --- a/quickstep/res/drawable/task_thumbnail_background.xml +++ b/quickstep/res/drawable/task_thumbnail_background.xml @@ -15,5 +15,5 @@ --> - + diff --git a/quickstep/res/layout/overview_panel.xml b/quickstep/res/layout/overview_panel.xml index 521551c217..a8b91c5d9d 100644 --- a/quickstep/res/layout/overview_panel.xml +++ b/quickstep/res/layout/overview_panel.xml @@ -19,35 +19,8 @@ android:theme="@style/HomeScreenElementTheme" android:layout_width="match_parent" android:layout_height="match_parent" - android:paddingTop="20dp" - android:paddingBottom="20dp" + android:layout_gravity="center" + android:clipChildren="false" android:clipToPadding="false" - android:layout_gravity="center_horizontal|bottom" - android:gravity="top"> - - - - - - - - - - - \ No newline at end of file + android:alpha="0.0" + android:visibility="invisible" /> \ No newline at end of file diff --git a/quickstep/res/layout/task.xml b/quickstep/res/layout/task.xml index 9d8aea7111..fdf1adcbc9 100644 --- a/quickstep/res/layout/task.xml +++ b/quickstep/res/layout/task.xml @@ -23,13 +23,14 @@ android:id="@+id/snapshot" android:layout_width="match_parent" android:layout_height="match_parent" + android:layout_marginTop="24dp" android:scaleType="matrix" android:background="@drawable/task_thumbnail_background" android:elevation="4dp" /> \ No newline at end of file diff --git a/quickstep/src/com/android/launcher3/uioverrides/OverviewState.java b/quickstep/src/com/android/launcher3/uioverrides/OverviewState.java index 9bdd7a3849..26f5d5b51b 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/OverviewState.java +++ b/quickstep/src/com/android/launcher3/uioverrides/OverviewState.java @@ -46,12 +46,14 @@ public class OverviewState extends LauncherState { @Override public void onStateEnabled(Launcher launcher) { - ((RecentsView) launcher.getOverviewPanel()).setViewVisible(true); + RecentsView rv = launcher.getOverviewPanel(); + rv.setOverviewStateEnabled(true); } @Override public void onStateDisabled(Launcher launcher) { - ((RecentsView) launcher.getOverviewPanel()).setViewVisible(false); + RecentsView rv = launcher.getOverviewPanel(); + rv.setOverviewStateEnabled(false); } @Override diff --git a/quickstep/src/com/android/quickstep/NavBarSwipeInteractionHandler.java b/quickstep/src/com/android/quickstep/NavBarSwipeInteractionHandler.java index caeef50778..0810579503 100644 --- a/quickstep/src/com/android/quickstep/NavBarSwipeInteractionHandler.java +++ b/quickstep/src/com/android/quickstep/NavBarSwipeInteractionHandler.java @@ -40,8 +40,15 @@ import com.android.launcher3.anim.AnimationSuccessListener; import com.android.launcher3.anim.Interpolators; import com.android.launcher3.dragndrop.DragLayer; import com.android.launcher3.states.InternalStateHandler; +import com.android.launcher3.uioverrides.OverviewState; +import com.android.systemui.shared.recents.model.RecentsTaskLoadPlan; import com.android.systemui.shared.recents.model.Task.TaskKey; import com.android.systemui.shared.system.ActivityManagerWrapper; +import com.android.systemui.shared.system.BackgroundExecutor; +import com.android.systemui.shared.system.WindowManagerWrapper; + +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; @TargetApi(Build.VERSION_CODES.O) public class NavBarSwipeInteractionHandler extends InternalStateHandler implements FrameCallback { @@ -66,13 +73,15 @@ public class NavBarSwipeInteractionHandler extends InternalStateHandler implemen private static final float MIN_PROGRESS_FOR_OVERVIEW = 0.5f; + private final Rect mStableInsets = new Rect(); private final Rect mSourceRect = new Rect(); private final Rect mTargetRect = new Rect(); private final Rect mCurrentRect = new Rect(); private final RectEvaluator mRectEvaluator = new RectEvaluator(mCurrentRect); private final Bitmap mTaskSnapshot; - private final RunningTaskInfo mTaskInfo; + private final int mRunningTaskId; + private Future mFutureLoadPlan; private Launcher mLauncher; private Choreographer mChoreographer; @@ -94,9 +103,10 @@ public class NavBarSwipeInteractionHandler extends InternalStateHandler implemen private boolean mTouchEnded = false; private float mEndVelocity; - NavBarSwipeInteractionHandler(Bitmap taskSnapShot, RunningTaskInfo taskInfo) { + NavBarSwipeInteractionHandler(Bitmap taskSnapShot, RunningTaskInfo runningTaskInfo) { mTaskSnapshot = taskSnapShot; - mTaskInfo = taskInfo; + mRunningTaskId = runningTaskInfo.id; + WindowManagerWrapper.getInstance().getStableInsets(mStableInsets); } @Override @@ -109,22 +119,39 @@ public class NavBarSwipeInteractionHandler extends InternalStateHandler implemen } @Override - public void onNewIntent(Launcher launcher) { + public void onCreate(Launcher launcher) { mLauncher = launcher; - - // Go immediately - launcher.getStateManager().goToState(LauncherState.OVERVIEW, false); - - // Optimization - launcher.getAppsView().setVisibility(View.GONE); - - mDragView = new SnapshotDragView(launcher, mTaskSnapshot); - launcher.getDragLayer().addView(mDragView); + mDragView = new SnapshotDragView(mLauncher, mTaskSnapshot); + mLauncher.getDragLayer().addView(mDragView); mDragView.setPivotX(0); mDragView.setPivotY(0); - mRecentsView = launcher.getOverviewPanel(); - mRecentsView.scrollTo(0, 0); - mHotseat = launcher.getHotseat(); + mRecentsView = mLauncher.getOverviewPanel(); + mHotseat = mLauncher.getHotseat(); + + // Optimization + mLauncher.getAppsView().setVisibility(View.GONE); + + // Launch overview + mRecentsView.update(consumeLastLoadPlan()); + mLauncher.getStateManager().goToState(LauncherState.OVERVIEW, false /* animate */); + } + + @Override + public void onNewIntent(Launcher launcher, boolean alreadyOnHome) { + mLauncher = launcher; + mDragView = new SnapshotDragView(mLauncher, mTaskSnapshot); + mLauncher.getDragLayer().addView(mDragView); + mDragView.setPivotX(0); + mDragView.setPivotY(0); + mRecentsView = mLauncher.getOverviewPanel(); + mHotseat = mLauncher.getHotseat(); + + // Optimization + mLauncher.getAppsView().setVisibility(View.GONE); + + // Launch overview, animate if already on home + mRecentsView.update(consumeLastLoadPlan()); + mLauncher.getStateManager().goToState(LauncherState.OVERVIEW, alreadyOnHome); } @BinderThread @@ -167,19 +194,46 @@ public class NavBarSwipeInteractionHandler extends InternalStateHandler implemen // Init target rect. View targetView = ((ViewGroup) mRecentsView.getChildAt(0)).getChildAt(0); dl.getViewRectRelativeToSelf(targetView, mTargetRect); + mTargetRect.right = mTargetRect.left + mTargetRect.width(); + mTargetRect.bottom = mTargetRect.top + mTargetRect.height(); mSourceRect.set(0, 0, dl.getWidth(), dl.getHeight()); } - mCurrentShift = shift; - int hotseatHeight = mHotseat.getHeight(); - mHotseat.setTranslationY((1 - shift) * hotseatHeight); + if (!mSourceRect.isEmpty()) { + mCurrentShift = shift; + int hotseatHeight = mHotseat.getHeight(); + mHotseat.setTranslationY((1 - shift) * hotseatHeight); - mRectEvaluator.evaluate(shift, mSourceRect, mTargetRect); + mRectEvaluator.evaluate(shift, mSourceRect, mTargetRect); - mDragView.setTranslationX(mCurrentRect.left); - mDragView.setTranslationY(mCurrentRect.top); - mDragView.setScaleX((float) mCurrentRect.width() / mSourceRect.width()); - mDragView.setScaleY((float) mCurrentRect.width() / mSourceRect.width()); + float scale = (float) mCurrentRect.width() / mSourceRect.width(); + mDragView.setTranslationX(mCurrentRect.left - mStableInsets.left * scale * shift); + mDragView.setTranslationY(mCurrentRect.top - mStableInsets.top * scale * shift); + mDragView.setScaleX(scale); + mDragView.setScaleY(scale); + mDragView.getViewBounds().setClipTop((int) (mStableInsets.top * shift)); + mDragView.getViewBounds().setClipBottom((int) (mStableInsets.bottom * shift)); + } + } + + void setLastLoadPlan(Future futureLoadPlan) { + if (mFutureLoadPlan != null) { + mFutureLoadPlan.cancel(true); + } + mFutureLoadPlan = futureLoadPlan; + } + + private RecentsTaskLoadPlan consumeLastLoadPlan() { + try { + if (mFutureLoadPlan != null) { + return mFutureLoadPlan.get(); + } + } catch (InterruptedException | ExecutionException e) { + e.printStackTrace(); + } finally { + mFutureLoadPlan = null; + } + return null; } @UiThread @@ -229,9 +283,8 @@ public class NavBarSwipeInteractionHandler extends InternalStateHandler implemen mHotseat.setTranslationY(0); mLauncher.setOnResumeCallback(() -> mDragView.close(false)); - // TODO: Task key should be received from Recents model - TaskKey taskKey = new TaskKey(mTaskInfo.id, 0, null, UserHandle.myUserId(), 0); - ActivityManagerWrapper.getInstance() - .startActivityFromRecentsAsync(taskKey, null, null, null); + // TODO: For now, assume that the task stack will have loaded in the bg, will update + // the lib api later for direct call + mRecentsView.launchTaskWithId(mRunningTaskId); } } diff --git a/quickstep/src/com/android/quickstep/RecentsView.java b/quickstep/src/com/android/quickstep/RecentsView.java index d7559daad9..528b11d590 100644 --- a/quickstep/src/com/android/quickstep/RecentsView.java +++ b/quickstep/src/com/android/quickstep/RecentsView.java @@ -19,17 +19,43 @@ package com.android.quickstep; import android.content.Context; import android.graphics.Rect; import android.util.AttributeSet; -import android.widget.HorizontalScrollView; +import android.view.LayoutInflater; import com.android.launcher3.DeviceProfile; -import com.android.launcher3.Insettable; import com.android.launcher3.Launcher; +import com.android.launcher3.PagedView; import com.android.launcher3.R; +import com.android.systemui.shared.recents.model.RecentsTaskLoadPlan; +import com.android.systemui.shared.recents.model.RecentsTaskLoader; +import com.android.systemui.shared.recents.model.Task; +import com.android.systemui.shared.recents.model.TaskStack; +import com.android.systemui.shared.recents.model.ThumbnailData; +import com.android.systemui.shared.system.ActivityManagerWrapper; +import com.android.systemui.shared.system.TaskStackChangeListener; +import com.android.systemui.shared.system.WindowManagerWrapper; + +import java.util.ArrayList; /** - * A placeholder view for recents + * A list of recent tasks. */ -public class RecentsView extends HorizontalScrollView implements Insettable { +public class RecentsView extends PagedView { + + private boolean mOverviewStateEnabled; + private boolean mTaskStackListenerRegistered; + + private TaskStackChangeListener mTaskStackListener = new TaskStackChangeListener() { + @Override + public void onTaskSnapshotChanged(int taskId, ThumbnailData snapshot) { + for (int i = 0; i < getChildCount(); i++) { + final TaskView taskView = (TaskView) getChildAt(i); + if (taskView.getTask().key.id == taskId) { + taskView.getThumbnail().setThumbnail(snapshot); + return; + } + } + } + }; public RecentsView(Context context) { this(context, null); @@ -41,24 +67,103 @@ public class RecentsView extends HorizontalScrollView implements Insettable { public RecentsView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); - setAlpha(0); - setVisibility(INVISIBLE); + setWillNotDraw(false); + setPageSpacing((int) getResources().getDimension(R.dimen.recents_page_spacing)); } - public void setViewVisible(boolean isVisible) { } + @Override + protected void onFinishInflate() { + super.onFinishInflate(); + + // TODO: These are rough calculations which currently use the stable insets + DeviceProfile profile = Launcher.getLauncher(getContext()).getDeviceProfile(); + Rect stableInsets = new Rect(); + WindowManagerWrapper.getInstance().getStableInsets(stableInsets); + Rect padding = profile.getWorkspacePadding(null); + float taskWidth = profile.getCurrentWidth() - stableInsets.left - stableInsets.right; + float taskHeight = profile.getCurrentHeight() - stableInsets.top - stableInsets.bottom; + float overviewHeight = profile.availableHeightPx - padding.top - padding.bottom + - stableInsets.top; + float overviewWidth = taskWidth * overviewHeight / taskHeight; + padding.left = padding.right = (int) ((profile.availableWidthPx - overviewWidth) / 2); + setPadding(padding.left, padding.top, padding.right, padding.bottom); + } @Override - public void setInsets(Rect insets) { - MarginLayoutParams lp = (MarginLayoutParams) getLayoutParams(); - lp.topMargin = insets.top; - lp.bottomMargin = insets.bottom; - lp.leftMargin = insets.left; - lp.rightMargin = insets.right; + protected void onWindowVisibilityChanged(int visibility) { + super.onWindowVisibilityChanged(visibility); + updateTaskStackListenerState(); + } - DeviceProfile dp = Launcher.getLauncher(getContext()).getDeviceProfile(); - if (!dp.isVerticalBarLayout()) { - lp.bottomMargin += dp.hotseatBarSizePx + getResources().getDimensionPixelSize( - R.dimen.dynamic_grid_min_page_indicator_size); + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + updateTaskStackListenerState(); + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + updateTaskStackListenerState(); + } + + public void setOverviewStateEnabled(boolean enabled) { + mOverviewStateEnabled = enabled; + updateTaskStackListenerState(); + } + + public void update(RecentsTaskLoadPlan loadPlan) { + final RecentsTaskLoader loader = TouchInteractionService.getRecentsTaskLoader(); + setCurrentPage(0); + TaskStack stack = loadPlan != null ? loadPlan.getTaskStack() : null; + if (stack == null) { + removeAllViews(); + return; + } + + // Ensure there are as many views as there are tasks in the stack (adding and trimming as + // necessary) + final LayoutInflater inflater = LayoutInflater.from(getContext()); + final ArrayList tasks = stack.getTasks(); + for (int i = getChildCount(); i < tasks.size(); i++) { + final TaskView taskView = (TaskView) inflater.inflate(R.layout.task, this, false); + addView(taskView); + } + while (getChildCount() > tasks.size()) { + final TaskView taskView = (TaskView) getChildAt(getChildCount() - 1); + removeView(taskView); + loader.unloadTaskData(taskView.getTask()); + } + + // Rebind all task views + for (int i = tasks.size() - 1; i >= 0; i--) { + final Task task = tasks.get(i); + final TaskView taskView = (TaskView) getChildAt(tasks.size() - i - 1); + taskView.bind(task); + loader.loadTaskData(task); + } + } + + public void launchTaskWithId(int taskId) { + for (int i = 0; i < getChildCount(); i++) { + final TaskView taskView = (TaskView) getChildAt(i); + if (taskView.getTask().key.id == taskId) { + taskView.launchTask(false /* animate */); + return; + } + } + } + + private void updateTaskStackListenerState() { + boolean registerStackListener = mOverviewStateEnabled && isAttachedToWindow() + && getWindowVisibility() == VISIBLE; + if (registerStackListener != mTaskStackListenerRegistered) { + if (registerStackListener) { + ActivityManagerWrapper.getInstance().registerTaskStackListener(mTaskStackListener); + } else { + ActivityManagerWrapper.getInstance().unregisterTaskStackListener(mTaskStackListener); + } + mTaskStackListenerRegistered = registerStackListener; } } } diff --git a/quickstep/src/com/android/quickstep/SnapshotDragView.java b/quickstep/src/com/android/quickstep/SnapshotDragView.java index 791fe9ff17..2ef39422d2 100644 --- a/quickstep/src/com/android/quickstep/SnapshotDragView.java +++ b/quickstep/src/com/android/quickstep/SnapshotDragView.java @@ -23,6 +23,7 @@ import android.view.MotionEvent; import com.android.launcher3.AbstractFloatingView; import com.android.launcher3.Insettable; import com.android.launcher3.Launcher; +import com.android.systemui.shared.recents.view.AnimateableViewBounds; /** * Floating view which shows the task snapshot allowing it to be dragged and placed. @@ -31,12 +32,20 @@ public class SnapshotDragView extends AbstractFloatingView implements Insettable private final Launcher mLauncher; private final Bitmap mSnapshot; + private final AnimateableViewBounds mViewBounds; public SnapshotDragView(Launcher launcher, Bitmap snapshot) { super(launcher, null); mLauncher = launcher; mSnapshot = snapshot; + mViewBounds = new AnimateableViewBounds(this, 0); setWillNotDraw(false); + setClipToOutline(true); + setOutlineProvider(mViewBounds); + } + + AnimateableViewBounds getViewBounds() { + return mViewBounds; } @Override diff --git a/quickstep/src/com/android/quickstep/TaskThumbnailView.java b/quickstep/src/com/android/quickstep/TaskThumbnailView.java index 96c93c23f9..55d22e0323 100644 --- a/quickstep/src/com/android/quickstep/TaskThumbnailView.java +++ b/quickstep/src/com/android/quickstep/TaskThumbnailView.java @@ -22,20 +22,17 @@ import android.graphics.Bitmap; import android.graphics.BitmapShader; import android.graphics.Canvas; import android.graphics.Color; -import android.graphics.ColorMatrixColorFilter; import android.graphics.LightingColorFilter; import android.graphics.Matrix; -import android.graphics.Outline; import android.graphics.Paint; import android.graphics.Point; import android.graphics.Rect; import android.graphics.Shader; import android.util.AttributeSet; -import android.view.Display; -import android.view.View; -import android.view.ViewOutlineProvider; import android.widget.FrameLayout; +import com.android.launcher3.DeviceProfile; +import com.android.launcher3.Launcher; import com.android.systemui.shared.recents.model.ThumbnailData; /** @@ -95,6 +92,14 @@ public class TaskThumbnailView extends FrameLayout { } } + /** + * Sets the alpha of the dim layer on top of this view. + */ + public void setDimAlpha(float dimAlpha) { + mDimAlpha = dimAlpha; + updateThumbnailPaintFilter(); + } + @Override protected void onDraw(Canvas canvas) { int viewWidth = getMeasuredWidth(); @@ -105,43 +110,40 @@ public class TaskThumbnailView extends FrameLayout { (int) (mThumbnailRect.height() * mThumbnailScale)); if (mBitmapShader != null && thumbnailWidth > 0 && thumbnailHeight > 0) { - int topOffset = 0; // Draw the background, there will be some small overdraw with the thumbnail if (thumbnailWidth < viewWidth) { // Portrait thumbnail on a landscape task view - canvas.drawRect(Math.max(0, thumbnailWidth), topOffset, viewWidth, viewHeight, + canvas.drawRect(Math.max(0, thumbnailWidth), 0, viewWidth, viewHeight, mBgFillPaint); } if (thumbnailHeight < viewHeight) { // Landscape thumbnail on a portrait task view - canvas.drawRect(0, Math.max(topOffset, thumbnailHeight), viewWidth, viewHeight, + canvas.drawRect(0, Math.max(0, thumbnailHeight), viewWidth, viewHeight, mBgFillPaint); } // Draw the thumbnail - canvas.drawRect(0, topOffset, thumbnailWidth, thumbnailHeight, mDrawPaint); + canvas.drawRect(0, 0, thumbnailWidth, thumbnailHeight, mDrawPaint); } else { canvas.drawRect(0, 0, viewWidth, viewHeight, mBgFillPaint); } } - void updateThumbnailPaintFilter() { - int mul = (int) ((1.0f - mDimAlpha) * 255); + private void updateThumbnailPaintFilter() { + int mul = (int) (mDimAlpha * 255); if (mBitmapShader != null) { - mLightingColorFilter = new LightingColorFilter(Color.WHITE, - Color.argb(255, mul, mul, mul)); + mLightingColorFilter = new LightingColorFilter(Color.argb(255, mul, mul, mul), 0); mDrawPaint.setColorFilter(mLightingColorFilter); mDrawPaint.setColor(0xFFffffff); mBgFillPaint.setColorFilter(mLightingColorFilter); } else { - int grey = mul; mDrawPaint.setColorFilter(null); - mDrawPaint.setColor(Color.argb(255, grey, grey, grey)); + mDrawPaint.setColor(Color.argb(255, mul, mul, mul)); } invalidate(); } - public void updateThumbnailMatrix() { + private void updateThumbnailMatrix() { mThumbnailScale = 1f; if (mBitmapShader != null && mThumbnailData != null) { if (getMeasuredWidth() == 0) { @@ -152,8 +154,7 @@ public class TaskThumbnailView extends FrameLayout { float invThumbnailScale = 1f / mThumbnailScale; final Configuration configuration = getContext().getApplicationContext().getResources().getConfiguration(); - final Point displaySize = new Point(); - getDisplay().getRealSize(displaySize); + final DeviceProfile profile = Launcher.getLauncher(getContext()).getDeviceProfile(); if (configuration.orientation == Configuration.ORIENTATION_PORTRAIT) { if (mThumbnailData.orientation == Configuration.ORIENTATION_PORTRAIT) { // If we are in the same orientation as the screenshot, just scale it to the @@ -163,23 +164,17 @@ public class TaskThumbnailView extends FrameLayout { // Scale the landscape thumbnail up to app size, then scale that to the task // view size to match other portrait screenshots mThumbnailScale = invThumbnailScale * - ((float) getMeasuredWidth() / displaySize.x); + ((float) getMeasuredWidth() / profile.getCurrentWidth()); } } else { // Otherwise, scale the screenshot to fit 1:1 in the current orientation mThumbnailScale = invThumbnailScale; } } - mMatrix.setTranslate(-mThumbnailData.insets.left * mThumbnailScale, - -mThumbnailData.insets.top * mThumbnailScale); + mMatrix.setTranslate(-mThumbnailData.insets.left, -mThumbnailData.insets.top); mMatrix.postScale(mThumbnailScale, mThumbnailScale); mBitmapShader.setLocalMatrix(mMatrix); } invalidate(); } - - public void setDimAlpha(float dimAlpha) { - mDimAlpha = dimAlpha; - updateThumbnailPaintFilter(); - } } diff --git a/quickstep/src/com/android/quickstep/TaskView.java b/quickstep/src/com/android/quickstep/TaskView.java index ea584f0095..f6408a89d3 100644 --- a/quickstep/src/com/android/quickstep/TaskView.java +++ b/quickstep/src/com/android/quickstep/TaskView.java @@ -16,17 +16,26 @@ package com.android.quickstep; +import android.app.ActivityOptions; import android.content.Context; +import android.graphics.Rect; import android.util.AttributeSet; import android.widget.FrameLayout; import android.widget.ImageView; import com.android.launcher3.R; +import com.android.launcher3.uioverrides.OverviewState; import com.android.systemui.shared.recents.model.Task; import com.android.systemui.shared.recents.model.Task.TaskCallbacks; import com.android.systemui.shared.recents.model.ThumbnailData; +import com.android.systemui.shared.recents.view.AppTransitionAnimationSpecCompat; +import com.android.systemui.shared.recents.view.AppTransitionAnimationSpecsFuture; +import com.android.systemui.shared.recents.view.RecentsTransition; import com.android.systemui.shared.system.ActivityManagerWrapper; +import java.util.ArrayList; +import java.util.List; + /** * A task in the Recents view. */ @@ -48,10 +57,7 @@ public class TaskView extends FrameLayout implements TaskCallbacks { super(context, attrs, defStyleAttr); setWillNotDraw(false); setOnClickListener((view) -> { - if (mTask != null) { - ActivityManagerWrapper.getInstance().startActivityFromRecentsAsync(mTask.key, - null, null, null); - } + launchTask(true /* animate */); }); } @@ -65,20 +71,63 @@ public class TaskView extends FrameLayout implements TaskCallbacks { * Updates this task view to the given {@param task}. */ public void bind(Task task) { + if (mTask != null) { + mTask.removeCallback(this); + } mTask = task; task.addCallback(this); } + public Task getTask() { + return mTask; + } + + public TaskThumbnailView getThumbnail() { + return mSnapshotView; + } + + public void launchTask(boolean animate) { + if (mTask != null) { + final ActivityOptions opts; + if (animate) { + // Calculate the bounds of the thumbnail to animate from + final Rect bounds = new Rect(); + final int[] pos = new int[2]; + mSnapshotView.getLocationInWindow(pos); + bounds.set(pos[0], pos[1], + pos[0] + mSnapshotView.getWidth(), + pos[1] + mSnapshotView.getHeight()); + AppTransitionAnimationSpecsFuture animFuture = + new AppTransitionAnimationSpecsFuture(getHandler()) { + @Override + public List composeSpecs() { + ArrayList specs = + new ArrayList<>(); + specs.add(new AppTransitionAnimationSpecCompat(mTask.key.id, null, + bounds)); + return specs; + } + }; + opts = RecentsTransition.createAspectScaleAnimation( + getContext(), getHandler(), true /* scaleUp */, animFuture, null); + } else { + opts = ActivityOptions.makeCustomAnimation(getContext(), 0, 0); + } + ActivityManagerWrapper.getInstance().startActivityFromRecentsAsync(mTask.key, + opts, null, null); + } + } + @Override public void onTaskDataLoaded(Task task, ThumbnailData thumbnailData) { mSnapshotView.setThumbnail(thumbnailData); - mSnapshotView.setDimAlpha(1f); mIconView.setImageDrawable(task.icon); } @Override public void onTaskDataUnloaded() { - // Do nothing + mSnapshotView.setThumbnail(null); + mIconView.setImageDrawable(null); } @Override diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java index dcfa53b41e..121817698c 100644 --- a/quickstep/src/com/android/quickstep/TouchInteractionService.java +++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java @@ -23,8 +23,10 @@ import android.app.ActivityManager.RunningTaskInfo; import android.app.ActivityOptions; import android.app.Service; import android.content.ComponentName; +import android.content.Context; import android.content.Intent; import android.content.pm.ResolveInfo; +import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.Point; import android.graphics.PointF; @@ -32,6 +34,7 @@ import android.graphics.Rect; import android.os.Bundle; import android.os.IBinder; import android.os.RemoteException; +import android.os.UserHandle; import android.util.Log; import android.view.Display; import android.view.MotionEvent; @@ -39,9 +42,17 @@ import android.view.VelocityTracker; import android.view.ViewConfiguration; import android.view.WindowManager; +import com.android.launcher3.LauncherAppState; +import com.android.launcher3.R; import com.android.systemui.shared.recents.IOverviewProxy; import com.android.systemui.shared.recents.ISystemUiProxy; +import com.android.systemui.shared.recents.model.RecentsTaskLoadPlan; +import com.android.systemui.shared.recents.model.RecentsTaskLoadPlan.Options; +import com.android.systemui.shared.recents.model.RecentsTaskLoader; import com.android.systemui.shared.system.ActivityManagerWrapper; +import com.android.systemui.shared.system.BackgroundExecutor; + +import java.util.concurrent.Future; /** * Service connected by system-UI for handling touch interaction. @@ -50,6 +61,8 @@ public class TouchInteractionService extends Service { private static final String TAG = "TouchInteractionService"; + private static RecentsTaskLoader sRecentsTaskLoader; + private final IBinder mMyBinder = new IOverviewProxy.Stub() { @Override @@ -68,6 +81,7 @@ public class TouchInteractionService extends Service { private Intent mHomeIntent; private ComponentName mLauncher; + private final PointF mDownPos = new PointF(); private final PointF mLastPos = new PointF(); private int mActivePointerId = INVALID_POINTER_ID; @@ -89,6 +103,14 @@ public class TouchInteractionService extends Service { ResolveInfo info = getPackageManager().resolveActivity(mHomeIntent, 0); mLauncher = new ComponentName(getPackageName(), info.activityInfo.name); mHomeIntent.setComponent(mLauncher); + + Resources res = getResources(); + if (sRecentsTaskLoader == null) { + sRecentsTaskLoader = new RecentsTaskLoader(this, + res.getInteger(R.integer.config_recentsMaxThumbnailCacheSize), + res.getInteger(R.integer.config_recentsMaxIconCacheSize), 0); + sRecentsTaskLoader.startLoader(this); + } } @Override @@ -97,6 +119,10 @@ public class TouchInteractionService extends Service { return mMyBinder; } + public static RecentsTaskLoader getRecentsTaskLoader() { + return sRecentsTaskLoader; + } + private void handleMotionEvent(MotionEvent ev) { if (ev.getActionMasked() != MotionEvent.ACTION_DOWN && mVelocityTracker == null) { return; @@ -170,16 +196,46 @@ public class TouchInteractionService extends Service { } private void startTouchTracking() { - mInteractionHandler = new NavBarSwipeInteractionHandler(getCurrentTaskSnapshot(), mRunningTask); + // Create the shared handler + mInteractionHandler = new NavBarSwipeInteractionHandler(getCurrentTaskSnapshot(), + mRunningTask); - Bundle extras = new Bundle(); - extras.putBinder(EXTRA_STATE_HANDLER, mInteractionHandler); - Intent homeIntent = new Intent(mHomeIntent).putExtras(extras); + // Preload and start the recents activity on a background thread + final Context context = this; + final int runningTaskId = ActivityManagerWrapper.getInstance().getRunningTask().id; + final RecentsTaskLoadPlan loadPlan = new RecentsTaskLoadPlan(context); + Future loadPlanFuture = BackgroundExecutor.get().submit(() -> { + // Preload the plan + RecentsTaskLoader loader = TouchInteractionService.getRecentsTaskLoader(); + loadPlan.preloadPlan(loader, runningTaskId, UserHandle.myUserId()); - // TODO: Call ActivityManager#startRecentsActivity instead, so that the system knows that - // recents was started and not Home. - startActivity(homeIntent, - ActivityOptions.makeCustomAnimation(this, 0, 0).toBundle()); + // Pass the + Bundle extras = new Bundle(); + extras.putBinder(EXTRA_STATE_HANDLER, mInteractionHandler); + + // Start the activity + Intent homeIntent = new Intent(mHomeIntent); + homeIntent.putExtras(extras); + startActivity(homeIntent, ActivityOptions.makeCustomAnimation(this, 0, 0).toBundle()); + /* + ActivityManagerWrapper.getInstance().startRecentsActivity(null, options, + ActivityOptions.makeCustomAnimation(this, 0, 0), UserHandle.myUserId(), + null, null); + */ + + // Kick off loading of the plan while the activity is starting + Options loadOpts = new Options(); + loadOpts.runningTaskId = runningTaskId; + loadOpts.loadIcons = true; + loadOpts.loadThumbnails = true; + loadOpts.numVisibleTasks = 2; + loadOpts.numVisibleTaskThumbnails = 2; + loadOpts.onlyLoadForCache = false; + loadOpts.onlyLoadPausedActivities = false; + loader.loadTasks(loadPlan, loadOpts); + }, loadPlan); + + mInteractionHandler.setLastLoadPlan(loadPlanFuture); } private void endInteraction() { diff --git a/res/values/config.xml b/res/values/config.xml index 54328e1486..0ff0d758bf 100644 --- a/res/values/config.xml +++ b/res/values/config.xml @@ -134,4 +134,8 @@ + + 6 + 12 + diff --git a/res/values/dimens.xml b/res/values/dimens.xml index 957ec191cb..59736d8fde 100644 --- a/res/values/dimens.xml +++ b/res/values/dimens.xml @@ -232,4 +232,7 @@ 19dp 0.5dp 70dp + + + 10dp diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java index 6030e08865..6ddaf29db8 100644 --- a/src/com/android/launcher3/DeviceProfile.java +++ b/src/com/android/launcher3/DeviceProfile.java @@ -27,7 +27,6 @@ import android.graphics.Rect; import android.util.DisplayMetrics; import android.view.Gravity; import android.view.View; -import android.view.ViewGroup; import android.view.ViewGroup.LayoutParams; import android.widget.FrameLayout; @@ -681,13 +680,13 @@ public class DeviceProfile { } } - private int getCurrentWidth() { + public int getCurrentWidth() { return isLandscape ? Math.max(widthPx, heightPx) : Math.min(widthPx, heightPx); } - private int getCurrentHeight() { + public int getCurrentHeight() { return isLandscape ? Math.min(widthPx, heightPx) : Math.max(widthPx, heightPx); diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java index b1b3452e4b..60c00fb55b 100644 --- a/src/com/android/launcher3/Launcher.java +++ b/src/com/android/launcher3/Launcher.java @@ -63,7 +63,6 @@ import android.graphics.Point; import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.os.AsyncTask; -import android.os.Binder; import android.os.Build; import android.os.Bundle; import android.os.Parcelable; @@ -362,6 +361,8 @@ public class Launcher extends BaseActivity restoreState(savedInstanceState); + InternalStateHandler.handleCreate(this, getIntent()); + // We only load the page synchronously if the user rotates (or triggers a // configuration change) while launcher is in the foreground int currentScreen = PagedView.INVALID_RESTORE_PAGE; @@ -1347,7 +1348,6 @@ public class Launcher extends BaseActivity // Check this condition before handling isActionMain, as this will get reset. boolean shouldMoveToDefaultScreen = alreadyOnHome && isInState(NORMAL) && AbstractFloatingView.getTopOpenView(this) == null; - boolean isActionMain = Intent.ACTION_MAIN.equals(intent.getAction()); if (isActionMain) { if (mWorkspace == null) { @@ -1407,7 +1407,7 @@ public class Launcher extends BaseActivity }); } } - InternalStateHandler.handleIntent(this, intent); + InternalStateHandler.handleNewIntent(this, intent, alreadyOnHome); TraceHelper.endSection("NEW_INTENT"); } diff --git a/src/com/android/launcher3/states/InternalStateHandler.java b/src/com/android/launcher3/states/InternalStateHandler.java index a90ed36aa9..c6feefc8bc 100644 --- a/src/com/android/launcher3/states/InternalStateHandler.java +++ b/src/com/android/launcher3/states/InternalStateHandler.java @@ -29,15 +29,30 @@ public abstract class InternalStateHandler extends Binder implements OnResumeCal public static final String EXTRA_STATE_HANDLER = "launcher.state_handler"; - public abstract void onNewIntent(Launcher launcher); + public abstract void onCreate(Launcher launcher); + public abstract void onNewIntent(Launcher launcher, boolean alreadyOnHome); - public static void handleIntent(Launcher launcher, Intent intent) { - IBinder stateBinder = intent.getExtras().getBinder(EXTRA_STATE_HANDLER); - if (stateBinder instanceof InternalStateHandler) { - InternalStateHandler handler = (InternalStateHandler) stateBinder; - launcher.setOnResumeCallback(handler); - handler.onNewIntent(launcher); + public static void handleCreate(Launcher launcher, Intent intent) { + if (intent.getExtras() != null) { + IBinder stateBinder = intent.getExtras().getBinder(EXTRA_STATE_HANDLER); + if (stateBinder instanceof InternalStateHandler) { + InternalStateHandler handler = (InternalStateHandler) stateBinder; + launcher.setOnResumeCallback(handler); + handler.onCreate(launcher); + } + intent.getExtras().remove(EXTRA_STATE_HANDLER); + } + } + + public static void handleNewIntent(Launcher launcher, Intent intent, boolean alreadyOnHome) { + if (intent.getExtras() != null) { + IBinder stateBinder = intent.getExtras().getBinder(EXTRA_STATE_HANDLER); + if (stateBinder instanceof InternalStateHandler) { + InternalStateHandler handler = (InternalStateHandler) stateBinder; + launcher.setOnResumeCallback(handler); + handler.onNewIntent(launcher, alreadyOnHome); + } + intent.getExtras().remove(EXTRA_STATE_HANDLER); } - intent.getExtras().remove(EXTRA_STATE_HANDLER); } }