Load some recent tasks
Bug: 69166452
Test: Build quickstep
Change-Id: Id4b0172256d6920616a6b9529d61abd1fe0c1a36
diff --git a/quickstep/libs/sysui_shared.jar b/quickstep/libs/sysui_shared.jar
index a76f4f9..ef50ac4 100644
--- a/quickstep/libs/sysui_shared.jar
+++ b/quickstep/libs/sysui_shared.jar
Binary files differ
diff --git a/quickstep/res/drawable/task_thumbnail_background.xml b/quickstep/res/drawable/task_thumbnail_background.xml
index 27efd6c..603380e 100644
--- a/quickstep/res/drawable/task_thumbnail_background.xml
+++ b/quickstep/res/drawable/task_thumbnail_background.xml
@@ -15,5 +15,5 @@
-->
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
<solid android:color="#FF000000" />
- <corners android:radius="6dp" />
+ <corners android:radius="2dp" />
</shape>
diff --git a/quickstep/res/layout/overview_panel.xml b/quickstep/res/layout/overview_panel.xml
index 521551c..a8b91c5 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">
-
- <LinearLayout
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:paddingStart="40dp"
- android:paddingEnd="40dp"
- android:orientation="horizontal">
-
- <com.android.quickstep.SimpleTaskView
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:background="#44FF0000"
- android:layout_marginEnd="10dp"/>
-
- <com.android.quickstep.SimpleTaskView
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:background="#4400FF00"
- android:layout_marginEnd="10dp"/>
-
- <com.android.quickstep.SimpleTaskView
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:background="#440000FF" />
- </LinearLayout>
-
-</com.android.quickstep.RecentsView>
\ 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 9d8aea7..fdf1adc 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" />
<ImageView
android:id="@+id/icon"
- android:layout_width="36dp"
- android:layout_height="36dp"
+ android:layout_width="48dp"
+ android:layout_height="48dp"
android:layout_gravity="top|center_horizontal"
android:elevation="5dp"/>
</com.android.quickstep.TaskView>
\ 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 9bdd7a3..26f5d5b 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/OverviewState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/OverviewState.java
@@ -46,12 +46,14 @@
@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 caeef50..0810579 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.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 @@
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<RecentsTaskLoadPlan> mFutureLoadPlan;
private Launcher mLauncher;
private Choreographer mChoreographer;
@@ -94,9 +103,10 @@
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 @@
}
@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 @@
// 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<RecentsTaskLoadPlan> 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 @@
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 d7559da..528b11d 100644
--- a/quickstep/src/com/android/quickstep/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/RecentsView.java
@@ -19,17 +19,43 @@
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 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<Task> 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 791fe9f..2ef3942 100644
--- a/quickstep/src/com/android/quickstep/SnapshotDragView.java
+++ b/quickstep/src/com/android/quickstep/SnapshotDragView.java
@@ -23,6 +23,7 @@
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 @@
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 96c93c2..55d22e0 100644
--- a/quickstep/src/com/android/quickstep/TaskThumbnailView.java
+++ b/quickstep/src/com/android/quickstep/TaskThumbnailView.java
@@ -22,20 +22,17 @@
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 @@
}
}
+ /**
+ * 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 @@
(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 @@
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 @@
// 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 ea584f0..f6408a8 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 @@
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 @@
* 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<AppTransitionAnimationSpecCompat> composeSpecs() {
+ ArrayList<AppTransitionAnimationSpecCompat> 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 dcfa53b..1218176 100644
--- a/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -23,8 +23,10 @@
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.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.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 @@
private static final String TAG = "TouchInteractionService";
+ private static RecentsTaskLoader sRecentsTaskLoader;
+
private final IBinder mMyBinder = new IOverviewProxy.Stub() {
@Override
@@ -68,6 +81,7 @@
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 @@
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 @@
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 @@
}
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<RecentsTaskLoadPlan> 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 54328e1..0ff0d75 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -134,4 +134,8 @@
<item type="id" name="search_container_hotseat" />
<item type="id" name="search_container_all_apps" />
+<!-- Recents -->
+ <integer name="config_recentsMaxThumbnailCacheSize">6</integer>
+ <integer name="config_recentsMaxIconCacheSize">12</integer>
+
</resources>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 957ec19..59736d8 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -232,4 +232,7 @@
<dimen name="horizontal_ellipsis_offset">19dp</dimen>
<dimen name="popup_item_divider_height">0.5dp</dimen>
<dimen name="swipe_helper_falsing_threshold">70dp</dimen>
+
+<!-- Recents -->
+ <dimen name="recents_page_spacing">10dp</dimen>
</resources>
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index 6030e08..6ddaf29 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -27,7 +27,6 @@
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 @@
}
}
- 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 b1b3452..60c00fb 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -63,7 +63,6 @@
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 @@
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 @@
// 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 @@
});
}
}
- 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 a90ed36..c6feefc 100644
--- a/src/com/android/launcher3/states/InternalStateHandler.java
+++ b/src/com/android/launcher3/states/InternalStateHandler.java
@@ -29,15 +29,30 @@
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);
}
- 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);
+ }
}
}