[automerger] Various quickscrub fixes am: 9bb8ffb5e3
Change-Id: Id9f1cb83795b3164dd8bc67c879a3b3d8b8fd91f
diff --git a/quickstep/src/com/android/quickstep/ActivityControlHelper.java b/quickstep/src/com/android/quickstep/ActivityControlHelper.java
index e202c57..52a6dd5 100644
--- a/quickstep/src/com/android/quickstep/ActivityControlHelper.java
+++ b/quickstep/src/com/android/quickstep/ActivityControlHelper.java
@@ -46,6 +46,7 @@
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.LauncherInitListener;
import com.android.launcher3.LauncherState;
+import com.android.launcher3.R;
import com.android.launcher3.allapps.AllAppsTransitionController;
import com.android.launcher3.allapps.DiscoveryBounce;
import com.android.launcher3.anim.AnimatorPlaybackController;
@@ -82,7 +83,8 @@
void onQuickInteractionStart(T activity, @Nullable RunningTaskInfo taskInfo,
boolean activityVisible);
- float getTranslationYForQuickScrub(T activity);
+ float getTranslationYForQuickScrub(TransformedRect targetRect, DeviceProfile dp,
+ Context context);
void executeOnWindowAvailable(T activity, Runnable action);
@@ -151,10 +153,15 @@
}
@Override
- public float getTranslationYForQuickScrub(Launcher activity) {
- LauncherRecentsView recentsView = activity.getOverviewPanel();
- return recentsView.computeTranslationYForFactor(
- FastOverviewState.OVERVIEW_TRANSLATION_FACTOR);
+ public float getTranslationYForQuickScrub(TransformedRect targetRect, DeviceProfile dp,
+ Context context) {
+ // The padding calculations are exactly same as that of RecentsView.setInsets
+ int topMargin = context.getResources()
+ .getDimensionPixelSize(R.dimen.task_thumbnail_top_margin);
+ int paddingTop = targetRect.rect.top - topMargin - dp.getInsets().top;
+ int paddingBottom = dp.availableHeightPx + dp.getInsets().top - targetRect.rect.bottom;
+
+ return FastOverviewState.OVERVIEW_TRANSLATION_FACTOR * (paddingBottom - paddingTop);
}
@Override
@@ -380,7 +387,8 @@
}
@Override
- public float getTranslationYForQuickScrub(RecentsActivity activity) {
+ public float getTranslationYForQuickScrub(TransformedRect targetRect, DeviceProfile dp,
+ Context context) {
return 0;
}
diff --git a/quickstep/src/com/android/quickstep/DeferredTouchConsumer.java b/quickstep/src/com/android/quickstep/DeferredTouchConsumer.java
index b92678a..8e83bd0 100644
--- a/quickstep/src/com/android/quickstep/DeferredTouchConsumer.java
+++ b/quickstep/src/com/android/quickstep/DeferredTouchConsumer.java
@@ -64,6 +64,16 @@
}
@Override
+ public void onQuickStep(MotionEvent ev) {
+ mTarget.onQuickStep(ev);
+ }
+
+ @Override
+ public void onCommand(int command) {
+ mTarget.onCommand(command);
+ }
+
+ @Override
public void preProcessMotionEvent(MotionEvent ev) {
mVelocityTracker.addMovement(ev);
}
@@ -92,6 +102,11 @@
return target == null ? true : target.deferNextEventToMainThread();
}
+ @Override
+ public void onShowOverviewFromAltTab() {
+ mTarget.onShowOverviewFromAltTab();
+ }
+
public interface DeferredTouchProvider {
TouchConsumer createTouchConsumer(VelocityTracker tracker);
diff --git a/quickstep/src/com/android/quickstep/MotionEventQueue.java b/quickstep/src/com/android/quickstep/MotionEventQueue.java
index 15f5aa5..f73be6c 100644
--- a/quickstep/src/com/android/quickstep/MotionEventQueue.java
+++ b/quickstep/src/com/android/quickstep/MotionEventQueue.java
@@ -55,6 +55,8 @@
ACTION_VIRTUAL | (6 << ACTION_POINTER_INDEX_SHIFT);
private static final int ACTION_QUICK_STEP =
ACTION_VIRTUAL | (7 << ACTION_POINTER_INDEX_SHIFT);
+ private static final int ACTION_COMMAND =
+ ACTION_VIRTUAL | (8 << ACTION_POINTER_INDEX_SHIFT);
private final EventArray mEmptyArray = new EventArray();
private final Object mExecutionLock = new Object();
@@ -165,6 +167,9 @@
case ACTION_QUICK_STEP:
mConsumer.onQuickStep(event);
break;
+ case ACTION_COMMAND:
+ mConsumer.onCommand(event.getSource());
+ break;
default:
Log.e(TAG, "Invalid virtual event: " + event.getAction());
}
@@ -222,6 +227,12 @@
queueVirtualAction(ACTION_DEFER_INIT, 0);
}
+ public void onCommand(int command) {
+ MotionEvent ev = MotionEvent.obtain(0, 0, ACTION_COMMAND, 0, 0, 0);
+ ev.setSource(command);
+ queueNoPreProcess(ev);
+ }
+
public TouchConsumer getConsumer() {
return mConsumer;
}
diff --git a/quickstep/src/com/android/quickstep/OtherActivityTouchConsumer.java b/quickstep/src/com/android/quickstep/OtherActivityTouchConsumer.java
index 9ba3328..23357ea 100644
--- a/quickstep/src/com/android/quickstep/OtherActivityTouchConsumer.java
+++ b/quickstep/src/com/android/quickstep/OtherActivityTouchConsumer.java
@@ -37,6 +37,7 @@
import android.os.Bundle;
import android.os.Looper;
import android.os.SystemClock;
+import android.util.SparseArray;
import android.view.Choreographer;
import android.view.Display;
import android.view.MotionEvent;
@@ -69,6 +70,7 @@
private static final long LAUNCHER_DRAW_TIMEOUT_MS = 150;
+ private final SparseArray<RecentsAnimationState> mAnimationStates = new SparseArray<>();
private final RunningTaskInfo mRunningTask;
private final RecentsModel mRecentsModel;
private final Intent mHomeIntent;
@@ -212,8 +214,9 @@
private void startTouchTrackingForWindowAnimation(long touchTimeMs) {
// Create the shared handler
+ RecentsAnimationState animationState = new RecentsAnimationState();
final WindowTransformSwipeHandler handler = new WindowTransformSwipeHandler(
- mRunningTask, this, touchTimeMs, mActivityControlHelper);
+ animationState.id, mRunningTask, this, touchTimeMs, mActivityControlHelper);
// Preload the plan
mRecentsModel.loadTasks(mRunningTask.id, null);
@@ -237,31 +240,7 @@
public void onHandleAssistData(Bundle bundle) {
mRecentsModel.preloadAssistData(mRunningTask.id, bundle);
}
- },
- new RecentsAnimationListener() {
- public void onAnimationStart(
- RecentsAnimationControllerCompat controller,
- RemoteAnimationTargetCompat[] apps, Rect homeContentInsets,
- Rect minimizedHomeBounds) {
- if (mInteractionHandler == handler) {
- TraceHelper.partitionSection("RecentsController", "Received");
- handler.onRecentsAnimationStart(controller,
- new RemoteAnimationTargetSet(apps, MODE_CLOSING),
- homeContentInsets, minimizedHomeBounds);
- } else {
- TraceHelper.endSection("RecentsController", "Finishing no handler");
- controller.finish(false /* toHome */);
- }
- }
-
- public void onAnimationCanceled() {
- TraceHelper.endSection("RecentsController",
- "Cancelled: " + mInteractionHandler);
- if (mInteractionHandler == handler) {
- handler.onRecentsAnimationCanceled();
- }
- }
- }, null, null);
+ }, animationState, null, null);
if (Looper.myLooper() != Looper.getMainLooper()) {
startActivity.run();
@@ -277,6 +256,14 @@
}
}
+ @Override
+ public void onCommand(int command) {
+ RecentsAnimationState state = mAnimationStates.get(command);
+ if (state != null) {
+ state.execute();
+ }
+ }
+
/**
* Called when the gesture has ended. Does not correlate to the completion of the interaction as
* the animation can still be running.
@@ -398,4 +385,55 @@
// TODO: Consider also check if the eventQueue is using mainThread of not.
return mInteractionHandler != null;
}
+
+ private class RecentsAnimationState implements RecentsAnimationListener {
+
+ private final int id;
+
+ private RecentsAnimationControllerCompat mController;
+ private RemoteAnimationTargetSet mTargets;
+ private Rect mHomeContentInsets;
+ private Rect mMinimizedHomeBounds;
+ private boolean mCancelled;
+
+ public RecentsAnimationState() {
+ id = mAnimationStates.size();
+ mAnimationStates.put(id, this);
+ }
+
+ @Override
+ public void onAnimationStart(
+ RecentsAnimationControllerCompat controller,
+ RemoteAnimationTargetCompat[] apps, Rect homeContentInsets,
+ Rect minimizedHomeBounds) {
+ mController = controller;
+ mTargets = new RemoteAnimationTargetSet(apps, MODE_CLOSING);
+ mHomeContentInsets = homeContentInsets;
+ mMinimizedHomeBounds = minimizedHomeBounds;
+ mEventQueue.onCommand(id);
+ }
+
+ @Override
+ public void onAnimationCanceled() {
+ mCancelled = true;
+ mEventQueue.onCommand(id);
+ }
+
+ public void execute() {
+ if (mInteractionHandler == null || mInteractionHandler.id != id) {
+ if (!mCancelled && mController != null) {
+ TraceHelper.endSection("RecentsController", "Finishing no handler");
+ mController.finish(false /* toHome */);
+ }
+ } else if (mCancelled) {
+ TraceHelper.endSection("RecentsController",
+ "Cancelled: " + mInteractionHandler);
+ mInteractionHandler.onRecentsAnimationCanceled();
+ } else {
+ TraceHelper.partitionSection("RecentsController", "Received");
+ mInteractionHandler.onRecentsAnimationStart(mController, mTargets,
+ mHomeContentInsets, mMinimizedHomeBounds);
+ }
+ }
+ }
}
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationWrapper.java b/quickstep/src/com/android/quickstep/RecentsAnimationWrapper.java
index 30b10b0..34d42ac 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationWrapper.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationWrapper.java
@@ -20,6 +20,8 @@
import com.android.launcher3.util.UiThreadHelper;
import com.android.quickstep.util.RemoteAnimationTargetSet;
import com.android.systemui.shared.system.RecentsAnimationControllerCompat;
+
+import java.util.ArrayList;
import java.util.concurrent.ExecutorService;
/**
@@ -27,6 +29,10 @@
*/
public class RecentsAnimationWrapper {
+ // A list of callbacks to run when we receive the recents animation target. There are different
+ // than the state callbacks as these run on the current worker thread.
+ private final ArrayList<Runnable> mCallbacks = new ArrayList<>();
+
public RemoteAnimationTargetSet targetSet;
private RecentsAnimationControllerCompat mController;
@@ -46,6 +52,21 @@
if (mInputConsumerEnabled) {
enableInputConsumer();
}
+
+ if (!mCallbacks.isEmpty()) {
+ for (Runnable action : new ArrayList<>(mCallbacks)) {
+ action.run();
+ }
+ mCallbacks.clear();
+ }
+ }
+
+ public synchronized void runOnInit(Runnable action) {
+ if (targetSet == null) {
+ mCallbacks.add(action);
+ } else {
+ action.run();
+ }
}
/**
diff --git a/quickstep/src/com/android/quickstep/TouchConsumer.java b/quickstep/src/com/android/quickstep/TouchConsumer.java
index aa844d8..4cecffa 100644
--- a/quickstep/src/com/android/quickstep/TouchConsumer.java
+++ b/quickstep/src/com/android/quickstep/TouchConsumer.java
@@ -48,6 +48,8 @@
default void onQuickStep(MotionEvent ev) { }
+ default void onCommand(int command) { }
+
/**
* Called on the binder thread to allow the consumer to process the motion event before it is
* posted on a handler thread.
diff --git a/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java b/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java
index d171f69..939811b 100644
--- a/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java
+++ b/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java
@@ -29,6 +29,7 @@
import android.annotation.TargetApi;
import android.app.ActivityManager.RunningTaskInfo;
import android.content.Context;
+import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.Point;
import android.graphics.Rect;
@@ -36,6 +37,7 @@
import android.os.Handler;
import android.os.Looper;
import android.os.SystemClock;
+import android.os.UserHandle;
import android.support.annotation.AnyThread;
import android.support.annotation.UiThread;
import android.support.annotation.WorkerThread;
@@ -51,6 +53,7 @@
import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.R;
+import com.android.launcher3.Utilities;
import com.android.launcher3.anim.AnimationSuccessListener;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.logging.UserEventDispatcher;
@@ -65,11 +68,12 @@
import com.android.quickstep.ActivityControlHelper.LayoutListener;
import com.android.quickstep.TouchConsumer.InteractionType;
import com.android.quickstep.util.ClipAnimationHelper;
-import com.android.quickstep.util.TransformedRect;
import com.android.quickstep.util.RemoteAnimationTargetSet;
+import com.android.quickstep.util.TransformedRect;
import com.android.quickstep.views.RecentsView;
import com.android.quickstep.views.TaskView;
import com.android.systemui.shared.recents.model.ThumbnailData;
+import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.InputConsumerController;
import com.android.systemui.shared.system.LatencyTrackerCompat;
import com.android.systemui.shared.system.RecentsAnimationControllerCompat;
@@ -167,6 +171,12 @@
private final Handler mMainThreadHandler = new Handler(Looper.getMainLooper());
+ // An increasing identifier per single instance of OtherActivityTouchConsumer. Generally one
+ // instance of OtherActivityTouchConsumer will only have one swipe handle, but sometimes we can
+ // end up with multiple handlers if we get recents command in the middle of a swipe gesture.
+ // This is used to match the corresponding activity manager callbacks in
+ // OtherActivityTouchConsumer
+ public final int id;
private final Context mContext;
private final ActivityControlHelper<T> mActivityControlHelper;
private final ActivityInitListener mActivityInitListener;
@@ -199,6 +209,7 @@
InputConsumerController.getRecentsAnimationInputConsumer();
private final RecentsAnimationWrapper mRecentsAnimationWrapper = new RecentsAnimationWrapper();
+
private final long mTouchTimeMs;
private long mLauncherFrameDrawnTime;
@@ -207,8 +218,9 @@
private float mLongSwipeDisplacement = 0;
private LongSwipeHelper mLongSwipeController;
- WindowTransformSwipeHandler(RunningTaskInfo runningTaskInfo, Context context, long touchTimeMs,
- ActivityControlHelper<T> controller) {
+ WindowTransformSwipeHandler(int id, RunningTaskInfo runningTaskInfo, Context context,
+ long touchTimeMs, ActivityControlHelper<T> controller) {
+ this.id = id;
mContext = context;
mRunningTaskInfo = runningTaskInfo;
mRunningTaskId = runningTaskInfo.id;
@@ -453,6 +465,7 @@
"Can't change interaction type to " + interactionType);
}
mInteractionType = interactionType;
+ mRecentsAnimationWrapper.runOnInit(this::shiftAnimationDestinationForQuickscrub);
setStateOnUiThread(STATE_QUICK_SCRUB_START | STATE_GESTURE_COMPLETED);
@@ -460,6 +473,34 @@
animateToProgress(1f, QUICK_SCRUB_FROM_APP_START_DURATION, LINEAR);
}
+ private void shiftAnimationDestinationForQuickscrub() {
+ TransformedRect tempRect = new TransformedRect();
+ mActivityControlHelper
+ .getSwipeUpDestinationAndLength(mDp, mContext, mInteractionType, tempRect);
+ mClipAnimationHelper.updateTargetRect(tempRect);
+
+ float offsetY =
+ mActivityControlHelper.getTranslationYForQuickScrub(tempRect, mDp, mContext);
+ float scale, offsetX;
+ Resources res = mContext.getResources();
+
+ if (ActivityManagerWrapper.getInstance().getRecentTasks(2, UserHandle.myUserId()).size()
+ < 2) {
+ // There are not enough tasks, we don't need to shift
+ offsetX = 0;
+ scale = 1;
+ } else {
+ offsetX = res.getDimensionPixelSize(R.dimen.recents_page_spacing)
+ + tempRect.rect.width();
+ float distanceToReachEdge = mDp.widthPx / 2 + tempRect.rect.width() / 2 +
+ res.getDimensionPixelSize(R.dimen.recents_page_spacing);
+ float interpolation = Math.min(1, offsetX / distanceToReachEdge);
+ scale = TaskView.getCurveScaleForInterpolation(interpolation);
+ }
+ mClipAnimationHelper.offsetTarget(scale, Utilities.isRtl(res) ? -offsetX : offsetX, offsetY,
+ QuickScrubController.QUICK_SCRUB_START_INTERPOLATOR);
+ }
+
@WorkerThread
public void updateDisplacement(float displacement) {
// We are moving in the negative x/y direction
@@ -658,7 +699,7 @@
: STATE_SCALED_CONTROLLER_APP);
}
});
- anim.start();
+ mRecentsAnimationWrapper.runOnInit(anim::start);
}
@UiThread
@@ -786,30 +827,6 @@
// Inform the last progress in case we skipped before.
mQuickScrubController.onQuickScrubProgress(mCurrentQuickScrubProgress);
-
- // Make sure the window follows the first task if it moves, e.g. during quick scrub.
- TaskView firstTask = mRecentsView.getPageAt(0);
- // The first task may be null if we are swiping up from a task that does not
- // appear in the list (i.e. the assistant)
- if (firstTask != null) {
- int scrollForFirstTask = mRecentsView.getScrollForPage(0);
- int scrollForSecondTask = mRecentsView.getChildCount() > 1
- ? mRecentsView.getScrollForPage(1) : scrollForFirstTask;
- float offsetFromFirstTask = scrollForFirstTask - scrollForSecondTask;
-
- TransformedRect tempRect = new TransformedRect();
- mActivityControlHelper
- .getSwipeUpDestinationAndLength(mDp, mContext, mInteractionType, tempRect);
- float distanceToReachEdge = mDp.widthPx / 2 + tempRect.rect.width() / 2 +
- mContext.getResources().getDimensionPixelSize(R.dimen.recents_page_spacing);
- float interpolation = Math.min(1,
- Math.abs(offsetFromFirstTask) / distanceToReachEdge);
-
- mClipAnimationHelper.offsetTarget(
- firstTask.getCurveScaleForInterpolation(interpolation), offsetFromFirstTask,
- mActivityControlHelper.getTranslationYForQuickScrub(mActivity),
- QuickScrubController.QUICK_SCRUB_START_INTERPOLATOR);
- }
}
private void onFinishedTransitionToQuickScrub() {
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index 02cdd3a..776509c 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -507,6 +507,7 @@
DeviceProfile dp = mActivity.getDeviceProfile();
getTaskSize(dp, mTempRect);
+ // Keep this logic in sync with ActivityControlHelper.getTranslationYForQuickScrub.
mTempRect.top -= mTaskTopMargin;
setPadding(mTempRect.left - mInsets.left, mTempRect.top - mInsets.top,
dp.availableWidthPx + mInsets.left - mTempRect.right,
diff --git a/quickstep/src/com/android/quickstep/views/TaskView.java b/quickstep/src/com/android/quickstep/views/TaskView.java
index 5413a13..91c0fa5 100644
--- a/quickstep/src/com/android/quickstep/views/TaskView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskView.java
@@ -250,12 +250,12 @@
setPivotY(mSnapshotView.getTop() + mSnapshotView.getHeight() * 0.5f);
}
- public float getCurveScaleForInterpolation(float linearInterpolation) {
+ public static float getCurveScaleForInterpolation(float linearInterpolation) {
float curveInterpolation = CURVE_INTERPOLATOR.getInterpolation(linearInterpolation);
return getCurveScaleForCurveInterpolation(curveInterpolation);
}
- private float getCurveScaleForCurveInterpolation(float curveInterpolation) {
+ private static float getCurveScaleForCurveInterpolation(float curveInterpolation) {
return 1 - curveInterpolation * EDGE_SCALE_DOWN_FACTOR;
}
diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java
index 62b581f..de9cd98 100644
--- a/src/com/android/launcher3/PagedView.java
+++ b/src/com/android/launcher3/PagedView.java
@@ -1450,6 +1450,10 @@
protected boolean snapToPage(int whichPage, int delta, int duration, boolean immediate,
TimeInterpolator interpolator) {
+ if (mFirstLayout) {
+ setCurrentPage(whichPage);
+ return false;
+ }
if (FeatureFlags.IS_DOGFOOD_BUILD) {
duration *= Settings.System.getFloat(getContext().getContentResolver(),