summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSunny Goyal <sunnygoyal@google.com>2018-01-30 12:44:19 -0800
committerSunny Goyal <sunnygoyal@google.com>2018-01-30 13:42:27 -0800
commit8317b6935afeffbc3002ce5bd77b011dedc8fcce (patch)
tree7187488fcdc7b98702c5600839b3133155a1e9dc
parent1a341002fcd8b6491701f6b7a8583c6e02ee34ba (diff)
downloadandroid_packages_apps_Trebuchet-8317b6935afeffbc3002ce5bd77b011dedc8fcce.tar.gz
android_packages_apps_Trebuchet-8317b6935afeffbc3002ce5bd77b011dedc8fcce.tar.bz2
android_packages_apps_Trebuchet-8317b6935afeffbc3002ce5bd77b011dedc8fcce.zip
Using a background thread for controlling window animation
Animate the task window on the background thread, until the launcher UI is ready. After the first frame of launcher is drawn, we switch the input handling to UI thread and fade in the launcher UI. Change-Id: Ia3d04b697530af3db441b14ad34827208b923137
-rw-r--r--quickstep/src/com/android/quickstep/BaseSwipeInteractionHandler.java5
-rw-r--r--quickstep/src/com/android/quickstep/MotionEventQueue.java85
-rw-r--r--quickstep/src/com/android/quickstep/RecentsAnimationWrapper.java65
-rw-r--r--quickstep/src/com/android/quickstep/TouchInteractionService.java68
-rw-r--r--quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java175
5 files changed, 283 insertions, 115 deletions
diff --git a/quickstep/src/com/android/quickstep/BaseSwipeInteractionHandler.java b/quickstep/src/com/android/quickstep/BaseSwipeInteractionHandler.java
index 0551938c1..aa210b8ab 100644
--- a/quickstep/src/com/android/quickstep/BaseSwipeInteractionHandler.java
+++ b/quickstep/src/com/android/quickstep/BaseSwipeInteractionHandler.java
@@ -15,6 +15,8 @@
*/
package com.android.quickstep;
+import android.support.annotation.WorkerThread;
+
import com.android.launcher3.states.InternalStateHandler;
import com.android.quickstep.TouchInteractionService.InteractionType;
@@ -28,8 +30,10 @@ public abstract class BaseSwipeInteractionHandler extends InternalStateHandler {
public void reset() {}
+ @WorkerThread
public abstract void onGestureStarted();
+ @WorkerThread
public abstract void onGestureEnded(float endVelocity);
public abstract void updateInteractionType(@InteractionType int interactionType);
@@ -38,5 +42,6 @@ public abstract class BaseSwipeInteractionHandler extends InternalStateHandler {
public abstract void onQuickScrubProgress(float progress);
+ @WorkerThread
public abstract void updateDisplacement(float displacement);
}
diff --git a/quickstep/src/com/android/quickstep/MotionEventQueue.java b/quickstep/src/com/android/quickstep/MotionEventQueue.java
index e3c3a1b89..fae9b66a2 100644
--- a/quickstep/src/com/android/quickstep/MotionEventQueue.java
+++ b/quickstep/src/com/android/quickstep/MotionEventQueue.java
@@ -18,6 +18,8 @@ package com.android.quickstep;
import static android.view.MotionEvent.ACTION_CANCEL;
import static android.view.MotionEvent.ACTION_MOVE;
+import android.annotation.TargetApi;
+import android.os.Build;
import android.view.Choreographer;
import android.view.MotionEvent;
@@ -29,25 +31,64 @@ import java.util.function.Consumer;
/**
* Helper class for batching input events
*/
-public class MotionEventQueue implements Runnable {
+@TargetApi(Build.VERSION_CODES.O)
+public class MotionEventQueue {
+
+ private final EventArray mEmptyArray = new EventArray();
+ private final Object mExecutionLock = new Object();
// We use two arrays and swap the current index when one array is being consumed
private final EventArray[] mArrays = new EventArray[] {new EventArray(), new EventArray()};
private int mCurrentIndex = 0;
- private final Choreographer mChoreographer;
- private final Consumer<MotionEvent> mConsumer;
+ private final Runnable mMainFrameCallback = this::frameCallbackForMainChoreographer;
+ private final Runnable mInterimFrameCallback = this::frameCallbackForInterimChoreographer;
+
+ private final Choreographer mMainChoreographer;
+
+ private Consumer<MotionEvent> mConsumer;
+
+ private Choreographer mInterimChoreographer;
+ private Choreographer mCurrentChoreographer;
+
+ private Runnable mCurrentRunnable;
public MotionEventQueue(Choreographer choreographer, Consumer<MotionEvent> consumer) {
- mChoreographer = choreographer;
+ mMainChoreographer = choreographer;
mConsumer = consumer;
+
+ mCurrentChoreographer = mMainChoreographer;
+ mCurrentRunnable = mMainFrameCallback;
+ }
+
+ public void setConsumer(Consumer<MotionEvent> consumer) {
+ synchronized (mExecutionLock) {
+ mConsumer = consumer;
+ }
+ }
+
+ public void setInterimChoreographer(Choreographer choreographer) {
+ synchronized (mExecutionLock) {
+ synchronized (mArrays) {
+ mInterimChoreographer = choreographer;
+ if (choreographer == null) {
+ mCurrentChoreographer = mMainChoreographer;
+ mCurrentRunnable = mMainFrameCallback;
+ } else {
+ mCurrentChoreographer = mInterimChoreographer;
+ mCurrentRunnable = mInterimFrameCallback;
+ }
+
+ ChoreographerCompat.postInputFrame(mCurrentChoreographer, mCurrentRunnable);
+ }
+ }
}
public void queue(MotionEvent event) {
synchronized (mArrays) {
EventArray array = mArrays[mCurrentIndex];
if (array.isEmpty()) {
- ChoreographerCompat.postInputFrame(mChoreographer, this);
+ ChoreographerCompat.postInputFrame(mCurrentChoreographer, mCurrentRunnable);
}
int eventAction = event.getAction();
@@ -61,21 +102,33 @@ public class MotionEventQueue implements Runnable {
}
}
- @Override
- public void run() {
- EventArray array = swapAndGetCurrentArray();
- int size = array.size();
- for (int i = 0; i < size; i++) {
- MotionEvent event = array.get(i);
- mConsumer.accept(event);
- event.recycle();
+ private void frameCallbackForMainChoreographer() {
+ runFor(mMainChoreographer);
+ }
+
+ private void frameCallbackForInterimChoreographer() {
+ runFor(mInterimChoreographer);
+ }
+
+ private void runFor(Choreographer caller) {
+ synchronized (mExecutionLock) {
+ EventArray array = swapAndGetCurrentArray(caller);
+ int size = array.size();
+ for (int i = 0; i < size; i++) {
+ MotionEvent event = array.get(i);
+ mConsumer.accept(event);
+ event.recycle();
+ }
+ array.clear();
+ array.lastEventAction = ACTION_CANCEL;
}
- array.clear();
- array.lastEventAction = ACTION_CANCEL;
}
- private EventArray swapAndGetCurrentArray() {
+ private EventArray swapAndGetCurrentArray(Choreographer caller) {
synchronized (mArrays) {
+ if (caller != mCurrentChoreographer) {
+ return mEmptyArray;
+ }
EventArray current = mArrays[mCurrentIndex];
mCurrentIndex = mCurrentIndex ^ 1;
return current;
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationWrapper.java b/quickstep/src/com/android/quickstep/RecentsAnimationWrapper.java
new file mode 100644
index 000000000..7c983173f
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationWrapper.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.quickstep;
+
+import com.android.systemui.shared.system.BackgroundExecutor;
+import com.android.systemui.shared.system.RecentsAnimationControllerCompat;
+import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
+
+/**
+ * Wrapper around RecentsAnimationController to help with some synchronization
+ */
+public class RecentsAnimationWrapper {
+
+ public RecentsAnimationControllerCompat controller;
+ public RemoteAnimationTargetCompat[] targets;
+
+ private boolean mInputConsumerEnabled;
+
+ public synchronized void setController(
+ RecentsAnimationControllerCompat controller, RemoteAnimationTargetCompat[] targets) {
+ this.controller = controller;
+ this.targets = targets;
+
+ if (mInputConsumerEnabled) {
+ enableInputConsumer();
+ }
+ }
+
+ public void finish(boolean toHome) {
+ BackgroundExecutor.get().submit(() -> {
+ synchronized (this) {
+ if (controller != null) {
+ controller.setInputConsumerEnabled(false);
+ controller.finish(toHome);
+ }
+ }
+ });
+ }
+
+ public void enableInputConsumer() {
+ mInputConsumerEnabled = true;
+ if (mInputConsumerEnabled) {
+ BackgroundExecutor.get().submit(() -> {
+ synchronized (this) {
+ if (controller != null) {
+ controller.setInputConsumerEnabled(true);
+ }
+ }
+ });
+ }
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java
index c0b12f78b..a760b7504 100644
--- a/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -40,6 +40,8 @@ import android.graphics.PointF;
import android.graphics.Rect;
import android.os.Build;
import android.os.Bundle;
+import android.os.Handler;
+import android.os.HandlerThread;
import android.os.IBinder;
import android.support.annotation.IntDef;
import android.util.Log;
@@ -92,11 +94,16 @@ public class TouchInteractionService extends Service {
public static final int INTERACTION_QUICK_SWITCH = 1;
public static final int INTERACTION_QUICK_SCRUB = 2;
+ /**
+ * A background thread used for handling UI for another window.
+ */
+ private static HandlerThread sRemoteUiThread;
+
private final IBinder mMyBinder = new IOverviewProxy.Stub() {
@Override
public void onMotionEvent(MotionEvent ev) {
- mEventQueue.queue(ev);
+ onBinderMotionEvent(ev);
}
@Override
@@ -166,7 +173,8 @@ public class TouchInteractionService extends Service {
private Rect mStableInsets = new Rect();
private ISystemUiProxy mISystemUiProxy;
- private Consumer<MotionEvent> mCurrentConsumer = mNoOpTouchConsumer;
+
+ private Choreographer mBackgroundThreadChoreographer;
@Override
public void onCreate() {
@@ -184,8 +192,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(), this::handleMotionEvent);
+ mEventQueue = new MotionEventQueue(Choreographer.getInstance(), mNoOpTouchConsumer);
sConnected = true;
+
+ initBackgroundChoreographer();
}
@Override
@@ -201,19 +211,23 @@ public class TouchInteractionService extends Service {
return mMyBinder;
}
- private void handleMotionEvent(MotionEvent ev) {
+ private void onBinderMotionEvent(MotionEvent ev) {
if (ev.getActionMasked() == ACTION_DOWN) {
mRunningTask = mAM.getRunningTask();
if (mRunningTask == null) {
- mCurrentConsumer = mNoOpTouchConsumer;
+ mEventQueue.setConsumer(mNoOpTouchConsumer);
+ mEventQueue.setInterimChoreographer(null);
} else if (mRunningTask.topActivity.equals(mLauncher)) {
- mCurrentConsumer = getLauncherConsumer();
+ mEventQueue.setConsumer(getLauncherConsumer());
+ mEventQueue.setInterimChoreographer(null);
} else {
- mCurrentConsumer = mOtherActivityTouchConsumer;
+ mEventQueue.setConsumer(mOtherActivityTouchConsumer);
+ mEventQueue.setInterimChoreographer(
+ isUsingScreenShot() ? null : mBackgroundThreadChoreographer);
}
}
- mCurrentConsumer.accept(ev);
+ mEventQueue.queue(ev);
}
private void handleTouchDownOnOtherActivity(MotionEvent ev) {
@@ -235,7 +249,8 @@ public class TouchInteractionService extends Service {
}
mVelocityTracker.addMovement(ev);
if (mInteractionHandler != null) {
- mInteractionHandler.reset();
+ final BaseSwipeInteractionHandler handler = mInteractionHandler;
+ mMainThreadExecutor.execute(handler::reset);
mInteractionHandler = null;
}
mTouchThresholdCrossed = false;
@@ -298,7 +313,7 @@ public class TouchInteractionService extends Service {
TraceHelper.endSection("TouchInt");
finishTouchTracking();
- mCurrentConsumer = mNoOpTouchConsumer;
+ mEventQueue.setConsumer(mNoOpTouchConsumer);
break;
}
}
@@ -312,11 +327,15 @@ public class TouchInteractionService extends Service {
return mDisplayRotation == Surface.ROTATION_270 && mStableInsets.left > 0;
}
+ private boolean isUsingScreenShot() {
+ return Utilities.getPrefs(this).getBoolean("pref_use_screenshot_animation", true);
+ }
+
/**
* Called when the gesture has started.
*/
private void startTouchTracking() {
- if (Utilities.getPrefs(this).getBoolean("pref_use_screenshot_animation", true)) {
+ if (isUsingScreenShot()) {
// Create the shared handler
final NavBarSwipeInteractionHandler handler =
new NavBarSwipeInteractionHandler(mRunningTask, this, INTERACTION_NORMAL);
@@ -343,7 +362,6 @@ public class TouchInteractionService extends Service {
// Create the shared handler
final WindowTransformSwipeHandler handler =
new WindowTransformSwipeHandler(mRunningTask, this);
-
BackgroundExecutor.get().submit(() -> {
ActivityManagerWrapper.getInstance().startRecentsActivity(mHomeIntent,
new AssistDataReceiver() {
@@ -375,8 +393,17 @@ public class TouchInteractionService extends Service {
// Preload the plan
mRecentsModel.loadTasks(mRunningTask.id, null);
mInteractionHandler = handler;
- mInteractionHandler.initWhenReady();
- mInteractionHandler.setGestureEndCallback(() -> mInteractionHandler = null);
+ handler.setGestureEndCallback(() -> {
+ if (handler == mInteractionHandler) {
+ mInteractionHandler = null;
+ }
+ });
+ handler.setLauncherOnDrawCallback(() -> {
+ if (handler == mInteractionHandler) {
+ mEventQueue.setInterimChoreographer(null);
+ }
+ });
+ mMainThreadExecutor.execute(handler::initWhenReady);
}
}
@@ -468,7 +495,7 @@ public class TouchInteractionService extends Service {
case ACTION_POINTER_UP:
case ACTION_POINTER_DOWN:
if (!mTrackingStarted) {
- mCurrentConsumer = mNoOpTouchConsumer;
+ mEventQueue.setConsumer(mNoOpTouchConsumer);
}
break;
case ACTION_MOVE: {
@@ -492,7 +519,7 @@ public class TouchInteractionService extends Service {
}
if (action == ACTION_UP || action == ACTION_CANCEL) {
- mCurrentConsumer = mNoOpTouchConsumer;
+ mEventQueue.setConsumer(mNoOpTouchConsumer);
}
}
@@ -506,6 +533,15 @@ public class TouchInteractionService extends Service {
}
}
+ private void initBackgroundChoreographer() {
+ if (sRemoteUiThread == null) {
+ sRemoteUiThread = new HandlerThread("remote-ui");
+ sRemoteUiThread.start();
+ }
+ new Handler(sRemoteUiThread.getLooper()).post(() ->
+ mBackgroundThreadChoreographer = Choreographer.getInstance());
+ }
+
public static boolean isInteractionQuick(@InteractionType int interactionType) {
return interactionType == INTERACTION_QUICK_SCRUB ||
interactionType == INTERACTION_QUICK_SWITCH;
diff --git a/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java b/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java
index e9b22a25e..16b34f99f 100644
--- a/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java
+++ b/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java
@@ -37,28 +37,31 @@ import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Rect;
import android.os.Build;
+import android.os.Looper;
import android.os.UserHandle;
import android.support.annotation.UiThread;
+import android.support.annotation.WorkerThread;
import android.view.View;
+import android.view.ViewTreeObserver.OnDrawListener;
import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Hotseat;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherAppState;
+import com.android.launcher3.MainThreadExecutor;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
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.states.InternalStateHandler;
import com.android.launcher3.util.Preconditions;
+import com.android.launcher3.util.TraceHelper;
import com.android.quickstep.TouchInteractionService.InteractionType;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.recents.model.Task.TaskKey;
import com.android.systemui.shared.recents.model.ThumbnailData;
-import com.android.systemui.shared.system.BackgroundExecutor;
import com.android.systemui.shared.system.InputConsumerController;
import com.android.systemui.shared.system.RecentsAnimationControllerCompat;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
@@ -70,17 +73,18 @@ public class WindowTransformSwipeHandler extends BaseSwipeInteractionHandler {
// Launcher UI related states
private static final int STATE_LAUNCHER_READY = 1 << 0;
- private static final int STATE_ACTIVITY_MULTIPLIER_COMPLETE = 1 << 1;
+ private static final int STATE_LAUNCHER_DRAWN = 1 << 1;
+ private static final int STATE_ACTIVITY_MULTIPLIER_COMPLETE = 1 << 2;
// Internal initialization states
- private static final int STATE_APP_CONTROLLER_RECEIVED = 1 << 2;
+ private static final int STATE_APP_CONTROLLER_RECEIVED = 1 << 3;
// Interaction finish states
- private static final int STATE_SCALED_SNAPSHOT_RECENTS = 1 << 3;
- private static final int STATE_SCALED_SNAPSHOT_APP = 1 << 4;
+ private static final int STATE_SCALED_SNAPSHOT_RECENTS = 1 << 4;
+ private static final int STATE_SCALED_SNAPSHOT_APP = 1 << 5;
private static final int LAUNCHER_UI_STATES =
- STATE_LAUNCHER_READY | STATE_ACTIVITY_MULTIPLIER_COMPLETE;
+ STATE_LAUNCHER_READY | STATE_LAUNCHER_DRAWN | STATE_ACTIVITY_MULTIPLIER_COMPLETE;
private static final long MAX_SWIPE_DURATION = 200;
private static final long MIN_SWIPE_DURATION = 80;
@@ -115,6 +119,8 @@ public class WindowTransformSwipeHandler extends BaseSwipeInteractionHandler {
private RecentsView mRecentsView;
private QuickScrubController mQuickScrubController;
+ private Runnable mLauncherDrawnCallback;
+
private boolean mWasLauncherAlreadyVisible;
private float mCurrentDisplacement;
@@ -122,16 +128,14 @@ public class WindowTransformSwipeHandler extends BaseSwipeInteractionHandler {
private @InteractionType int mInteractionType = INTERACTION_NORMAL;
private boolean mStartedQuickScrubFromHome;
- private RecentsAnimationControllerCompat mRecentsAnimationController;
- private RemoteAnimationTargetCompat[] mRecentsAnimationApps;
- private boolean mRecentsAnimationInputConsumerEnabled;
+ private final RecentsAnimationWrapper mRecentsAnimationWrapper = new RecentsAnimationWrapper();
private Matrix mTmpMatrix = new Matrix();
private final InputConsumerController mInputConsumerController;
private final InputConsumerController.TouchListener mInputConsumerTouchListener =
(ev) -> {
if (ev.getActionMasked() == ACTION_UP) {
- onGestureInterruptEnd();
+ // TODO: Handle touch event while the transition is in progress.
}
return true;
};
@@ -144,7 +148,6 @@ public class WindowTransformSwipeHandler extends BaseSwipeInteractionHandler {
mContext = context;
mInputConsumerController = InputConsumerController.getRecentsAnimationInputConsumer();
-
WindowManagerWrapper.getInstance().getStableInsets(mStableInsets);
DeviceProfile dp = LauncherAppState.getIDP(mContext).getDeviceProfile(mContext);
@@ -173,6 +176,15 @@ public class WindowTransformSwipeHandler extends BaseSwipeInteractionHandler {
this::reset);
mStateCallback.addCallback(STATE_LAUNCHER_READY | STATE_SCALED_SNAPSHOT_RECENTS,
this::reset);
+
+ mStateCallback.addCallback(STATE_LAUNCHER_READY | STATE_LAUNCHER_DRAWN,
+ mLauncherDrawnCallback);
+ }
+
+ public void setLauncherOnDrawCallback(Runnable callback) {
+ mLauncherDrawnCallback = callback;
+ mStateCallback.addCallback(STATE_LAUNCHER_READY | STATE_LAUNCHER_DRAWN,
+ mLauncherDrawnCallback);
}
private void initTransitionEndpoints(DeviceProfile dp) {
@@ -220,17 +232,35 @@ public class WindowTransformSwipeHandler extends BaseSwipeInteractionHandler {
.createAnimationToNewWorkspace(OVERVIEW, accuracy);
mLauncherTransitionController.setPlayFraction(mCurrentShift.value);
- mStateCallback.setState(STATE_ACTIVITY_MULTIPLIER_COMPLETE);
+ mStateCallback.setState(STATE_ACTIVITY_MULTIPLIER_COMPLETE | STATE_LAUNCHER_DRAWN);
} else {
+ TraceHelper.beginSection("WTS-init");
launcher.getStateManager().goToState(OVERVIEW, false);
+ TraceHelper.partitionSection("WTS-init", "State changed");
// TODO: Implement a better animation for fading in
View rootView = launcher.getRootView();
rootView.setAlpha(0);
- rootView.animate().alpha(1)
- .setDuration(getFadeInDuration())
- .withEndAction(() -> mStateCallback.setState(
- launcher == mLauncher ? STATE_ACTIVITY_MULTIPLIER_COMPLETE : 0));
+ rootView.getViewTreeObserver().addOnDrawListener(new OnDrawListener() {
+
+ @Override
+ public void onDraw() {
+ TraceHelper.endSection("WTS-init", "Launcher frame is drawn");
+ rootView.post(() ->
+ rootView.getViewTreeObserver().removeOnDrawListener(this));
+ if (launcher != mLauncher) {
+ return;
+ }
+
+ if ((mStateCallback.getState() & STATE_LAUNCHER_DRAWN) == 0) {
+ mStateCallback.setState(STATE_LAUNCHER_DRAWN);
+ rootView.animate().alpha(1)
+ .setDuration(getFadeInDuration())
+ .withEndAction(() -> mStateCallback.setState(launcher == mLauncher
+ ? STATE_ACTIVITY_MULTIPLIER_COMPLETE : 0));
+ }
+ }
+ });
}
mRecentsView = mLauncher.getOverviewPanel();
@@ -334,48 +364,49 @@ public class WindowTransformSwipeHandler extends BaseSwipeInteractionHandler {
updateDisplacement(mCurrentDisplacement);
}
- @UiThread
+ @WorkerThread
private void updateFinalShift() {
if (mStartedQuickScrubFromHome) {
return;
}
float shift = mCurrentShift.value;
- mRectEvaluator.evaluate(shift, mSourceRect, mTargetRect);
- float scale = (float) mCurrentRect.width() / mSourceRect.width();
- if (mRecentsAnimationApps != null) {
- mClipRect.left = mSourceRect.left;
- mClipRect.top = (int) (mStableInsets.top * shift);
- mClipRect.bottom = (int) (mDp.heightPx - (mStableInsets.bottom * shift));
- mClipRect.right = mSourceRect.right;
-
- mTmpMatrix.setScale(scale, scale, 0, 0);
- mTmpMatrix.postTranslate(mCurrentRect.left - mStableInsets.left * scale * shift,
- mCurrentRect.top - mStableInsets.top * scale * shift);
- TransactionCompat transaction = new TransactionCompat();
- for (RemoteAnimationTargetCompat app : mRecentsAnimationApps) {
- if (app.mode == MODE_CLOSING) {
- transaction.setMatrix(app.leash, mTmpMatrix)
- .setWindowCrop(app.leash, mClipRect)
- .show(app.leash);
+
+ synchronized (mRecentsAnimationWrapper) {
+ if (mRecentsAnimationWrapper.controller != null) {
+ mRectEvaluator.evaluate(shift, mSourceRect, mTargetRect);
+ float scale = (float) mCurrentRect.width() / mSourceRect.width();
+
+ mClipRect.left = mSourceRect.left;
+ mClipRect.top = (int) (mStableInsets.top * shift);
+ mClipRect.bottom = (int) (mDp.heightPx - (mStableInsets.bottom * shift));
+ mClipRect.right = mSourceRect.right;
+
+ mTmpMatrix.setScale(scale, scale, 0, 0);
+ mTmpMatrix.postTranslate(mCurrentRect.left - mStableInsets.left * scale * shift,
+ mCurrentRect.top - mStableInsets.top * scale * shift);
+ TransactionCompat transaction = new TransactionCompat();
+ for (RemoteAnimationTargetCompat app : mRecentsAnimationWrapper.targets) {
+ if (app.mode == MODE_CLOSING) {
+ transaction.setMatrix(app.leash, mTmpMatrix)
+ .setWindowCrop(app.leash, mClipRect)
+ .show(app.leash);
+ }
}
+ transaction.apply();
}
- transaction.apply();
}
- if (mLauncherTransitionController != null) {
- mLauncherTransitionController.setPlayFraction(shift);
+ if (Looper.getMainLooper() == Looper.myLooper()) {
+ if (mLauncherTransitionController != null) {
+ mLauncherTransitionController.setPlayFraction(shift);
+ }
}
}
public void setRecentsAnimation(RecentsAnimationControllerCompat controller,
RemoteAnimationTargetCompat[] apps) {
- mRecentsAnimationController = controller;
- if (mRecentsAnimationInputConsumerEnabled) {
- BackgroundExecutor.get().submit(() ->
- mRecentsAnimationController.setInputConsumerEnabled(true));
- }
- mRecentsAnimationApps = apps;
+ mRecentsAnimationWrapper.setController(controller, apps);
mStateCallback.setState(STATE_APP_CONTROLLER_RECEIVED);
}
@@ -384,12 +415,7 @@ public class WindowTransformSwipeHandler extends BaseSwipeInteractionHandler {
mInputConsumerController.registerInputConsumer();
mInputConsumerController.setTouchListener(mInputConsumerTouchListener);
- if (mRecentsAnimationController != null) {
- BackgroundExecutor.get().submit(() ->
- mRecentsAnimationController.setInputConsumerEnabled(true));
- } else {
- mRecentsAnimationInputConsumerEnabled = true;
- }
+ mRecentsAnimationWrapper.enableInputConsumer();
}
@UiThread
@@ -415,18 +441,6 @@ public class WindowTransformSwipeHandler extends BaseSwipeInteractionHandler {
}
}
- if (endShift == mCurrentShift.value) {
- mStateCallback.setState((Float.compare(mCurrentShift.value, 0) == 0)
- ? STATE_SCALED_SNAPSHOT_APP : STATE_SCALED_SNAPSHOT_RECENTS);
- } else {
- animateToProgress(endShift, duration);
- }
- }
-
- @UiThread
- public void onGestureInterruptEnd() {
- final float endShift = 0;
- final long duration = MAX_SWIPE_DURATION;
animateToProgress(endShift, duration);
}
@@ -437,8 +451,9 @@ public class WindowTransformSwipeHandler extends BaseSwipeInteractionHandler {
anim.addListener(new AnimationSuccessListener() {
@Override
public void onAnimationSuccess(Animator animator) {
- mStateCallback.setState((Float.compare(mCurrentShift.value, 0) == 0)
- ? STATE_SCALED_SNAPSHOT_APP : STATE_SCALED_SNAPSHOT_RECENTS);
+ new MainThreadExecutor().execute(() -> mStateCallback.setState(
+ (Float.compare(mCurrentShift.value, 0) == 0)
+ ? STATE_SCALED_SNAPSHOT_APP : STATE_SCALED_SNAPSHOT_RECENTS));
}
});
anim.start();
@@ -446,12 +461,7 @@ public class WindowTransformSwipeHandler extends BaseSwipeInteractionHandler {
@UiThread
private void resumeLastTask() {
- if (mRecentsAnimationController != null) {
- BackgroundExecutor.get().submit(() -> {
- mRecentsAnimationController.setInputConsumerEnabled(false);
- mRecentsAnimationController.finish(false /* toHome */);
- });
- }
+ mRecentsAnimationWrapper.finish(false /* toHome */);
}
public void reset() {
@@ -497,22 +507,21 @@ public class WindowTransformSwipeHandler extends BaseSwipeInteractionHandler {
mQuickScrubController.snapToPageForCurrentQuickScrubSection();
}
} else {
- if (mRecentsAnimationController != null) {
- TransactionCompat transaction = new TransactionCompat();
- for (RemoteAnimationTargetCompat app : mRecentsAnimationApps) {
- if (app.mode == MODE_CLOSING) {
- // Update the screenshot of the task
- final ThumbnailData thumbnail =
- mRecentsAnimationController.screenshotTask(app.taskId);
- mRecentsView.updateThumbnail(app.taskId, thumbnail);
+ synchronized (mRecentsAnimationWrapper) {
+ if (mRecentsAnimationWrapper.controller != null) {
+ TransactionCompat transaction = new TransactionCompat();
+ for (RemoteAnimationTargetCompat app : mRecentsAnimationWrapper.targets) {
+ if (app.mode == MODE_CLOSING) {
+ // Update the screenshot of the task
+ final ThumbnailData thumbnail =
+ mRecentsAnimationWrapper.controller.screenshotTask(app.taskId);
+ mRecentsView.updateThumbnail(app.taskId, thumbnail);
+ }
}
+ transaction.apply();
}
- transaction.apply();
- BackgroundExecutor.get().submit(() -> {
- mRecentsAnimationController.setInputConsumerEnabled(false);
- mRecentsAnimationController.finish(true /* toHome */);
- });
}
+ mRecentsAnimationWrapper.finish(true /* toHome */);
}
}