diff options
9 files changed, 251 insertions, 182 deletions
diff --git a/quickstep/src/com/android/quickstep/MotionEventQueue.java b/quickstep/src/com/android/quickstep/MotionEventQueue.java index fae9b66a2..6e92d83c5 100644 --- a/quickstep/src/com/android/quickstep/MotionEventQueue.java +++ b/quickstep/src/com/android/quickstep/MotionEventQueue.java @@ -16,17 +16,22 @@ package com.android.quickstep; import static android.view.MotionEvent.ACTION_CANCEL; +import static android.view.MotionEvent.ACTION_MASK; import static android.view.MotionEvent.ACTION_MOVE; +import static android.view.MotionEvent.ACTION_POINTER_INDEX_SHIFT; + +import static com.android.quickstep.TouchConsumer.INTERACTION_QUICK_SCRUB; +import static com.android.quickstep.TouchConsumer.INTERACTION_QUICK_SWITCH; import android.annotation.TargetApi; import android.os.Build; +import android.util.Log; import android.view.Choreographer; import android.view.MotionEvent; import com.android.systemui.shared.system.ChoreographerCompat; import java.util.ArrayList; -import java.util.function.Consumer; /** * Helper class for batching input events @@ -34,6 +39,21 @@ import java.util.function.Consumer; @TargetApi(Build.VERSION_CODES.O) public class MotionEventQueue { + private static final String TAG = "MotionEventQueue"; + + private static final int ACTION_VIRTUAL = ACTION_MASK - 1; + + private static final int ACTION_QUICK_SWITCH = + ACTION_VIRTUAL | (1 << ACTION_POINTER_INDEX_SHIFT); + private static final int ACTION_QUICK_SCRUB_START = + ACTION_VIRTUAL | (2 << ACTION_POINTER_INDEX_SHIFT); + private static final int ACTION_QUICK_SCRUB_PROGRESS = + ACTION_VIRTUAL | (3 << ACTION_POINTER_INDEX_SHIFT); + private static final int ACTION_QUICK_SCRUB_END = + ACTION_VIRTUAL | (4 << ACTION_POINTER_INDEX_SHIFT); + private static final int ACTION_RESET = + ACTION_VIRTUAL | (5 << ACTION_POINTER_INDEX_SHIFT); + private final EventArray mEmptyArray = new EventArray(); private final Object mExecutionLock = new Object(); @@ -46,45 +66,48 @@ public class MotionEventQueue { private final Choreographer mMainChoreographer; - private Consumer<MotionEvent> mConsumer; + private final TouchConsumer mConsumer; private Choreographer mInterimChoreographer; private Choreographer mCurrentChoreographer; private Runnable mCurrentRunnable; - public MotionEventQueue(Choreographer choreographer, Consumer<MotionEvent> consumer) { + public MotionEventQueue(Choreographer choreographer, TouchConsumer consumer) { mMainChoreographer = choreographer; mConsumer = consumer; mCurrentChoreographer = mMainChoreographer; mCurrentRunnable = mMainFrameCallback; - } - - public void setConsumer(Consumer<MotionEvent> consumer) { - synchronized (mExecutionLock) { - mConsumer = consumer; - } + setInterimChoreographerLocked(consumer.getIntrimChoreographer(this)); } public void setInterimChoreographer(Choreographer choreographer) { synchronized (mExecutionLock) { synchronized (mArrays) { - mInterimChoreographer = choreographer; - if (choreographer == null) { - mCurrentChoreographer = mMainChoreographer; - mCurrentRunnable = mMainFrameCallback; - } else { - mCurrentChoreographer = mInterimChoreographer; - mCurrentRunnable = mInterimFrameCallback; - } - + setInterimChoreographerLocked(choreographer); ChoreographerCompat.postInputFrame(mCurrentChoreographer, mCurrentRunnable); } } } + private void setInterimChoreographerLocked(Choreographer choreographer) { + mInterimChoreographer = choreographer; + if (choreographer == null) { + mCurrentChoreographer = mMainChoreographer; + mCurrentRunnable = mMainFrameCallback; + } else { + mCurrentChoreographer = mInterimChoreographer; + mCurrentRunnable = mInterimFrameCallback; + } + } + public void queue(MotionEvent event) { + mConsumer.preProcessMotionEvent(event); + queueNoPreProcess(event); + } + + private void queueNoPreProcess(MotionEvent event) { synchronized (mArrays) { EventArray array = mArrays[mCurrentIndex]; if (array.isEmpty()) { @@ -116,7 +139,29 @@ public class MotionEventQueue { int size = array.size(); for (int i = 0; i < size; i++) { MotionEvent event = array.get(i); - mConsumer.accept(event); + if (event.getActionMasked() == ACTION_VIRTUAL) { + switch (event.getAction()) { + case ACTION_QUICK_SWITCH: + mConsumer.updateTouchTracking(INTERACTION_QUICK_SWITCH); + break; + case ACTION_QUICK_SCRUB_START: + mConsumer.updateTouchTracking(INTERACTION_QUICK_SCRUB); + break; + case ACTION_QUICK_SCRUB_PROGRESS: + mConsumer.onQuickScrubProgress(event.getX()); + break; + case ACTION_QUICK_SCRUB_END: + mConsumer.onQuickScrubEnd(); + break; + case ACTION_RESET: + mConsumer.reset(); + break; + default: + Log.e(TAG, "Invalid virtual event: " + event.getAction()); + } + } else { + mConsumer.accept(event); + } event.recycle(); } array.clear(); @@ -135,6 +180,30 @@ public class MotionEventQueue { } } + private void queueVirtualAction(int action, float progress) { + queueNoPreProcess(MotionEvent.obtain(0, 0, action, progress, 0, 0)); + } + + public void onQuickSwitch() { + queueVirtualAction(ACTION_QUICK_SWITCH, 0); + } + + public void onQuickScrubStart() { + queueVirtualAction(ACTION_QUICK_SCRUB_START, 0); + } + + public void onQuickScrubProgress(float progress) { + queueVirtualAction(ACTION_QUICK_SCRUB_PROGRESS, progress); + } + + public void onQuickScrubEnd() { + queueVirtualAction(ACTION_QUICK_SCRUB_END, 0); + } + + public void reset() { + queueVirtualAction(ACTION_RESET, 0); + } + private static class EventArray extends ArrayList<MotionEvent> { public int lastEventAction = ACTION_CANCEL; diff --git a/quickstep/src/com/android/quickstep/NavBarSwipeInteractionHandler.java b/quickstep/src/com/android/quickstep/NavBarSwipeInteractionHandler.java index 0be13ea70..ae70474c0 100644 --- a/quickstep/src/com/android/quickstep/NavBarSwipeInteractionHandler.java +++ b/quickstep/src/com/android/quickstep/NavBarSwipeInteractionHandler.java @@ -371,10 +371,6 @@ public class NavBarSwipeInteractionHandler extends BaseSwipeInteractionHandler i if (mQuickScrubController != null) { mQuickScrubController.onQuickSwitch(); } - } else if (mInteractionType == INTERACTION_QUICK_SCRUB) { - if (mQuickScrubController != null) { - mQuickScrubController.snapToPageForCurrentQuickScrubSection(); - } } } diff --git a/quickstep/src/com/android/quickstep/OtherActivityTouchConsumer.java b/quickstep/src/com/android/quickstep/OtherActivityTouchConsumer.java index ef7f894df..1e48a53b2 100644 --- a/quickstep/src/com/android/quickstep/OtherActivityTouchConsumer.java +++ b/quickstep/src/com/android/quickstep/OtherActivityTouchConsumer.java @@ -40,6 +40,7 @@ import android.os.Bundle; import android.os.Looper; import android.os.SystemClock; import android.util.Log; +import android.view.Choreographer; import android.view.Display; import android.view.MotionEvent; import android.view.Surface; @@ -110,6 +111,7 @@ public class OtherActivityTouchConsumer extends ContextWrapper implements TouchC private final Intent mHomeIntent; private final ISystemUiProxy mISystemUiProxy; private final MainThreadExecutor mMainThreadExecutor; + private final Choreographer mBackgroundThreadChoreographer; private final PointF mDownPos = new PointF(); private final PointF mLastPos = new PointF(); @@ -123,12 +125,13 @@ public class OtherActivityTouchConsumer extends ContextWrapper implements TouchC private @HitTarget int mDownHitTarget = HIT_TARGET_NONE; private VelocityTracker mVelocityTracker; + private MotionEventQueue mEventQueue; private final MetricsLogger mMetricsLogger = new MetricsLogger(); public OtherActivityTouchConsumer(Context base, RunningTaskInfo runningTaskInfo, RecentsModel recentsModel, Intent homeIntent, ISystemUiProxy systemUiProxy, - MainThreadExecutor mainThreadExecutor) { + MainThreadExecutor mainThreadExecutor, Choreographer backgroundThreadChoreographer) { super(base); mRunningTask = runningTaskInfo; mRecentsModel = recentsModel; @@ -136,6 +139,7 @@ public class OtherActivityTouchConsumer extends ContextWrapper implements TouchC mVelocityTracker = VelocityTracker.obtain(); mISystemUiProxy = systemUiProxy; mMainThreadExecutor = mainThreadExecutor; + mBackgroundThreadChoreographer = backgroundThreadChoreographer; } @Override @@ -394,8 +398,6 @@ public class OtherActivityTouchConsumer extends ContextWrapper implements TouchC } mVelocityTracker.recycle(); mVelocityTracker = null; - - onTouchTrackingComplete(); } @Override @@ -412,16 +414,23 @@ public class OtherActivityTouchConsumer extends ContextWrapper implements TouchC public void updateTouchTracking(int interactionType) { notifyGestureStarted(); - mMainThreadExecutor.execute(() -> { + if (isUsingScreenShot()) { + mMainThreadExecutor.execute(() -> { + if (mInteractionHandler != null) { + mInteractionHandler.updateInteractionType(interactionType); + } + }); + } else { if (mInteractionHandler != null) { mInteractionHandler.updateInteractionType(interactionType); } - }); + } } @Override - public boolean shouldUseBackgroundConsumer() { - return !isUsingScreenShot(); + public Choreographer getIntrimChoreographer(MotionEventQueue queue) { + mEventQueue = queue; + return isUsingScreenShot() ? null : mBackgroundThreadChoreographer; } @Override @@ -444,9 +453,9 @@ public class OtherActivityTouchConsumer extends ContextWrapper implements TouchC } } - public void onTouchTrackingComplete() { } - - public void switchToMainChoreographer() { } + public void switchToMainChoreographer() { + mEventQueue.setInterimChoreographer(null); + } @Override public void preProcessMotionEvent(MotionEvent ev) { diff --git a/quickstep/src/com/android/quickstep/QuickScrubController.java b/quickstep/src/com/android/quickstep/QuickScrubController.java index 8d5422f04..bc7647a93 100644 --- a/quickstep/src/com/android/quickstep/QuickScrubController.java +++ b/quickstep/src/com/android/quickstep/QuickScrubController.java @@ -38,9 +38,10 @@ public class QuickScrubController implements OnAlarmListener { private static final int QUICKSCRUB_SNAP_DURATION_PER_PAGE = 325; private static final int QUICKSCRUB_END_SNAP_DURATION_PER_PAGE = 60; - private Alarm mAutoAdvanceAlarm; - private RecentsView mRecentsView; + private final Alarm mAutoAdvanceAlarm; + private final RecentsView mRecentsView; + private boolean mInQuickScrub; private int mQuickScrubSection; private int mStartPage; @@ -51,32 +52,30 @@ public class QuickScrubController implements OnAlarmListener { } public void onQuickScrubStart(boolean startingFromHome) { + mInQuickScrub = true; mStartPage = startingFromHome ? 0 : mRecentsView.getFirstTaskIndex(); mQuickScrubSection = 0; } public void onQuickScrubEnd() { + mInQuickScrub = false; mAutoAdvanceAlarm.cancelAlarm(); - if (mRecentsView == null) { - } else { - int page = mRecentsView.getNextPage(); - Runnable launchTaskRunnable = () -> { - if (page < mRecentsView.getFirstTaskIndex()) { - // Call post() since we can't performClick() on a background thread. - mRecentsView.post(() -> mRecentsView.getPageAt(page).performClick()); - } else { - ((TaskView) mRecentsView.getPageAt(page)).launchTask(true); - } - }; - int snapDuration = Math.abs(page - mRecentsView.getPageNearestToCenterOfScreen()) - * QUICKSCRUB_END_SNAP_DURATION_PER_PAGE; - if (mRecentsView.snapToPage(page, snapDuration)) { - // Settle on the page then launch it - mRecentsView.setNextPageSwitchRunnable(launchTaskRunnable); + int page = mRecentsView.getNextPage(); + Runnable launchTaskRunnable = () -> { + if (page < mRecentsView.getFirstTaskIndex()) { + mRecentsView.getPageAt(page).performClick(); } else { - // No page move needed, just launch it - launchTaskRunnable.run(); + ((TaskView) mRecentsView.getPageAt(page)).launchTask(true); } + }; + int snapDuration = Math.abs(page - mRecentsView.getPageNearestToCenterOfScreen()) + * QUICKSCRUB_END_SNAP_DURATION_PER_PAGE; + if (mRecentsView.snapToPage(page, snapDuration)) { + // Settle on the page then launch it + mRecentsView.setNextPageSwitchRunnable(launchTaskRunnable); + } else { + // No page move needed, just launch it + launchTaskRunnable.run(); } } @@ -112,7 +111,9 @@ public class QuickScrubController implements OnAlarmListener { } public void snapToPageForCurrentQuickScrubSection() { - goToPageWithHaptic(mRecentsView.getFirstTaskIndex() + mQuickScrubSection); + if (mInQuickScrub) { + goToPageWithHaptic(mRecentsView.getFirstTaskIndex() + mQuickScrubSection); + } } private void goToPageWithHaptic(int pageToGoTo) { diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationWrapper.java b/quickstep/src/com/android/quickstep/RecentsAnimationWrapper.java index 2fae01a66..28229f6c0 100644 --- a/quickstep/src/com/android/quickstep/RecentsAnimationWrapper.java +++ b/quickstep/src/com/android/quickstep/RecentsAnimationWrapper.java @@ -15,9 +15,6 @@ */ package com.android.quickstep; -import android.os.Handler; -import android.os.Looper; - import com.android.systemui.shared.system.BackgroundExecutor; import com.android.systemui.shared.system.RecentsAnimationControllerCompat; import com.android.systemui.shared.system.RemoteAnimationTargetCompat; @@ -43,7 +40,8 @@ public class RecentsAnimationWrapper { } /** - * @param onFinishComplete A callback that runs on the UI thread. + * @param onFinishComplete A callback that runs after the animation controller has finished + * on the background thread. */ public void finish(boolean toHome, Runnable onFinishComplete) { BackgroundExecutor.get().submit(() -> { @@ -52,7 +50,7 @@ public class RecentsAnimationWrapper { controller.setInputConsumerEnabled(false); controller.finish(toHome); if (onFinishComplete != null) { - new Handler(Looper.getMainLooper()).post(onFinishComplete); + onFinishComplete.run(); } } } diff --git a/quickstep/src/com/android/quickstep/RecentsView.java b/quickstep/src/com/android/quickstep/RecentsView.java index 57188695e..a9d5e630b 100644 --- a/quickstep/src/com/android/quickstep/RecentsView.java +++ b/quickstep/src/com/android/quickstep/RecentsView.java @@ -266,6 +266,8 @@ public class RecentsView extends PagedView implements Insettable { return; } + int oldChildCount = getChildCount(); + // Ensure there are as many views as there are tasks in the stack (adding and trimming as // necessary) final LayoutInflater inflater = LayoutInflater.from(getContext()); @@ -296,6 +298,10 @@ public class RecentsView extends PagedView implements Insettable { taskView.setAlpha(1f); loader.loadTaskData(task); } + + if (oldChildCount != getChildCount()) { + mQuickScrubController.snapToPageForCurrentQuickScrubSection(); + } } private void updateTaskStackListenerState() { diff --git a/quickstep/src/com/android/quickstep/TouchConsumer.java b/quickstep/src/com/android/quickstep/TouchConsumer.java index 5cfa8df8d..aaea37957 100644 --- a/quickstep/src/com/android/quickstep/TouchConsumer.java +++ b/quickstep/src/com/android/quickstep/TouchConsumer.java @@ -18,6 +18,7 @@ package com.android.quickstep; import android.annotation.TargetApi; import android.os.Build; import android.support.annotation.IntDef; +import android.view.Choreographer; import android.view.MotionEvent; import com.android.systemui.shared.system.NavigationBarCompat.HitTarget; @@ -48,10 +49,6 @@ public interface TouchConsumer extends Consumer<MotionEvent> { default void reset() { } - default boolean shouldUseBackgroundConsumer() { - return false; - } - default void setDownHitTarget(@HitTarget int downHitTarget) { } default void updateTouchTracking(@InteractionType int interactionType) { } @@ -65,4 +62,8 @@ public interface TouchConsumer extends Consumer<MotionEvent> { * posted on a handler thread. */ default void preProcessMotionEvent(MotionEvent ev) { } + + default Choreographer getIntrimChoreographer(MotionEventQueue queue) { + return null; + } } diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java index 52cd60e4f..46ef528dc 100644 --- a/quickstep/src/com/android/quickstep/TouchInteractionService.java +++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java @@ -23,8 +23,6 @@ import static android.view.MotionEvent.ACTION_POINTER_UP; import static android.view.MotionEvent.ACTION_UP; import static com.android.launcher3.LauncherState.OVERVIEW; import static com.android.quickstep.QuickScrubController.QUICK_SWITCH_START_DURATION; -import static com.android.quickstep.TouchConsumer.INTERACTION_QUICK_SCRUB; -import static com.android.quickstep.TouchConsumer.INTERACTION_QUICK_SWITCH; import android.annotation.TargetApi; import android.app.ActivityManager.RunningTaskInfo; @@ -77,7 +75,7 @@ public class TouchInteractionService extends Service { @Override public void onMotionEvent(MotionEvent ev) { - onBinderMotionEvent(ev); + mEventQueue.queue(ev); } @Override @@ -90,29 +88,28 @@ public class TouchInteractionService extends Service { @Override public void onQuickSwitch() { - mCurrentConsumer.updateTouchTracking(INTERACTION_QUICK_SWITCH); + mEventQueue.onQuickSwitch(); } @Override public void onQuickScrubStart() { - mCurrentConsumer.updateTouchTracking(INTERACTION_QUICK_SCRUB); + mEventQueue.onQuickScrubStart(); sQuickScrubEnabled = true; } @Override - public void onQuickScrubEnd() { - mCurrentConsumer.onQuickScrubEnd(); - sQuickScrubEnabled = false; + public void onQuickScrubProgress(float progress) { + mEventQueue.onQuickScrubProgress(progress); } @Override - public void onQuickScrubProgress(float progress) { - mCurrentConsumer.onQuickScrubProgress(progress); + public void onQuickScrubEnd() { + mEventQueue.onQuickScrubEnd(); + sQuickScrubEnabled = false; } }; private final TouchConsumer mNoOpTouchConsumer = (ev) -> {}; - private TouchConsumer mCurrentConsumer = mNoOpTouchConsumer; private static boolean sConnected = false; private static boolean sQuickScrubEnabled = false; @@ -133,7 +130,10 @@ public class TouchInteractionService extends Service { private MotionEventQueue mEventQueue; private MainThreadExecutor mMainThreadExecutor; private ISystemUiProxy mISystemUiProxy; + + private Choreographer mMainThreadChoreographer; private Choreographer mBackgroundThreadChoreographer; + private MotionEventQueue mNoOpEventQueue; @Override public void onCreate() { @@ -151,7 +151,10 @@ public class TouchInteractionService extends Service { // Clear the packageName as system can fail to dedupe it b/64108432 mHomeIntent.setComponent(mLauncher).setPackage(null); - mEventQueue = new MotionEventQueue(Choreographer.getInstance(), mNoOpTouchConsumer); + mMainThreadChoreographer = Choreographer.getInstance(); + mNoOpEventQueue = new MotionEventQueue(mMainThreadChoreographer, mNoOpTouchConsumer); + mEventQueue = mNoOpEventQueue; + sConnected = true; // Temporarily disable model preload @@ -175,60 +178,32 @@ public class TouchInteractionService extends Service { private void onBinderPreMotionEvent(@HitTarget int downHitTarget) { mRunningTask = mAM.getRunningTask(); - mCurrentConsumer.reset(); + mEventQueue.reset(); + if (mRunningTask == null) { - mCurrentConsumer = mNoOpTouchConsumer; + mEventQueue = mNoOpEventQueue; } else if (mRunningTask.topActivity.equals(mLauncher)) { - mCurrentConsumer = getLauncherConsumer(); + mEventQueue = getLauncherEventQueue(); } else { - mCurrentConsumer = getOtherActivityConsumer(); + mEventQueue = new MotionEventQueue(mMainThreadChoreographer, + new OtherActivityTouchConsumer(this, mRunningTask, mRecentsModel, + mHomeIntent, mISystemUiProxy, mMainThreadExecutor, + mBackgroundThreadChoreographer)); } - - mCurrentConsumer.setDownHitTarget(downHitTarget); - mEventQueue.setConsumer(mCurrentConsumer); - mEventQueue.setInterimChoreographer(mCurrentConsumer.shouldUseBackgroundConsumer() - ? mBackgroundThreadChoreographer : null); - } - - private void onBinderMotionEvent(MotionEvent ev) { - mCurrentConsumer.preProcessMotionEvent(ev); - mEventQueue.queue(ev); } - private TouchConsumer getOtherActivityConsumer() { - TouchConsumer consumer = new OtherActivityTouchConsumer(this, mRunningTask, mRecentsModel, - mHomeIntent, mISystemUiProxy, mMainThreadExecutor) { - - @Override - public void switchToMainChoreographer() { - if (mCurrentConsumer == this) { - mEventQueue.setInterimChoreographer(null); - } - } - - @Override - public void onTouchTrackingComplete() { - if (mCurrentConsumer == this) { - mCurrentConsumer = mNoOpTouchConsumer; - mEventQueue.setConsumer(mCurrentConsumer); - } - } - }; - return consumer; - } - - private TouchConsumer getLauncherConsumer() { - + private MotionEventQueue getLauncherEventQueue() { Launcher launcher = (Launcher) LauncherAppState.getInstance(this).getModel().getCallback(); if (launcher == null) { - return mNoOpTouchConsumer; + return mNoOpEventQueue; } View target = launcher.getDragLayer(); - return new LauncherTouchConsumer(launcher, target); + return new MotionEventQueue(mMainThreadChoreographer, + new LauncherTouchConsumer(launcher, target)); } - private class LauncherTouchConsumer implements TouchConsumer { + private static class LauncherTouchConsumer implements TouchConsumer { private final Launcher mLauncher; private final View mTarget; @@ -238,6 +213,7 @@ public class TouchInteractionService extends Service { private final QuickScrubController mQuickScrubController; private boolean mTrackingStarted = false; + private boolean mInvalidated = false; LauncherTouchConsumer(Launcher launcher, View target) { mLauncher = launcher; @@ -250,6 +226,9 @@ public class TouchInteractionService extends Service { @Override public void accept(MotionEvent ev) { + if (mInvalidated) { + return; + } if (!mTarget.hasWindowFocus()) { return; } @@ -262,7 +241,7 @@ public class TouchInteractionService extends Service { case ACTION_POINTER_UP: case ACTION_POINTER_DOWN: if (!mTrackingStarted) { - mEventQueue.setConsumer(mNoOpTouchConsumer); + mInvalidated = true; } break; case ACTION_MOVE: { @@ -286,7 +265,7 @@ public class TouchInteractionService extends Service { } if (action == ACTION_UP || action == ACTION_CANCEL) { - mEventQueue.setConsumer(mNoOpTouchConsumer); + mInvalidated = true; } } @@ -301,35 +280,42 @@ public class TouchInteractionService extends Service { @Override public void updateTouchTracking(int interactionType) { - mMainThreadExecutor.execute(() -> { - if (TouchConsumer.isInteractionQuick(interactionType)) { - Runnable action = () -> { - Runnable onComplete = null; - if (interactionType == INTERACTION_QUICK_SCRUB) { - mQuickScrubController.onQuickScrubStart(true); - } else if (interactionType == INTERACTION_QUICK_SWITCH) { - onComplete = mQuickScrubController::onQuickSwitch; - } - mLauncher.getStateManager().goToState(OVERVIEW, true, 0, - QUICK_SWITCH_START_DURATION, onComplete); - }; - - if (mLauncher.getWorkspace().runOnOverlayHidden(action)) { - // Hide the minus one overlay so launcher can get window focus. - mLauncher.onQuickstepGestureStarted(true); + if (mInvalidated) { + return; + } + if (TouchConsumer.isInteractionQuick(interactionType)) { + Runnable action = () -> { + Runnable onComplete = null; + if (interactionType == INTERACTION_QUICK_SCRUB) { + mQuickScrubController.onQuickScrubStart(true); + } else if (interactionType == INTERACTION_QUICK_SWITCH) { + onComplete = mQuickScrubController::onQuickSwitch; } + mLauncher.getStateManager().goToState(OVERVIEW, true, 0, + QUICK_SWITCH_START_DURATION, onComplete); + }; + + if (mLauncher.getWorkspace().runOnOverlayHidden(action)) { + // Hide the minus one overlay so launcher can get window focus. + mLauncher.onQuickstepGestureStarted(true); } - }); + } } @Override public void onQuickScrubEnd() { - mMainThreadExecutor.execute(mQuickScrubController::onQuickScrubEnd); + if (mInvalidated) { + return; + } + mQuickScrubController.onQuickScrubEnd(); } @Override public void onQuickScrubProgress(float progress) { - mMainThreadExecutor.execute(() -> mQuickScrubController.onQuickScrubProgress(progress)); + if (mInvalidated) { + return; + } + mQuickScrubController.onQuickScrubProgress(progress); } } diff --git a/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java b/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java index a4c8d9634..6b1c5e199 100644 --- a/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java +++ b/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java @@ -59,7 +59,6 @@ import com.android.launcher3.allapps.AllAppsTransitionController; import com.android.launcher3.anim.AnimationSuccessListener; import com.android.launcher3.anim.AnimatorPlaybackController; import com.android.launcher3.anim.Interpolators; -import com.android.launcher3.util.Preconditions; import com.android.launcher3.util.TraceHelper; import com.android.quickstep.TouchConsumer.InteractionType; import com.android.systemui.shared.recents.model.ThumbnailData; @@ -91,6 +90,13 @@ public class WindowTransformSwipeHandler extends BaseSwipeInteractionHandler { private static final int STATE_HANDLER_INVALIDATED = 1 << 6; private static final int STATE_GESTURE_STARTED = 1 << 7; + // States for quick switch/scrub + private static final int STATE_SWITCH_TO_SCREENSHOT_COMPLETE = 1 << 8; + private static final int STATE_QUICK_SWITCH = 1 << 9; + private static final int STATE_QUICK_SCRUB_START = 1 << 10; + private static final int STATE_QUICK_SCRUB_END = 1 << 11; + + private static final int LAUNCHER_UI_STATES = STATE_LAUNCHER_PRESENT | STATE_LAUNCHER_DRAWN | STATE_ACTIVITY_MULTIPLIER_COMPLETE; @@ -103,7 +109,11 @@ public class WindowTransformSwipeHandler extends BaseSwipeInteractionHandler { "STATE_SCALED_CONTROLLER_RECENTS", "STATE_SCALED_CONTROLLER_APP", "STATE_HANDLER_INVALIDATED", - "STATE_GESTURE_STARTED" + "STATE_GESTURE_STARTED", + "STATE_SWITCH_TO_SCREENSHOT_COMPLETE", + "STATE_QUICK_SWITCH", + "STATE_QUICK_SCRUB_START", + "STATE_QUICK_SCRUB_END" }; private static final long MAX_SWIPE_DURATION = 200; @@ -162,7 +172,6 @@ public class WindowTransformSwipeHandler extends BaseSwipeInteractionHandler { private boolean mGestureStarted; private @InteractionType int mInteractionType = INTERACTION_NORMAL; - private boolean mDeferredQuickScrubEnd; private InputConsumerController mInputConsumer = InputConsumerController.getRecentsAnimationInputConsumer(); @@ -185,6 +194,7 @@ public class WindowTransformSwipeHandler extends BaseSwipeInteractionHandler { super.setState(stateFlag); } }; + mStateCallback.addCallback(STATE_LAUNCHER_DRAWN | STATE_GESTURE_STARTED, this::initializeLauncherAnimationController); mStateCallback.addCallback(STATE_LAUNCHER_PRESENT | STATE_LAUNCHER_DRAWN, @@ -195,8 +205,7 @@ public class WindowTransformSwipeHandler extends BaseSwipeInteractionHandler { mStateCallback.addCallback(STATE_SCALED_CONTROLLER_APP | STATE_APP_CONTROLLER_RECEIVED, this::resumeLastTask); mStateCallback.addCallback(STATE_SCALED_CONTROLLER_RECENTS - | STATE_ACTIVITY_MULTIPLIER_COMPLETE - | STATE_APP_CONTROLLER_RECEIVED, + | STATE_ACTIVITY_MULTIPLIER_COMPLETE | STATE_APP_CONTROLLER_RECEIVED, this::switchToScreenshot); mStateCallback.addCallback(STATE_SCALED_CONTROLLER_RECENTS @@ -211,6 +220,16 @@ public class WindowTransformSwipeHandler extends BaseSwipeInteractionHandler { mStateCallback.addCallback(STATE_HANDLER_INVALIDATED, this::invalidateHandler); mStateCallback.addCallback(STATE_LAUNCHER_PRESENT | STATE_HANDLER_INVALIDATED, this::invalidateHandlerWithLauncher); + + mStateCallback.addCallback(STATE_LAUNCHER_PRESENT | STATE_QUICK_SWITCH, + this::onQuickInteractionStart); + mStateCallback.addCallback(STATE_LAUNCHER_PRESENT | STATE_QUICK_SCRUB_START, + this::onQuickInteractionStart); + + mStateCallback.addCallback(STATE_LAUNCHER_PRESENT | STATE_SWITCH_TO_SCREENSHOT_COMPLETE + | STATE_QUICK_SWITCH, this::switchToFinalAppAfterQuickSwitch); + mStateCallback.addCallback(STATE_LAUNCHER_PRESENT | STATE_SWITCH_TO_SCREENSHOT_COMPLETE + | STATE_QUICK_SCRUB_END, this::switchToFinalAppAfterQuickScrub); } private void setStateOnUiThread(int stateFlag) { @@ -294,6 +313,7 @@ public class WindowTransformSwipeHandler extends BaseSwipeInteractionHandler { AbstractFloatingView.closeAllOpenViews(launcher, alreadyOnHome); mRecentsView = mLauncher.getOverviewPanel(); + mQuickScrubController = mRecentsView.getQuickScrubController(); mLauncherLayoutListener = new LauncherLayoutListener(mLauncher); final int state; @@ -370,7 +390,6 @@ public class WindowTransformSwipeHandler extends BaseSwipeInteractionHandler { } public void updateInteractionType(@InteractionType int interactionType) { - Preconditions.assertUIThread(); if (mInteractionType != INTERACTION_NORMAL) { throw new IllegalArgumentException( "Can't change interaction type from " + mInteractionType); @@ -381,16 +400,15 @@ public class WindowTransformSwipeHandler extends BaseSwipeInteractionHandler { } mInteractionType = interactionType; - if (mLauncher != null) { - updateUiForQuickScrub(); - } + setStateOnUiThread(interactionType == INTERACTION_QUICK_SWITCH + ? STATE_QUICK_SWITCH : STATE_QUICK_SCRUB_START); + + // Start the window animation without waiting for launcher. + animateToProgress(1f, QUICK_SWITCH_START_DURATION); } - private void updateUiForQuickScrub() { - mDeferredQuickScrubEnd = false; - mQuickScrubController = mRecentsView.getQuickScrubController(); + private void onQuickInteractionStart() { mQuickScrubController.onQuickScrubStart(false); - animateToProgress(1f, QUICK_SWITCH_START_DURATION); } @WorkerThread @@ -647,21 +665,8 @@ public class WindowTransformSwipeHandler extends BaseSwipeInteractionHandler { transaction.apply(); } } - mRecentsAnimationWrapper.finish(true /* toHome */, () -> { - if (mInteractionType == INTERACTION_QUICK_SWITCH) { - if (mQuickScrubController != null) { - mQuickScrubController.onQuickSwitch(); - } - } else if (mInteractionType == INTERACTION_QUICK_SCRUB) { - if (mQuickScrubController != null) { - if (mDeferredQuickScrubEnd) { - onQuickScrubEnd(); - } else { - mQuickScrubController.snapToPageForCurrentQuickScrubSection(); - } - } - } - }); + mRecentsAnimationWrapper.finish(true /* toHome */, + () -> setStateOnUiThread(STATE_SWITCH_TO_SCREENSHOT_COMPLETE)); } private void setupLauncherUiAfterSwipeUpAnimation() { @@ -676,19 +681,15 @@ public class WindowTransformSwipeHandler extends BaseSwipeInteractionHandler { } public void onQuickScrubEnd() { - if ((mStateCallback.getState() & STATE_SCALED_CONTROLLER_RECENTS) == 0) { - // If we are still animating into recents, then defer until that has run to end - // quick scrub since we need to finish the window animation before launching the next - // task - mDeferredQuickScrubEnd = true; - return; - } + setStateOnUiThread(STATE_QUICK_SCRUB_END); + } - if (mQuickScrubController != null) { - mQuickScrubController.onQuickScrubEnd(); - } else { - // TODO: - } + private void switchToFinalAppAfterQuickSwitch() { + mQuickScrubController.onQuickSwitch(); + } + + private void switchToFinalAppAfterQuickScrub() { + mQuickScrubController.onQuickScrubEnd(); // Normally this is handled in reset(), but since we are still scrubbing after the // transition into recents, we need to defer the handler invalidation for quick scrub until @@ -697,14 +698,16 @@ public class WindowTransformSwipeHandler extends BaseSwipeInteractionHandler { } public void onQuickScrubProgress(float progress) { - if (mQuickScrubController != null) { - mQuickScrubController.onQuickScrubProgress(progress); - } else { - // TODO: + if (Looper.myLooper() != Looper.getMainLooper() || mQuickScrubController == null) { + // TODO: We can still get progress events while launcher is not ready on the worker + // thread. Keep track of last received progress and apply that progress when launcher + // is ready + return; } + mQuickScrubController.onQuickScrubProgress(progress); } - private synchronized void debugNewState(int stateFlag) { + private void debugNewState(int stateFlag) { if (!DEBUG_STATES) { return; } |