summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSunny Goyal <sunnygoyal@google.com>2018-02-14 15:59:36 -0800
committerSunny Goyal <sunnygoyal@google.com>2018-02-16 14:00:09 -0800
commit841bbf07d0b521bcebe0ef59254e72dbaad52405 (patch)
tree3aadf4878e169534e063776d2086bc4e56dcc237
parentbd3a798aa2e326625e4a152f4d3e6cece1d892a1 (diff)
downloadandroid_packages_apps_Trebuchet-841bbf07d0b521bcebe0ef59254e72dbaad52405.tar.gz
android_packages_apps_Trebuchet-841bbf07d0b521bcebe0ef59254e72dbaad52405.tar.bz2
android_packages_apps_Trebuchet-841bbf07d0b521bcebe0ef59254e72dbaad52405.zip
Serializing all event handling from SystemUI
> EventQueue is only accessed on the binder thread > For every new touch down, we use a new event queue to prevent race conditions > All event hendling are serialized by event queue (including quick switch/scrub) > Using state handlers for quick scrub Bug: 73356768 Change-Id: Idde33a348270b8167a087129f177d5d2b54f5822
-rw-r--r--quickstep/src/com/android/quickstep/MotionEventQueue.java107
-rw-r--r--quickstep/src/com/android/quickstep/NavBarSwipeInteractionHandler.java4
-rw-r--r--quickstep/src/com/android/quickstep/OtherActivityTouchConsumer.java29
-rw-r--r--quickstep/src/com/android/quickstep/QuickScrubController.java43
-rw-r--r--quickstep/src/com/android/quickstep/RecentsAnimationWrapper.java8
-rw-r--r--quickstep/src/com/android/quickstep/RecentsView.java6
-rw-r--r--quickstep/src/com/android/quickstep/TouchConsumer.java9
-rw-r--r--quickstep/src/com/android/quickstep/TouchInteractionService.java134
-rw-r--r--quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java93
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;
}