6/ Update recents animation classes to have their respective responsibilities

- RecentsAnimationTargets: manages information about the targets only
  RecentsAnimationCallbacks: manages callbacks from WM about the animation
  RecentsAnimationWrapper: manages calls into WM to update the animation
                           (to be renamed accordingly in a follow up CL)
- Create the Callbacks as a part of starting the recents animation, and
  have the callbacks create the controller wrapper and the targets, which
  are both notified to the listeners through the callbacks.
- Instead of passing through a callback for recents animation finished,
  have it be a part of the recents animation callbacks.

Bug: 141886704

Change-Id: I4ff26a175654e82efe059fa74d1f310e93961dc9
This commit is contained in:
Winson Chung
2019-10-02 11:54:14 -07:00
parent bfcee430fe
commit 9e876a34ee
12 changed files with 311 additions and 271 deletions
@@ -64,15 +64,16 @@ import com.android.quickstep.util.ActivityInitListener;
import com.android.quickstep.util.AppWindowAnimationHelper;
import com.android.quickstep.util.AppWindowAnimationHelper.TransformParams;
import com.android.quickstep.util.RectFSpringAnim;
import com.android.quickstep.util.RemoteAnimationTargets;
import com.android.quickstep.util.RecentsAnimationTargets;
import com.android.quickstep.util.RecentsAnimationCallbacks.RecentsAnimationListener;
import com.android.quickstep.views.RecentsView;
import com.android.quickstep.views.TaskView;
import com.android.systemui.shared.recents.model.ThumbnailData;
import com.android.systemui.shared.system.InputConsumerController;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat;
import java.util.ArrayList;
import java.util.function.Consumer;
/**
@@ -115,7 +116,13 @@ public abstract class BaseSwipeUpHandler<T extends BaseDraggingActivity, Q exten
protected final AnimatedFloat mCurrentShift = new AnimatedFloat(this::updateFinalShift);
protected final ActivityInitListener mActivityInitListener;
protected final RecentsAnimationWrapper mRecentsAnimationWrapper;
protected final InputConsumerController mInputConsumer;
protected RecentsAnimationWrapper mRecentsAnimationWrapper;
protected RecentsAnimationTargets mRecentsAnimationTargets;
// Callbacks to be made once the recents animation starts
private final ArrayList<Runnable> mRecentsAnimationStartCallbacks = new ArrayList<>();
protected T mActivity;
protected Q mRecentsView;
@@ -140,8 +147,7 @@ public abstract class BaseSwipeUpHandler<T extends BaseDraggingActivity, Q exten
mActivityInitListener =
mActivityControlHelper.createActivityInitListener(this::onActivityInit);
mRunningTaskId = runningTaskId;
mRecentsAnimationWrapper = new RecentsAnimationWrapper(inputConsumer,
this::createNewInputProxyHandler);
mInputConsumer = inputConsumer;
mMode = SysUINavigationMode.getMode(context);
mAppWindowAnimationHelper = new AppWindowAnimationHelper(context);
@@ -210,8 +216,8 @@ public abstract class BaseSwipeUpHandler<T extends BaseDraggingActivity, Q exten
protected void linkRecentsViewScroll() {
SyncRtSurfaceTransactionApplierCompat.create(mRecentsView, applier -> {
mTransformParams.setSyncTransactionApplier(applier);
mRecentsAnimationWrapper.runOnInit(() ->
mRecentsAnimationWrapper.targetSet.addDependentTransactionApplier(applier));
runOnRecentsAnimationStart(() ->
mRecentsAnimationTargets.addDependentTransactionApplier(applier));
});
mRecentsView.setOnScrollChangeListener((v, scrollX, scrollY, oldScrollX, oldScrollY) -> {
@@ -219,8 +225,10 @@ public abstract class BaseSwipeUpHandler<T extends BaseDraggingActivity, Q exten
updateFinalShift();
}
});
mRecentsView.setRecentsAnimationWrapper(mRecentsAnimationWrapper);
mRecentsView.setAppWindowAnimationHelper(mAppWindowAnimationHelper);
runOnRecentsAnimationStart(() ->
mRecentsView.setRecentsAnimationTargets(mRecentsAnimationWrapper,
mRecentsAnimationTargets));
}
protected void startNewTask(int successStateFlag, Consumer<Boolean> resultCallback) {
@@ -256,8 +264,30 @@ public abstract class BaseSwipeUpHandler<T extends BaseDraggingActivity, Q exten
ActiveGestureLog.INSTANCE.addLog("finishRecentsAnimation", true);
}
/**
* Runs the given {@param action} if the recents animation has already started, or queues it to
* be run when it is next started.
*/
protected void runOnRecentsAnimationStart(Runnable action) {
if (mRecentsAnimationTargets == null) {
mRecentsAnimationStartCallbacks.add(action);
} else {
action.run();
}
}
/**
* @return whether the recents animation has started and there are valid app targets.
*/
protected boolean hasTargets() {
return mRecentsAnimationTargets != null && mRecentsAnimationTargets.hasTargets();
}
@Override
public void onRecentsAnimationStart(RecentsAnimationTargets targetSet) {
public void onRecentsAnimationStart(RecentsAnimationWrapper recentsAnimationController,
RecentsAnimationTargets targetSet) {
mRecentsAnimationWrapper = recentsAnimationController;
mRecentsAnimationTargets = targetSet;
DeviceProfile dp = InvariantDeviceProfile.INSTANCE.get(mContext).getDeviceProfile(mContext);
final Rect overviewStackBounds;
RemoteAnimationTargetCompat runningTaskTarget = targetSet.findTask(mRunningTaskId);
@@ -281,7 +311,25 @@ public abstract class BaseSwipeUpHandler<T extends BaseDraggingActivity, Q exten
mAppWindowAnimationHelper.prepareAnimation(dp, false /* isOpening */);
initTransitionEndpoints(dp);
mRecentsAnimationWrapper.setController(targetSet);
// Notify when the animation starts
if (!mRecentsAnimationStartCallbacks.isEmpty()) {
for (Runnable action : new ArrayList<>(mRecentsAnimationStartCallbacks)) {
action.run();
}
mRecentsAnimationStartCallbacks.clear();
}
}
@Override
public void onRecentsAnimationCanceled(ThumbnailData thumbnailData) {
mRecentsAnimationWrapper = null;
mRecentsAnimationTargets = null;
}
@Override
public void onRecentsAnimationFinished(RecentsAnimationWrapper controller) {
mRecentsAnimationWrapper = null;
mRecentsAnimationTargets = null;
}
private Rect getStackBounds(DeviceProfile dp) {
@@ -370,7 +418,7 @@ public abstract class BaseSwipeUpHandler<T extends BaseDraggingActivity, Q exten
mTransformParams.setProgress(shift)
.setOffsetX(offsetX)
.setOffsetScale(offsetScale)
.setTargetSet(mRecentsAnimationWrapper.targetSet)
.setTargetSet(mRecentsAnimationTargets)
.setLauncherOnTop(true);
mAppWindowAnimationHelper.applyTransform(mTransformParams);
}
@@ -388,11 +436,10 @@ public abstract class BaseSwipeUpHandler<T extends BaseDraggingActivity, Q exten
*/
protected RectFSpringAnim createWindowAnimationToHome(float startProgress,
HomeAnimationFactory homeAnimationFactory) {
final RemoteAnimationTargets targetSet = mRecentsAnimationWrapper.targetSet;
final RectF startRect = new RectF(
mAppWindowAnimationHelper.applyTransform(
mTransformParams.setProgress(startProgress)
.setTargetSet(targetSet)
.setTargetSet(mRecentsAnimationTargets)
.setLauncherOnTop(false)));
final RectF targetRect = homeAnimationFactory.getWindowTargetRect();
@@ -18,6 +18,8 @@ package com.android.quickstep;
import static android.view.MotionEvent.ACTION_CANCEL;
import static android.view.MotionEvent.ACTION_DOWN;
import static android.view.MotionEvent.ACTION_UP;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
import android.os.SystemClock;
import android.util.Log;
@@ -29,10 +31,14 @@ import androidx.annotation.UiThread;
import com.android.launcher3.util.Preconditions;
import com.android.quickstep.inputconsumers.InputConsumer;
import com.android.quickstep.util.RecentsAnimationCallbacks;
import com.android.quickstep.util.RecentsAnimationTargets;
import com.android.systemui.shared.recents.model.ThumbnailData;
import com.android.systemui.shared.system.InputConsumerController;
import java.util.ArrayList;
import com.android.systemui.shared.system.RecentsAnimationControllerCompat;
import java.util.function.Consumer;
import java.util.function.Supplier;
/**
@@ -42,56 +48,82 @@ public class RecentsAnimationWrapper {
private static final String TAG = "RecentsAnimationWrapper";
// A list of callbacks to run when we receive the recents animation target. There are different
// than the state callbacks as these run on the current worker thread.
private final ArrayList<Runnable> mCallbacks = new ArrayList<>();
public RecentsAnimationTargets targetSet;
private final RecentsAnimationControllerCompat mController;
private final Consumer<RecentsAnimationWrapper> mOnFinishedListener;
private final boolean mShouldMinimizeSplitScreen;
private boolean mWindowThresholdCrossed = false;
private final InputConsumerController mInputConsumerController;
private final Supplier<InputConsumer> mInputProxySupplier;
private InputConsumerController mInputConsumerController;
private Supplier<InputConsumer> mInputProxySupplier;
private InputConsumer mInputConsumer;
private boolean mTouchInProgress;
private boolean mFinishPending;
public RecentsAnimationWrapper(InputConsumerController inputConsumerController,
Supplier<InputConsumer> inputProxySupplier) {
mInputConsumerController = inputConsumerController;
mInputProxySupplier = inputProxySupplier;
public RecentsAnimationWrapper(RecentsAnimationControllerCompat controller,
boolean shouldMinimizeSplitScreen,
Consumer<RecentsAnimationWrapper> onFinishedListener) {
mController = controller;
mOnFinishedListener = onFinishedListener;
mShouldMinimizeSplitScreen = shouldMinimizeSplitScreen;
setWindowThresholdCrossed(mWindowThresholdCrossed);
}
public boolean hasTargets() {
return targetSet != null && targetSet.hasTargets();
/**
* Synchronously takes a screenshot of the task with the given {@param taskId} if the task is
* currently being animated.
*/
public ThumbnailData screenshotTask(int taskId) {
return mController != null ? mController.screenshotTask(taskId) : null;
}
/**
* Indicates that the gesture has crossed the window boundary threshold and system UI can be
* update the represent the window behind
*/
public void setWindowThresholdCrossed(boolean windowThresholdCrossed) {
if (mWindowThresholdCrossed != windowThresholdCrossed) {
mWindowThresholdCrossed = windowThresholdCrossed;
UI_HELPER_EXECUTOR.execute(() -> {
mController.setAnimationTargetsBehindSystemBars(!windowThresholdCrossed);
if (mShouldMinimizeSplitScreen && windowThresholdCrossed) {
// NOTE: As a workaround for conflicting animations (Launcher animating the task
// leash, and SystemUI resizing the docked stack, which resizes the task), we
// currently only set the minimized mode, and not the inverse.
// TODO: Synchronize the minimize animation with the launcher animation
mController.setSplitScreenMinimized(windowThresholdCrossed);
}
});
}
}
/**
* Notifies the controller that we want to defer cancel until the next app transition starts.
* If {@param screenshot} is set, then we will receive a screenshot on the next
* {@link RecentsAnimationCallbacks#onAnimationCanceled(ThumbnailData)} and we must also call
* {@link #cleanupScreenshot()} when that screenshot is no longer used.
*/
public void setDeferCancelUntilNextTransition(boolean defer, boolean screenshot) {
mController.setDeferCancelUntilNextTransition(defer, screenshot);
}
/**
* Cleans up the screenshot previously returned from
* {@link RecentsAnimationCallbacks#onAnimationCanceled(ThumbnailData)}.
*/
public void cleanupScreenshot() {
UI_HELPER_EXECUTOR.execute(() -> mController.cleanupScreenshot());
}
@UiThread
public synchronized void setController(RecentsAnimationTargets targetSet) {
Preconditions.assertUIThread();
this.targetSet = targetSet;
if (targetSet == null) {
return;
}
targetSet.setWindowThresholdCrossed(mWindowThresholdCrossed);
if (!mCallbacks.isEmpty()) {
for (Runnable action : new ArrayList<>(mCallbacks)) {
action.run();
}
mCallbacks.clear();
}
public void finishAnimationToHome() {
finishAndClear(true /* toRecents */, null, false /* sendUserLeaveHint */);
}
public synchronized void runOnInit(Runnable action) {
if (targetSet == null) {
mCallbacks.add(action);
} else {
action.run();
}
@UiThread
public void finishAnimationToApp() {
finishAndClear(false /* toRecents */, null, false /* sendUserLeaveHint */);
}
/** See {@link #finish(boolean, Runnable, boolean)} */
@@ -127,34 +159,36 @@ public class RecentsAnimationWrapper {
private void finishAndClear(boolean toRecents, Runnable onFinishComplete,
boolean sendUserLeaveHint) {
RecentsAnimationTargets controller = targetSet;
targetSet = null;
disableInputProxy();
if (controller != null) {
controller.finishController(toRecents, onFinishComplete, sendUserLeaveHint);
}
finishController(toRecents, onFinishComplete, sendUserLeaveHint);
}
public void enableInputConsumer() {
if (targetSet != null) {
targetSet.enableInputConsumer();
}
@UiThread
public void finishController(boolean toRecents, Runnable callback, boolean sendUserLeaveHint) {
mOnFinishedListener.accept(this);
UI_HELPER_EXECUTOR.execute(() -> {
mController.setInputConsumerEnabled(false);
mController.finish(toRecents, sendUserLeaveHint);
if (callback != null) {
MAIN_EXECUTOR.execute(callback);
}
});
}
/**
* Indicates that the gesture has crossed the window boundary threshold and system UI can be
* update the represent the window behind
* Enables the input consumer to start intercepting touches in the app window.
*/
public void setWindowThresholdCrossed(boolean windowThresholdCrossed) {
if (mWindowThresholdCrossed != windowThresholdCrossed) {
mWindowThresholdCrossed = windowThresholdCrossed;
if (targetSet != null) {
targetSet.setWindowThresholdCrossed(windowThresholdCrossed);
}
}
public void enableInputConsumer() {
UI_HELPER_EXECUTOR.submit(() -> {
mController.hideCurrentInputMethod();
mController.setInputConsumerEnabled(true);
});
}
public void enableInputProxy() {
public void enableInputProxy(InputConsumerController inputConsumerController,
Supplier<InputConsumer> inputProxySupplier) {
mInputProxySupplier = inputProxySupplier;
mInputConsumerController = inputConsumerController;
mInputConsumerController.setInputListener(this::onInputConsumerEvent);
}
@@ -165,7 +199,9 @@ public class RecentsAnimationWrapper {
mInputConsumer.onMotionEvent(dummyCancel);
dummyCancel.recycle();
}
mInputConsumerController.setInputListener(null);
if (mInputConsumerController != null) {
mInputConsumerController.setInputListener(null);
}
}
private boolean onInputConsumerEvent(InputEvent ev) {
@@ -214,14 +250,4 @@ public class RecentsAnimationWrapper {
return true;
}
public void setDeferCancelUntilNextTransition(boolean defer, boolean screenshot) {
if (targetSet != null) {
targetSet.controller.setDeferCancelUntilNextTransition(defer, screenshot);
}
}
public RecentsAnimationTargets getController() {
return targetSet;
}
}
@@ -38,11 +38,9 @@ public class SwipeSharedState implements RecentsAnimationListener {
private OverviewComponentObserver mOverviewComponentObserver;
private RecentsAnimationCallbacks mRecentsAnimationListener;
private RecentsAnimationWrapper mLastRecentsAnimationController;
private RecentsAnimationTargets mLastAnimationTarget;
// TODO: Remove
private Runnable mRecentsAnimationCanceledCallback;
private boolean mLastAnimationCancelled = false;
private boolean mLastAnimationRunning = false;
@@ -57,13 +55,35 @@ public class SwipeSharedState implements RecentsAnimationListener {
}
@Override
public final void onRecentsAnimationStart(RecentsAnimationTargets targetSet) {
public final void onRecentsAnimationStart(RecentsAnimationWrapper controller,
RecentsAnimationTargets targetSet) {
mLastRecentsAnimationController = controller;
mLastAnimationTarget = targetSet;
mLastAnimationCancelled = false;
mLastAnimationRunning = true;
}
@Override
public final void onRecentsAnimationCanceled(ThumbnailData thumbnailData) {
if (thumbnailData != null) {
mOverviewComponentObserver.getActivityControlHelper().switchToScreenshot(thumbnailData,
() -> {
mLastRecentsAnimationController.cleanupScreenshot();
clearAnimationState();
});
} else {
clearAnimationState();
}
}
@Override
public final void onRecentsAnimationFinished(RecentsAnimationWrapper controller) {
if (mLastRecentsAnimationController == controller) {
mLastAnimationRunning = false;
}
}
private void clearAnimationTarget() {
if (mLastAnimationTarget != null) {
mLastAnimationTarget.release();
@@ -71,42 +91,23 @@ public class SwipeSharedState implements RecentsAnimationListener {
}
}
@Override
public final void onRecentsAnimationCanceled(ThumbnailData thumbnailData) {
if (thumbnailData != null) {
mOverviewComponentObserver.getActivityControlHelper().switchToScreenshot(thumbnailData,
() -> {
if (mRecentsAnimationCanceledCallback != null) {
mRecentsAnimationCanceledCallback.run();
}
clearAnimationState();
});
} else {
clearAnimationState();
}
}
public void setRecentsAnimationCanceledCallback(Runnable callback) {
mRecentsAnimationCanceledCallback = callback;
}
private void clearAnimationState() {
clearAnimationTarget();
mLastAnimationCancelled = true;
mLastAnimationRunning = false;
mRecentsAnimationCanceledCallback = null;
}
private void clearListenerState(boolean finishAnimation) {
if (mRecentsAnimationListener != null) {
mRecentsAnimationListener.removeListener(this);
mRecentsAnimationListener.cancelListener();
if (mLastAnimationRunning && mLastAnimationTarget != null) {
mRecentsAnimationListener.notifyAnimationCanceled();
if (mLastAnimationRunning && mLastRecentsAnimationController != null) {
Utilities.postAsyncCallback(MAIN_EXECUTOR.getHandler(),
finishAnimation
? mLastAnimationTarget::finishAnimation
: mLastAnimationTarget::cancelAnimation);
? mLastRecentsAnimationController::finishAnimationToHome
: mLastRecentsAnimationController::finishAnimationToApp);
mLastRecentsAnimationController = null;
mLastAnimationTarget = null;
}
}
@@ -116,12 +117,6 @@ public class SwipeSharedState implements RecentsAnimationListener {
mLastAnimationRunning = false;
}
private void onSwipeAnimationFinished(RecentsAnimationTargets targetSet) {
if (mLastAnimationTarget == targetSet) {
mLastAnimationRunning = false;
}
}
public RecentsAnimationCallbacks newRecentsAnimationListenerSet() {
Preconditions.assertUIThread();
@@ -137,8 +132,7 @@ public class SwipeSharedState implements RecentsAnimationListener {
clearListenerState(false /* finishAnimation */);
boolean shouldMinimiseSplitScreen = mOverviewComponentObserver == null ? false
: mOverviewComponentObserver.getActivityControlHelper().shouldMinimizeSplitScreen();
mRecentsAnimationListener = new RecentsAnimationCallbacks(
shouldMinimiseSplitScreen, this::onSwipeAnimationFinished);
mRecentsAnimationListener = new RecentsAnimationCallbacks(shouldMinimiseSplitScreen);
mRecentsAnimationListener.addListener(this);
return mRecentsAnimationListener;
}
@@ -148,8 +142,9 @@ public class SwipeSharedState implements RecentsAnimationListener {
}
public void applyActiveRecentsAnimationState(RecentsAnimationListener listener) {
if (mLastAnimationTarget != null) {
listener.onRecentsAnimationStart(mLastAnimationTarget);
if (mLastRecentsAnimationController != null) {
listener.onRecentsAnimationStart(mLastRecentsAnimationController,
mLastAnimationTarget);
} else if (mLastAnimationCancelled) {
listener.onRecentsAnimationCanceled(null);
}
@@ -414,10 +414,9 @@ public class TouchInteractionService extends Service implements
// Do not change mConsumer as if there is an ongoing QuickSwitch gesture, we should
// not interrupt it. QuickSwitch assumes that interruption can only happen if the
// next gesture is also quick switch.
mUncheckedConsumer =
new AssistantInputConsumer(this,
mOverviewComponentObserver.getActivityControlHelper(),
InputConsumer.NO_OP, mInputMonitorCompat);
mUncheckedConsumer = new AssistantInputConsumer(this,
mOverviewComponentObserver.getActivityControlHelper(),
InputConsumer.NO_OP, mInputMonitorCompat);
} else {
mUncheckedConsumer = InputConsumer.NO_OP;
}
@@ -291,9 +291,6 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
mStateCallback.addCallback(STATE_HANDLER_INVALIDATED | STATE_RESUME_LAST_TASK,
this::notifyTransitionCancelled);
mStateCallback.addCallback(STATE_APP_CONTROLLER_RECEIVED | STATE_GESTURE_STARTED,
mRecentsAnimationWrapper::enableInputConsumer);
if (!ENABLE_QUICKSTEP_LIVE_TILE.get()) {
mStateCallback.addChangeHandler(STATE_APP_CONTROLLER_RECEIVED | STATE_LAUNCHER_PRESENT
| STATE_SCREENSHOT_VIEW_SHOWN | STATE_CAPTURE_SCREENSHOT,
@@ -417,7 +414,7 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
}
private void sendRemoteAnimationsToAnimationFactory() {
mAnimationFactory.onRemoteAnimationReceived(mRecentsAnimationWrapper.targetSet);
mAnimationFactory.onRemoteAnimationReceived(mRecentsAnimationTargets);
}
private void initializeLauncherAnimationController() {
@@ -464,9 +461,9 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
if (mMode != Mode.NO_BUTTON || mRecentsView == null) {
return;
}
RemoteAnimationTargetCompat runningTaskTarget = mRecentsAnimationWrapper.targetSet == null
RemoteAnimationTargetCompat runningTaskTarget = mRecentsAnimationTargets == null
? null
: mRecentsAnimationWrapper.targetSet.findTask(mRunningTaskId);
: mRecentsAnimationTargets.findTask(mRunningTaskId);
final boolean recentsAttachedToAppWindow;
int runningTaskIndex = mRecentsView.getRunningTaskIndex();
if (mGestureEndTarget != null) {
@@ -548,15 +545,13 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
@Override
public void updateFinalShift() {
RecentsAnimationTargets controller = mRecentsAnimationWrapper.getController();
if (controller != null) {
if (mRecentsAnimationTargets != null) {
applyTransformUnchecked();
updateSysUiFlags(mCurrentShift.value);
}
if (ENABLE_QUICKSTEP_LIVE_TILE.get()) {
if (mRecentsAnimationWrapper.getController() != null) {
if (mRecentsAnimationTargets != null) {
mLiveTileOverlay.update(mAppWindowAnimationHelper.getCurrentRectWithInsets(),
mAppWindowAnimationHelper.getCurrentCornerRadius());
}
@@ -599,17 +594,24 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
: centermostTask.getThumbnail().getSysUiStatusNavFlags();
boolean useHomeScreenFlags = windowProgress > 1 - UPDATE_SYSUI_FLAGS_THRESHOLD;
// We will handle the sysui flags based on the centermost task view.
mRecentsAnimationWrapper.setWindowThresholdCrossed(centermostTaskFlags != 0
|| useHomeScreenFlags);
if (mRecentsAnimationWrapper != null) {
mRecentsAnimationWrapper.setWindowThresholdCrossed(centermostTaskFlags != 0
|| useHomeScreenFlags);
}
int sysuiFlags = useHomeScreenFlags ? 0 : centermostTaskFlags;
mActivity.getSystemUiController().updateUiState(UI_STATE_OVERVIEW, sysuiFlags);
}
}
@Override
public void onRecentsAnimationStart(RecentsAnimationTargets targetSet) {
super.onRecentsAnimationStart(targetSet);
public void onRecentsAnimationStart(RecentsAnimationWrapper controller,
RecentsAnimationTargets targetSet) {
ActiveGestureLog.INSTANCE.addLog("startRecentsAnimationCallback", targetSet.apps.length);
super.onRecentsAnimationStart(controller, targetSet);
// Only add the callback to enable the input consumer after we actually have the controller
mStateCallback.addCallback(STATE_APP_CONTROLLER_RECEIVED | STATE_GESTURE_STARTED,
mRecentsAnimationWrapper::enableInputConsumer);
setStateOnUiThread(STATE_APP_CONTROLLER_RECEIVED);
mPassedOverviewThreshold = false;
@@ -617,7 +619,8 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
@Override
public void onRecentsAnimationCanceled(ThumbnailData thumbnailData) {
mRecentsAnimationWrapper.setController(null);
super.onRecentsAnimationCanceled(thumbnailData);
mRecentsView.setRecentsAnimationTargets(null, null);
mActivityInitListener.unregister();
setStateOnUiThread(STATE_GESTURE_CANCELLED | STATE_HANDLER_INVALIDATED);
ActiveGestureLog.INSTANCE.addLog("cancelRecentsAnimation");
@@ -707,7 +710,7 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
final GestureEndTarget endTarget;
final boolean goingToNewTask;
if (mRecentsView != null) {
if (!mRecentsAnimationWrapper.hasTargets()) {
if (!hasTargets()) {
// If there are no running tasks, then we can assume that this is a continuation of
// the last gesture, but after the recents animation has finished
goingToNewTask = true;
@@ -810,8 +813,9 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
}
}
if (endTarget.isLauncher) {
mRecentsAnimationWrapper.enableInputProxy();
if (endTarget.isLauncher && mRecentsAnimationWrapper != null) {
mRecentsAnimationWrapper.enableInputProxy(mInputConsumer,
this::createNewInputProxyHandler);
}
if (endTarget == HOME) {
@@ -866,7 +870,7 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
@UiThread
private void animateToProgress(float start, float end, long duration, Interpolator interpolator,
GestureEndTarget target, PointF velocityPxPerMs) {
mRecentsAnimationWrapper.runOnInit(() -> animateToProgressInternal(start, end, duration,
runOnRecentsAnimationStart(() -> animateToProgressInternal(start, end, duration,
interpolator, target, velocityPxPerMs));
}
@@ -1108,25 +1112,24 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
}
private void switchToScreenshot() {
RecentsAnimationTargets controller = mRecentsAnimationWrapper.getController();
if (ENABLE_QUICKSTEP_LIVE_TILE.get()) {
if (controller != null) {
if (mRecentsAnimationWrapper != null) {
// Update the screenshot of the task
if (mTaskSnapshot == null) {
mTaskSnapshot = controller.screenshotTask(mRunningTaskId);
mTaskSnapshot = mRecentsAnimationWrapper.screenshotTask(mRunningTaskId);
}
mRecentsView.updateThumbnail(mRunningTaskId, mTaskSnapshot, false /* refreshNow */);
}
setStateOnUiThread(STATE_SCREENSHOT_CAPTURED);
} else if (!mRecentsAnimationWrapper.hasTargets()) {
} else if (!hasTargets()) {
// If there are no targets, then we don't need to capture anything
setStateOnUiThread(STATE_SCREENSHOT_CAPTURED);
} else {
boolean finishTransitionPosted = false;
if (controller != null) {
if (mRecentsAnimationWrapper != null) {
// Update the screenshot of the task
if (mTaskSnapshot == null) {
mTaskSnapshot = controller.screenshotTask(mRunningTaskId);
mTaskSnapshot = mRecentsAnimationWrapper.screenshotTask(mRunningTaskId);
}
final TaskView taskView;
if (mGestureEndTarget == HOME) {
@@ -1155,7 +1158,7 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
private void finishCurrentTransitionToRecents() {
if (ENABLE_QUICKSTEP_LIVE_TILE.get()) {
setStateOnUiThread(STATE_CURRENT_TASK_FINISHED);
} else if (!mRecentsAnimationWrapper.hasTargets()) {
} else if (!hasTargets()) {
// If there are no targets, then there is nothing to finish
setStateOnUiThread(STATE_CURRENT_TASK_FINISHED);
} else {
@@ -1180,8 +1183,10 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
private void setupLauncherUiAfterSwipeUpToRecentsAnimation() {
endLauncherTransitionController();
mActivityControlHelper.onSwipeUpToRecentsComplete(mActivity);
mRecentsAnimationWrapper.setDeferCancelUntilNextTransition(true /* defer */,
true /* screenshot */);
if (mRecentsAnimationWrapper != null) {
mRecentsAnimationWrapper.setDeferCancelUntilNextTransition(true /* defer */,
true /* screenshot */);
}
mRecentsView.onSwipeUpAnimationSuccess();
RecentsModel.INSTANCE.get(mContext).onOverviewShown(false, TAG);
@@ -42,6 +42,7 @@ import com.android.launcher3.util.DefaultDisplay;
import com.android.quickstep.LockScreenRecentsActivity;
import com.android.quickstep.MultiStateCallback;
import com.android.quickstep.RecentsAnimationDeviceState;
import com.android.quickstep.RecentsAnimationWrapper;
import com.android.quickstep.SwipeSharedState;
import com.android.quickstep.util.AppWindowAnimationHelper;
import com.android.quickstep.util.RecentsAnimationCallbacks;
@@ -91,7 +92,8 @@ public class DeviceLockedInputConsumer implements InputConsumer,
private boolean mThresholdCrossed = false;
private RecentsAnimationTargets mTargetSet;
private RecentsAnimationWrapper mRecentsAnimationController;
private RecentsAnimationTargets mRecentsAnimationTargets;
public DeviceLockedInputConsumer(Context context, RecentsAnimationDeviceState deviceState,
SwipeSharedState swipeSharedState, InputMonitorCompat inputMonitorCompat,
@@ -216,8 +218,10 @@ public class DeviceLockedInputConsumer implements InputConsumer,
}
@Override
public void onRecentsAnimationStart(RecentsAnimationTargets targetSet) {
mTargetSet = targetSet;
public void onRecentsAnimationStart(RecentsAnimationWrapper controller,
RecentsAnimationTargets targetSet) {
mRecentsAnimationController = controller;
mRecentsAnimationTargets = targetSet;
Rect displaySize = new Rect(0, 0, mDisplaySize.x, mDisplaySize.y);
RemoteAnimationTargetCompat targetCompat = targetSet.findTask(mRunningTaskId);
@@ -227,7 +231,7 @@ public class DeviceLockedInputConsumer implements InputConsumer,
Utilities.scaleRectAboutCenter(displaySize, SCALE_DOWN);
displaySize.offsetTo(displaySize.left, 0);
mTransformParams.setTargetSet(mTargetSet)
mTransformParams.setTargetSet(mRecentsAnimationTargets)
.setLauncherOnTop(true);
mAppWindowAnimationHelper.updateTargetRect(displaySize);
mAppWindowAnimationHelper.applyTransform(mTransformParams);
@@ -237,12 +241,13 @@ public class DeviceLockedInputConsumer implements InputConsumer,
@Override
public void onRecentsAnimationCanceled(ThumbnailData thumbnailData) {
mTargetSet = null;
mRecentsAnimationController = null;
mRecentsAnimationTargets = null;
}
private void endRemoteAnimation() {
if (mTargetSet != null) {
mTargetSet.finishController(
if (mRecentsAnimationController != null) {
mRecentsAnimationController.finishController(
false /* toRecents */, null /* callback */, false /* sendUserLeaveHint */);
}
}
@@ -45,6 +45,7 @@ import com.android.quickstep.BaseSwipeUpHandler;
import com.android.quickstep.MultiStateCallback;
import com.android.quickstep.OverviewComponentObserver;
import com.android.quickstep.RecentsActivity;
import com.android.quickstep.RecentsAnimationWrapper;
import com.android.quickstep.RecentsModel;
import com.android.quickstep.SwipeSharedState;
import com.android.quickstep.fallback.FallbackRecentsView;
@@ -157,7 +158,7 @@ public class FallbackNoButtonInputConsumer extends
}
private void onLauncherAlphaChanged() {
if (mRecentsAnimationWrapper.targetSet != null && mEndTarget == null) {
if (mRecentsAnimationTargets != null && mEndTarget == null) {
applyTransformUnchecked();
}
}
@@ -231,9 +232,11 @@ public class FallbackNoButtonInputConsumer extends
@Override
public void updateFinalShift() {
mTransformParams.setProgress(mCurrentShift.value);
mRecentsAnimationWrapper.setWindowThresholdCrossed(!mInQuickSwitchMode
&& (mCurrentShift.value > 1 - UPDATE_SYSUI_FLAGS_THRESHOLD));
if (mRecentsAnimationWrapper.targetSet != null) {
if (mRecentsAnimationWrapper != null) {
mRecentsAnimationWrapper.setWindowThresholdCrossed(!mInQuickSwitchMode
&& (mCurrentShift.value > 1 - UPDATE_SYSUI_FLAGS_THRESHOLD));
}
if (mRecentsAnimationTargets != null) {
applyTransformUnchecked();
}
}
@@ -333,8 +336,7 @@ public class FallbackNoButtonInputConsumer extends
break;
}
ThumbnailData thumbnail =
mRecentsAnimationWrapper.targetSet.controller.screenshotTask(mRunningTaskId);
ThumbnailData thumbnail = mRecentsAnimationWrapper.screenshotTask(mRunningTaskId);
mRecentsAnimationWrapper.setDeferCancelUntilNextTransition(true /* defer */,
false /* screenshot */);
@@ -348,7 +350,7 @@ public class FallbackNoButtonInputConsumer extends
Intent intent = new Intent(mOverviewComponentObserver.getOverviewIntent())
.putExtras(extras);
mContext.startActivity(intent, options.toBundle());
mRecentsAnimationWrapper.targetSet.controller.cleanupScreenshot();
mRecentsAnimationWrapper.cleanupScreenshot();
break;
}
case NEW_TASK: {
@@ -364,7 +366,7 @@ public class FallbackNoButtonInputConsumer extends
if (mInQuickSwitchMode) {
// Recalculate the end target, some views might have been initialized after
// gesture has ended.
if (mRecentsView == null || !mRecentsAnimationWrapper.hasTargets()) {
if (mRecentsView == null || !hasTargets()) {
mEndTarget = LAST_TASK;
} else {
final int runningTaskIndex = mRecentsView.getRunningTaskIndex();
@@ -414,8 +416,9 @@ public class FallbackNoButtonInputConsumer extends
}
@Override
public void onRecentsAnimationStart(RecentsAnimationTargets targetSet) {
super.onRecentsAnimationStart(targetSet);
public void onRecentsAnimationStart(RecentsAnimationWrapper controller,
RecentsAnimationTargets targetSet) {
super.onRecentsAnimationStart(controller, targetSet);
mRecentsAnimationWrapper.enableInputConsumer();
if (mRunningOverHome) {
@@ -428,7 +431,7 @@ public class FallbackNoButtonInputConsumer extends
@Override
public void onRecentsAnimationCanceled(ThumbnailData thumbnailData) {
mRecentsAnimationWrapper.setController(null);
mRecentsView.setRecentsAnimationTargets(null, null);
setStateOnUiThread(STATE_HANDLER_INVALIDATED);
}
@@ -26,33 +26,30 @@ import androidx.annotation.UiThread;
import com.android.launcher3.Utilities;
import com.android.launcher3.util.Preconditions;
import com.android.quickstep.TouchInteractionService;
import com.android.quickstep.RecentsAnimationWrapper;
import com.android.systemui.shared.recents.model.ThumbnailData;
import com.android.systemui.shared.system.RecentsAnimationControllerCompat;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
import java.util.Set;
import java.util.function.Consumer;
/**
* Wrapper around {@link com.android.systemui.shared.system.RecentsAnimationListener} which delegates callbacks to multiple listeners
* on the main thread
* Wrapper around {@link com.android.systemui.shared.system.RecentsAnimationListener} which
* delegates callbacks to multiple listeners on the main thread
*/
public class RecentsAnimationCallbacks implements
com.android.systemui.shared.system.RecentsAnimationListener {
private final Set<RecentsAnimationListener> mListeners = new ArraySet<>();
private final boolean mShouldMinimizeSplitScreen;
private final Consumer<RecentsAnimationTargets> mOnFinishListener;
private RecentsAnimationControllerCompat mController;
// TODO(141886704): Remove these references when they are no longer needed
private RecentsAnimationWrapper mController;
private boolean mCancelled;
public RecentsAnimationCallbacks(boolean shouldMinimizeSplitScreen,
Consumer<RecentsAnimationTargets> onFinishListener) {
public RecentsAnimationCallbacks(boolean shouldMinimizeSplitScreen) {
mShouldMinimizeSplitScreen = shouldMinimizeSplitScreen;
mOnFinishListener = onFinishListener;
TouchInteractionService.getSwipeSharedState().setRecentsAnimationCanceledCallback(
() -> mController.cleanupScreenshot());
}
@UiThread
@@ -67,26 +64,9 @@ public class RecentsAnimationCallbacks implements
mListeners.remove(listener);
}
// Called only in R+ platform
@BinderThread
public final void onAnimationStart(RecentsAnimationControllerCompat controller,
RemoteAnimationTargetCompat[] appTargets,
RemoteAnimationTargetCompat[] wallpaperTargets,
Rect homeContentInsets, Rect minimizedHomeBounds) {
mController = controller;
RecentsAnimationTargets targetSet = new RecentsAnimationTargets(controller, appTargets,
wallpaperTargets, homeContentInsets, minimizedHomeBounds,
mShouldMinimizeSplitScreen, mOnFinishListener);
if (mCancelled) {
targetSet.cancelAnimation();
} else {
Utilities.postAsyncCallback(MAIN_EXECUTOR.getHandler(), () -> {
for (RecentsAnimationListener listener : getListeners()) {
listener.onRecentsAnimationStart(targetSet);
}
});
}
public void notifyAnimationCanceled() {
mCancelled = true;
onAnimationCanceled(null);
}
// Called only in Q platform
@@ -99,6 +79,29 @@ public class RecentsAnimationCallbacks implements
homeContentInsets, minimizedHomeBounds);
}
// Called only in R+ platform
@BinderThread
public final void onAnimationStart(RecentsAnimationControllerCompat animationController,
RemoteAnimationTargetCompat[] appTargets,
RemoteAnimationTargetCompat[] wallpaperTargets,
Rect homeContentInsets, Rect minimizedHomeBounds) {
RecentsAnimationTargets targetSet = new RecentsAnimationTargets(appTargets,
wallpaperTargets, homeContentInsets, minimizedHomeBounds);
mController = new RecentsAnimationWrapper(animationController, mShouldMinimizeSplitScreen,
this::onAnimationFinished);
if (mCancelled) {
Utilities.postAsyncCallback(MAIN_EXECUTOR.getHandler(),
mController::finishAnimationToApp);
} else {
Utilities.postAsyncCallback(MAIN_EXECUTOR.getHandler(), () -> {
for (RecentsAnimationListener listener : getListeners()) {
listener.onRecentsAnimationStart(mController, targetSet);
}
});
}
}
@BinderThread
@Override
public final void onAnimationCanceled(ThumbnailData thumbnailData) {
@@ -109,25 +112,31 @@ public class RecentsAnimationCallbacks implements
});
}
private RecentsAnimationListener[] getListeners() {
return mListeners.toArray(new RecentsAnimationListener[mListeners.size()]);
private final void onAnimationFinished(RecentsAnimationWrapper controller) {
Utilities.postAsyncCallback(MAIN_EXECUTOR.getHandler(), () -> {
for (RecentsAnimationListener listener : getListeners()) {
listener.onRecentsAnimationFinished(controller);
}
});
}
public void cancelListener() {
mCancelled = true;
onAnimationCanceled(null);
private RecentsAnimationListener[] getListeners() {
return mListeners.toArray(new RecentsAnimationListener[mListeners.size()]);
}
/**
* Listener for the recents animation callbacks.
*/
public interface RecentsAnimationListener {
void onRecentsAnimationStart(RecentsAnimationTargets targetSet);
default void onRecentsAnimationStart(RecentsAnimationWrapper controller,
RecentsAnimationTargets targetSet) {}
/**
* Callback from the system when the recents animation is canceled. {@param thumbnailData}
* is passed back for rendering screenshot to replace live tile.
*/
void onRecentsAnimationCanceled(ThumbnailData thumbnailData);
default void onRecentsAnimationCanceled(ThumbnailData thumbnailData) {}
default void onRecentsAnimationFinished(RecentsAnimationWrapper controller) {}
}
}
@@ -15,41 +15,27 @@
*/
package com.android.quickstep.util;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_CLOSING;
import android.graphics.Rect;
import com.android.systemui.shared.recents.model.ThumbnailData;
import com.android.systemui.shared.system.RecentsAnimationControllerCompat;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
import java.util.function.Consumer;
/**
* Extension of {@link RemoteAnimationTargets} with additional information about swipe
* up animation
*/
public class RecentsAnimationTargets extends RemoteAnimationTargets {
private final boolean mShouldMinimizeSplitScreen;
private final Consumer<RecentsAnimationTargets> mOnFinishListener;
public final RecentsAnimationControllerCompat controller;
public final Rect homeContentInsets;
public final Rect minimizedHomeBounds;
public RecentsAnimationTargets(RecentsAnimationControllerCompat controller,
RemoteAnimationTargetCompat[] apps, RemoteAnimationTargetCompat[] wallpapers,
Rect homeContentInsets, Rect minimizedHomeBounds, boolean shouldMinimizeSplitScreen,
Consumer<RecentsAnimationTargets> onFinishListener) {
public RecentsAnimationTargets(RemoteAnimationTargetCompat[] apps,
RemoteAnimationTargetCompat[] wallpapers, Rect homeContentInsets,
Rect minimizedHomeBounds) {
super(apps, wallpapers, MODE_CLOSING);
this.controller = controller;
this.homeContentInsets = homeContentInsets;
this.minimizedHomeBounds = minimizedHomeBounds;
this.mShouldMinimizeSplitScreen = shouldMinimizeSplitScreen;
this.mOnFinishListener = onFinishListener;
}
public boolean hasTargets() {
@@ -61,52 +47,7 @@ public class RecentsAnimationTargets extends RemoteAnimationTargets {
* the actual recents animation has finished.
*/
public RecentsAnimationTargets cloneWithoutTargets() {
return new RecentsAnimationTargets(controller, new RemoteAnimationTargetCompat[0],
new RemoteAnimationTargetCompat[0], homeContentInsets, minimizedHomeBounds,
mShouldMinimizeSplitScreen, mOnFinishListener);
}
public void finishController(boolean toRecents, Runnable callback, boolean sendUserLeaveHint) {
mOnFinishListener.accept(this);
UI_HELPER_EXECUTOR.execute(() -> {
controller.setInputConsumerEnabled(false);
controller.finish(toRecents, sendUserLeaveHint);
if (callback != null) {
MAIN_EXECUTOR.execute(callback);
}
});
}
public void enableInputConsumer() {
UI_HELPER_EXECUTOR.submit(() -> {
controller.hideCurrentInputMethod();
controller.setInputConsumerEnabled(true);
});
}
public void setWindowThresholdCrossed(boolean thresholdCrossed) {
UI_HELPER_EXECUTOR.execute(() -> {
controller.setAnimationTargetsBehindSystemBars(!thresholdCrossed);
if (mShouldMinimizeSplitScreen && thresholdCrossed) {
// NOTE: As a workaround for conflicting animations (Launcher animating the task
// leash, and SystemUI resizing the docked stack, which resizes the task), we
// currently only set the minimized mode, and not the inverse.
// TODO: Synchronize the minimize animation with the launcher animation
controller.setSplitScreenMinimized(thresholdCrossed);
}
});
}
public ThumbnailData screenshotTask(int taskId) {
return controller != null ? controller.screenshotTask(taskId) : null;
}
public void cancelAnimation() {
finishController(false /* toRecents */, null, false /* sendUserLeaveHint */);
}
public void finishAnimation() {
finishController(true /* toRecents */, null, false /* sendUserLeaveHint */);
return new RecentsAnimationTargets(new RemoteAnimationTargetCompat[0],
new RemoteAnimationTargetCompat[0], homeContentInsets, minimizedHomeBounds);
}
}
@@ -221,7 +221,7 @@ public class LauncherRecentsView extends RecentsView<Launcher> implements StateL
public AppWindowAnimationHelper.TransformParams getLiveTileParams(
boolean mightNeedToRefill) {
if (!mEnableDrawingLiveTile || mRecentsAnimationWrapper == null
|| mAppWindowAnimationHelper == null) {
|| mRecentsAnimationTargets == null || mAppWindowAnimationHelper == null) {
return null;
}
TaskView taskView = getRunningTaskView();
@@ -245,7 +245,7 @@ public class LauncherRecentsView extends RecentsView<Launcher> implements StateL
mTransformParams.setProgress(1f)
.setCurrentRectAndTargetAlpha(mTempRectF, taskView.getAlpha())
.setSyncTransactionApplier(mSyncTransactionApplier)
.setTargetSet(mRecentsAnimationWrapper.targetSet)
.setTargetSet(mRecentsAnimationTargets)
.setLauncherOnTop(true);
}
return mTransformParams;
@@ -108,6 +108,7 @@ import com.android.quickstep.TaskThumbnailCache;
import com.android.quickstep.TaskUtils;
import com.android.quickstep.ViewUtils;
import com.android.quickstep.util.AppWindowAnimationHelper;
import com.android.quickstep.util.RecentsAnimationTargets;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.recents.model.ThumbnailData;
import com.android.systemui.shared.system.ActivityManagerWrapper;
@@ -156,6 +157,7 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
};
protected RecentsAnimationWrapper mRecentsAnimationWrapper;
protected RecentsAnimationTargets mRecentsAnimationTargets;
protected AppWindowAnimationHelper mAppWindowAnimationHelper;
protected SyncRtSurfaceTransactionApplierCompat mSyncTransactionApplier;
protected int mTaskWidth;
@@ -808,6 +810,7 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
mTaskListChangeId = -1;
mRecentsAnimationWrapper = null;
mRecentsAnimationTargets = null;
mAppWindowAnimationHelper = null;
unloadVisibleTaskData();
@@ -1692,10 +1695,14 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
public void redrawLiveTile(boolean mightNeedToRefill) { }
public void setRecentsAnimationWrapper(RecentsAnimationWrapper recentsAnimationWrapper) {
// TODO: To be removed in a follow up CL
public void setRecentsAnimationTargets(RecentsAnimationWrapper recentsAnimationWrapper,
RecentsAnimationTargets recentsAnimationTargets) {
mRecentsAnimationWrapper = recentsAnimationWrapper;
mRecentsAnimationTargets = recentsAnimationTargets;
}
// TODO: To be removed in a follow up CL
public void setAppWindowAnimationHelper(AppWindowAnimationHelper appWindowAnimationHelper) {
mAppWindowAnimationHelper = appWindowAnimationHelper;
}
@@ -86,6 +86,9 @@ public class RemoteAnimationTargets {
for (RemoteAnimationTargetCompat target : unfilteredApps) {
target.release();
}
for (RemoteAnimationTargetCompat target : wallpapers) {
target.release();
}
} else {
applier.addAfterApplyCallback(this::release);
}