diff options
Diffstat (limited to 'quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java')
-rw-r--r-- | quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java | 327 |
1 files changed, 186 insertions, 141 deletions
diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java index 1ef4039ce9..d7ff59e2eb 100644 --- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java +++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java @@ -24,6 +24,8 @@ import static android.widget.Toast.LENGTH_SHORT; import static com.android.app.animation.Interpolators.ACCELERATE_DECELERATE; import static com.android.app.animation.Interpolators.DECELERATE; import static com.android.app.animation.Interpolators.OVERSHOOT_1_2; +import static com.android.launcher3.BaseActivity.EVENT_DESTROYED; +import static com.android.launcher3.BaseActivity.EVENT_STARTED; import static com.android.launcher3.BaseActivity.INVISIBLE_BY_STATE_HANDLER; import static com.android.launcher3.BaseActivity.STATE_HANDLER_INVISIBILITY_FLAGS; import static com.android.launcher3.LauncherPrefs.ALL_APPS_OVERVIEW_THRESHOLD; @@ -51,8 +53,10 @@ import static com.android.quickstep.GestureState.STATE_RECENTS_SCROLLING_FINISHE import static com.android.quickstep.MultiStateCallback.DEBUG_STATES; import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.CANCEL_RECENTS_ANIMATION; import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.EXPECTING_TASK_APPEARED; +import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.INVALID_VELOCITY_ON_SWIPE_UP; import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.LAUNCHER_DESTROYED; import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.ON_SETTLED_ON_END_TARGET; +import static com.android.quickstep.views.DesktopTaskView.isDesktopModeSupported; import static com.android.quickstep.views.RecentsView.UPDATE_SYSUI_FLAGS_THRESHOLD; import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_RECENTS; @@ -61,7 +65,6 @@ import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorSet; import android.animation.ValueAnimator; import android.annotation.TargetApi; -import android.app.Activity; import android.app.ActivityManager; import android.app.TaskInfo; import android.app.WindowConfiguration; @@ -78,6 +81,7 @@ import android.os.SystemClock; import android.util.Log; import android.view.MotionEvent; import android.view.RemoteAnimationTarget; +import android.view.SurfaceControl; import android.view.View; import android.view.View.OnApplyWindowInsetsListener; import android.view.ViewGroup; @@ -88,6 +92,7 @@ import android.view.animation.Interpolator; import android.widget.Toast; import android.window.PictureInPictureSurfaceTransaction; +import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.UiThread; @@ -108,7 +113,6 @@ import com.android.launcher3.statemanager.StatefulActivity; import com.android.launcher3.taskbar.TaskbarThresholdUtils; import com.android.launcher3.taskbar.TaskbarUIController; import com.android.launcher3.uioverrides.QuickstepLauncher; -import com.android.launcher3.util.ActivityLifecycleCallbacksAdapter; import com.android.launcher3.util.DisplayController; import com.android.launcher3.util.SafeCloseable; import com.android.launcher3.util.TraceHelper; @@ -131,7 +135,6 @@ import com.android.quickstep.util.SurfaceTransaction; import com.android.quickstep.util.SurfaceTransactionApplier; import com.android.quickstep.util.SwipePipToHomeAnimator; import com.android.quickstep.util.TaskViewSimulator; -import com.android.quickstep.views.DesktopTaskView; import com.android.quickstep.views.RecentsView; import com.android.quickstep.views.TaskView; import com.android.quickstep.views.TaskView.TaskIdAttributeContainer; @@ -177,25 +180,19 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>, protected @Nullable RecentsAnimationController mRecentsAnimationController; protected @Nullable RecentsAnimationController mDeferredCleanupRecentsAnimationController; protected RecentsAnimationTargets mRecentsAnimationTargets; - protected T mActivity; + protected @Nullable T mActivity; protected @Nullable Q mRecentsView; protected Runnable mGestureEndCallback; protected MultiStateCallback mStateCallback; protected boolean mCanceled; private boolean mRecentsViewScrollLinked = false; - private final ActivityLifecycleCallbacksAdapter mLifecycleCallbacks = - new ActivityLifecycleCallbacksAdapter() { - @Override - public void onActivityDestroyed(Activity activity) { - if (mActivity != activity) { - return; - } - ActiveGestureLog.INSTANCE.addLog("Launcher destroyed", LAUNCHER_DESTROYED); - mRecentsView = null; - mActivity = null; - mStateCallback.clearState(STATE_LAUNCHER_PRESENT); - } - }; + + private final Runnable mLauncherOnDestroyCallback = () -> { + ActiveGestureLog.INSTANCE.addLog("Launcher destroyed", LAUNCHER_DESTROYED); + mRecentsView = null; + mActivity = null; + mStateCallback.clearState(STATE_LAUNCHER_PRESENT); + }; private static int FLAG_COUNT = 0; private static int getNextStateFlag(String name) { @@ -316,8 +313,9 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>, private final int mSplashMainWindowShiftLength; private final Runnable mOnDeferredActivityLaunch = this::onDeferredActivityLaunch; + private final Runnable mLauncherOnStartCallback = this::onLauncherStart; - private SwipePipToHomeAnimator mSwipePipToHomeAnimator; + @Nullable private SwipePipToHomeAnimator mSwipePipToHomeAnimator; protected boolean mIsSwipingPipToHome; // TODO(b/195473090) no split PIP for now, remove once we have more clarity // can try to have RectFSpringAnim evaluate multiple rects at once @@ -355,7 +353,7 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>, return ROTATION_0; } return mRecentsView.getPagedViewOrientedState().getRecentsActivityRotation(); - }, inputConsumer, /* callback = */ () -> { + }, inputConsumer, /* onTouchDownCallback = */ () -> { endRunningWindowAnim(mGestureState.getEndTarget() == HOME /* cancel */); endLauncherTransitionController(); }, new InputProxyHandlerFactory(mActivityInterface, mGestureState)); @@ -489,6 +487,7 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>, mGestureState.setState(STATE_RECENTS_SCROLLING_FINISHED); return true; } + resetLauncherListeners(); // The launcher may have been recreated as a result of device rotation. int oldState = mStateCallback.getState() & ~LAUNCHER_UI_STATES; @@ -512,7 +511,7 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>, if (alreadyOnHome) { onLauncherStart(); } else { - activity.runOnceOnStart(this::onLauncherStart); + activity.addEventCallback(EVENT_STARTED, mLauncherOnStartCallback); } // Set up a entire animation lifecycle callback to notify the current recents view when @@ -537,9 +536,8 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>, setupRecentsViewUi(); mRecentsView.runOnPageScrollsInitialized(this::linkRecentsViewScroll); - activity.runOnBindToTouchInteractionService(this::onLauncherBindToService); - - mActivity.registerActivityLifecycleCallbacks(mLifecycleCallbacks); + mActivity.runOnBindToTouchInteractionService(this::onLauncherBindToService); + mActivity.addEventCallback(EVENT_DESTROYED, mLauncherOnDestroyCallback); return true; } @@ -552,7 +550,7 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>, private void onLauncherStart() { final T activity = mActivityInterface.getCreatedActivity(); - if (mActivity != activity) { + if (activity == null || mActivity != activity) { return; } if (mStateCallback.hasStates(STATE_HANDLER_INVALIDATED)) { @@ -676,6 +674,9 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>, if (Arrays.stream(runningTasks).anyMatch(Objects::isNull)) { return; } + if (mRecentsView == null) { + return; + } mRecentsView.onGestureAnimationStart(runningTasks, mDeviceState.getRotationTouchHelper()); } @@ -854,7 +855,9 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>, if (windowInsets.isVisible(WindowInsets.Type.ime())) { return result; } - buildAnimationController(); + if (mGestureState.getEndTarget() == null) { + buildAnimationController(); + } // Reapply the current shift to ensure it takes new insets into account, e.g. when long // pressing to stash taskbar without moving the finger. onCurrentShiftUpdated(); @@ -922,6 +925,7 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>, // needs to be canceled mRecentsAnimationController.setWillFinishToHome(swipeUpThresholdPassed); + if (mActivity == null) return; if (swipeUpThresholdPassed) { mActivity.getSystemUiController().updateUiState(UI_STATE_FULLSCREEN_TASK, 0); } else { @@ -935,7 +939,7 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>, public void onRecentsAnimationStart(RecentsAnimationController controller, RecentsAnimationTargets targets) { super.onRecentsAnimationStart(controller, targets); - if (DesktopTaskView.DESKTOP_MODE_SUPPORTED && targets.hasDesktopTasks()) { + if (isDesktopModeSupported() && targets.hasDesktopTasks()) { mRemoteTargetHandles = mTargetGluer.assignTargetsForDesktop(targets); } else { int untrimmedAppCount = mRemoteTargetHandles.length; @@ -1161,7 +1165,7 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>, mStateCallback.setState(STATE_SCALED_CONTROLLER_HOME | STATE_CAPTURE_SCREENSHOT); // Notify the SysUI to use fade-in animation when entering PiP SystemUiProxy.INSTANCE.get(mContext).setPipAnimationTypeToAlpha(); - if (DesktopTaskView.DESKTOP_IS_PROTO2_ENABLED) { + if (isDesktopModeSupported()) { // Notify the SysUI to stash desktop apps if they are visible DesktopVisibilityController desktopVisibilityController = mActivityInterface.getDesktopVisibilityController(); @@ -1189,7 +1193,8 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>, break; } ActiveGestureLog.INSTANCE.addLog( - /* event= */ "onSettledOnEndTarget " + endTarget, + new ActiveGestureLog.CompoundString("onSettledOnEndTarget ") + .append(endTarget.name()), /* gestureEvent= */ ON_SETTLED_ON_END_TARGET); } @@ -1213,14 +1218,19 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>, private GestureEndTarget calculateEndTarget( PointF velocityPxPerMs, float endVelocityPxPerMs, boolean isFlingY, boolean isCancel) { + + ActiveGestureErrorDetector.GestureEvent gestureEvent = + velocityPxPerMs.x == 0 && velocityPxPerMs.y == 0 + ? INVALID_VELOCITY_ON_SWIPE_UP + : null; ActiveGestureLog.INSTANCE.addLog( new ActiveGestureLog.CompoundString("calculateEndTarget: velocities=(x=") - .append(Float.toString(dpiFromPx(velocityPxPerMs.x))) + .append(dpiFromPx(velocityPxPerMs.x)) .append("dp/ms, y=") - .append(Float.toString(dpiFromPx(velocityPxPerMs.y))) + .append(dpiFromPx(velocityPxPerMs.y)) .append("dp/ms), angle=") - .append(Double.toString(Math.toDegrees(Math.atan2( - -velocityPxPerMs.y, velocityPxPerMs.x))))); + .append(Math.toDegrees(Math.atan2( + -velocityPxPerMs.y, velocityPxPerMs.x))), gestureEvent); if (mGestureState.isHandlingAtomicEvent()) { // Button mode, this is only used to go to recents. @@ -1240,7 +1250,7 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>, return LAST_TASK; } - if (DesktopTaskView.DESKTOP_MODE_SUPPORTED && endTarget == NEW_TASK) { + if (isDesktopModeSupported() && endTarget == NEW_TASK) { // TODO(b/268075592): add support for quickswitch to/from desktop return LAST_TASK; } @@ -1257,8 +1267,8 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>, return isSwipeUp ? ALL_APPS : LAST_TASK; } if (!isSwipeUp) { - final boolean isCenteredOnNewTask = - mRecentsView.getDestinationPage() != mRecentsView.getRunningTaskIndex(); + final boolean isCenteredOnNewTask = mRecentsView != null + && mRecentsView.getDestinationPage() != mRecentsView.getRunningTaskIndex(); return willGoToNewTask || isCenteredOnNewTask ? NEW_TASK : LAST_TASK; } @@ -1491,7 +1501,9 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>, if (mGestureState.getEndTarget().isLauncher) { // This is also called when the launcher is resumed, in order to clear the pending // widgets that have yet to be configured. - DragView.removeAllViews(mActivity); + if (mActivity != null) { + DragView.removeAllViews(mActivity); + } TaskStackChangeListeners.getInstance().registerTaskStackListener( mActivityRestartListener); @@ -1534,11 +1546,13 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>, HomeAnimationFactory homeAnimFactory = createHomeAnimationFactory(cookies, duration, isTranslucent, appCanEnterPip, runningTaskTarget); - mIsSwipingPipToHome = !mIsSwipeForSplit && appCanEnterPip; + SwipePipToHomeAnimator swipePipToHomeAnimator = !mIsSwipeForSplit && appCanEnterPip + ? createWindowAnimationToPip(homeAnimFactory, runningTaskTarget, start) + : null; + mIsSwipingPipToHome = swipePipToHomeAnimator != null; final RectFSpringAnim[] windowAnim; if (mIsSwipingPipToHome) { - mSwipePipToHomeAnimator = createWindowAnimationToPip( - homeAnimFactory, runningTaskTarget, start); + mSwipePipToHomeAnimator = swipePipToHomeAnimator; mSwipePipToHomeAnimators[0] = mSwipePipToHomeAnimator; if (mSwipePipToHomeReleaseCheck != null) { mSwipePipToHomeReleaseCheck.setCanRelease(false); @@ -1546,6 +1560,9 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>, // grab a screenshot before the PipContentOverlay gets parented on top of the task UI_HELPER_EXECUTOR.execute(() -> { + if (mRecentsAnimationController == null) { + return; + } // Directly use top task, split to pip handled on shell side final int taskId = mGestureState.getTopRunningTaskId(); mTaskSnapshotCache.put(taskId, @@ -1663,6 +1680,10 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>, @Nullable private SwipePipToHomeAnimator createWindowAnimationToPip(HomeAnimationFactory homeAnimFactory, RemoteAnimationTarget runningTaskTarget, float startProgress) { + if (mRecentsView == null) { + // Overview was destroyed, bail early. + return null; + } // Directly animate the app to PiP (picture-in-picture) mode final ActivityManager.RunningTaskInfo taskInfo = runningTaskTarget.taskInfo; final RecentsOrientedState orientationState = mRemoteTargetHandles[0].getTaskViewSimulator() @@ -1803,7 +1824,8 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>, private void continueComputingRecentsScrollIfNecessary() { if (!mGestureState.hasState(STATE_RECENTS_SCROLLING_FINISHED) && !mStateCallback.hasStates(STATE_HANDLER_INVALIDATED) - && !mCanceled) { + && !mCanceled + && mRecentsView != null) { computeRecentsScrollIfInvisible(); mRecentsView.postOnAnimation(this::continueComputingRecentsScrollIfNecessary); } @@ -1844,12 +1866,9 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>, } public void onConsumerAboutToBeSwitched() { - if (mActivity != null) { - // In the off chance that the gesture ends before Launcher is started, we should clear - // the callback here so that it doesn't update with the wrong state - mActivity.clearRunOnceOnStartCallback(); - resetLauncherListeners(); - } + // In the off chance that the gesture ends before Launcher is started, we should clear + // the callback here so that it doesn't update with the wrong state + resetLauncherListeners(); if (mGestureState.isRecentsAnimationRunning() && mGestureState.getEndTarget() != null && !mGestureState.getEndTarget().isLauncher) { // Continued quick switch. @@ -1913,7 +1932,7 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>, private void reset() { mStateCallback.setStateOnUiThread(STATE_HANDLER_INVALIDATED); if (mActivity != null) { - mActivity.unregisterActivityLifecycleCallbacks(mLifecycleCallbacks); + mActivity.removeEventCallback(EVENT_DESTROYED, mLauncherOnDestroyCallback); } } @@ -1929,7 +1948,7 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>, mCurrentShift.cancelAnimation(); // Cleanup when switching handlers - mInputConsumerProxy.unregisterCallback(); + mInputConsumerProxy.unregisterOnTouchDownCallback(); mActivityInitListener.unregister(); TaskStackChangeListeners.getInstance().unregisterTaskStackListener( mActivityRestartListener); @@ -1941,7 +1960,7 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>, mInputConsumerProxy.destroy(); mTaskAnimationManager.setLiveTileCleanUpHandler(null); } - mInputConsumerProxy.unregisterCallback(); + mInputConsumerProxy.unregisterOnTouchDownCallback(); endRunningWindowAnim(false /* cancel */); if (mGestureEndCallback != null) { @@ -1984,8 +2003,12 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>, * continued quick switch gesture, which cancels the previous handler but doesn't invalidate it. */ private void resetLauncherListeners() { - mActivity.getRootView().setOnApplyWindowInsetsListener(null); + if (mActivity != null) { + mActivity.removeEventCallback(EVENT_STARTED, mLauncherOnStartCallback); + mActivity.removeEventCallback(EVENT_DESTROYED, mLauncherOnDestroyCallback); + mActivity.getRootView().setOnApplyWindowInsetsListener(null); + } if (mRecentsView != null) { mRecentsView.removeOnScrollChangedListener(mOnRecentsScrollListener); } @@ -2021,10 +2044,12 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>, // Update the screenshot of the task if (shouldUpdate) { UI_HELPER_EXECUTOR.execute(() -> { - if (mRecentsAnimationController == null) return; + RecentsAnimationController recentsAnimationController = + mRecentsAnimationController; + if (recentsAnimationController == null) return; for (int id : runningTaskIds) { mTaskSnapshotCache.put( - id, mRecentsAnimationController.screenshotTask(id)); + id, recentsAnimationController.screenshotTask(id)); } MAIN_EXECUTOR.execute(() -> { @@ -2077,18 +2102,9 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>, } private void finishCurrentTransitionToRecents() { - if (mRecentsView != null - && mActivityInterface.getDesktopVisibilityController() != null - && mActivityInterface.getDesktopVisibilityController().areFreeformTasksVisible()) { - mRecentsView.switchToScreenshot(() -> { - mRecentsView.finishRecentsAnimation(true /* toRecents */, false /* shouldPip */, - () -> mStateCallback.setStateOnUiThread(STATE_CURRENT_TASK_FINISHED)); - }); - } else { - mStateCallback.setStateOnUiThread(STATE_CURRENT_TASK_FINISHED); - if (mRecentsAnimationController != null) { - mRecentsAnimationController.detachNavigationBarFromApp(true); - } + mStateCallback.setStateOnUiThread(STATE_CURRENT_TASK_FINISHED); + if (mRecentsAnimationController != null) { + mRecentsAnimationController.detachNavigationBarFromApp(true); } } @@ -2114,7 +2130,7 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>, * from Launcher to WM. */ private void maybeAbortSwipePipToHome() { - if (mIsSwipingPipToHome && mSwipePipToHomeAnimators[0] != null) { + if (mIsSwipingPipToHome && mSwipePipToHomeAnimator != null) { SystemUiProxy.INSTANCE.get(mContext).abortSwipePipToHome( mSwipePipToHomeAnimator.getTaskId(), mSwipePipToHomeAnimator.getComponentName()); @@ -2128,7 +2144,10 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>, * This should happen before {@link #finishRecentsControllerToHome(Runnable)}. */ private void maybeFinishSwipePipToHome() { - if (mIsSwipingPipToHome && mSwipePipToHomeAnimators[0] != null) { + if (mRecentsAnimationController == null) { + return; + } + if (mIsSwipingPipToHome && mSwipePipToHomeAnimator != null) { mRecentsAnimationController.setFinishTaskTransaction( mSwipePipToHomeAnimator.getTaskId(), mSwipePipToHomeAnimator.getFinishTransaction(), @@ -2152,7 +2171,7 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>, protected abstract void finishRecentsControllerToHome(Runnable callback); private void setupLauncherUiAfterSwipeUpToRecentsAnimation() { - if (mStateCallback.hasStates(STATE_HANDLER_INVALIDATED)) { + if (mStateCallback.hasStates(STATE_HANDLER_INVALIDATED) || mRecentsView == null) { return; } endLauncherTransitionController(); @@ -2186,6 +2205,9 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>, } protected void linkRecentsViewScroll() { + if (mRecentsView == null) { + return; + } SurfaceTransactionApplier applier = new SurfaceTransactionApplier(mRecentsView); runActionOnRemoteHandles(remoteTargetHandle -> remoteTargetHandle.getTransformParams() .setSyncTransactionApplier(applier)); @@ -2193,9 +2215,13 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>, mRecentsAnimationTargets.addReleaseCheck(applier)); mRecentsView.addOnScrollChangedListener(mOnRecentsScrollListener); - runOnRecentsAnimationAndLauncherBound(() -> - mRecentsView.setRecentsAnimationTargets(mRecentsAnimationController, - mRecentsAnimationTargets)); + runOnRecentsAnimationAndLauncherBound(() -> { + if (mRecentsView == null) { + return; + } + mRecentsView.setRecentsAnimationTargets( + mRecentsAnimationController, mRecentsAnimationTargets); + }); // Disable scrolling in RecentsView for trackpad 3-finger swipe up gesture. if (!mGestureState.isThreeFingerTrackpadGesture()) { @@ -2215,7 +2241,8 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>, TaskView nextTask = mRecentsView == null ? null : mRecentsView.getNextPageTaskView(); if (nextTask != null) { int[] taskIds = nextTask.getTaskIds(); - StringBuilder nextTaskLog = new StringBuilder(); + ActiveGestureLog.CompoundString nextTaskLog = new ActiveGestureLog.CompoundString( + "Launching task: "); for (TaskIdAttributeContainer c : nextTask.getTaskIdAttributeContainers()) { if (c == null) { continue; @@ -2234,7 +2261,7 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>, if (!hasTaskPreviouslyAppeared) { ActiveGestureLog.INSTANCE.trackEvent(EXPECTING_TASK_APPEARED); } - ActiveGestureLog.INSTANCE.addLog("Launching task: " + nextTaskLog); + ActiveGestureLog.INSTANCE.addLog(nextTaskLog); nextTask.launchTask(success -> { resultCallback.accept(success); if (success) { @@ -2292,7 +2319,7 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>, } @Override - public void onRecentsAnimationFinished(RecentsAnimationController controller) { + public void onRecentsAnimationFinished(@NonNull RecentsAnimationController controller) { mRecentsAnimationController = null; mRecentsAnimationTargets = null; if (mRecentsView != null) { @@ -2301,77 +2328,95 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>, } @Override - public void onTasksAppeared(RemoteAnimationTarget[] appearedTaskTargets) { - if (mRecentsAnimationController != null) { - boolean hasStartedTaskBefore = Arrays.stream(appearedTaskTargets).anyMatch( - mGestureState.mLastStartedTaskIdPredicate); - if (!mStateCallback.hasStates(STATE_GESTURE_COMPLETED) && !hasStartedTaskBefore) { - // This is a special case, if a task is started mid-gesture that wasn't a part of a - // previous quickswitch task launch, then cancel the animation back to the app - RemoteAnimationTarget appearedTaskTarget = appearedTaskTargets[0]; - TaskInfo taskInfo = appearedTaskTarget.taskInfo; - ActiveGestureLog.INSTANCE.addLog("Unexpected task appeared" - + " id=" + taskInfo.taskId - + " pkg=" + taskInfo.baseIntent.getComponent().getPackageName()); - finishRecentsAnimationOnTasksAppeared(null /* onFinishComplete */); - } else if (handleTaskAppeared(appearedTaskTargets)) { - Optional<RemoteAnimationTarget> taskTargetOptional = - Arrays.stream(appearedTaskTargets) - .filter(mGestureState.mLastStartedTaskIdPredicate) - .findFirst(); - if (!taskTargetOptional.isPresent()) { - ActiveGestureLog.INSTANCE.addLog("No appeared task matching started task id"); - finishRecentsAnimationOnTasksAppeared(null /* onFinishComplete */); - return; - } - RemoteAnimationTarget taskTarget = taskTargetOptional.get(); - TaskView taskView = mRecentsView == null - ? null : mRecentsView.getTaskViewByTaskId(taskTarget.taskId); - if (taskView == null || !taskView.getThumbnail().shouldShowSplashView()) { - ActiveGestureLog.INSTANCE.addLog("Invalid task view splash state"); - finishRecentsAnimationOnTasksAppeared(null /* onFinishComplete */); - return; - } + public void onTasksAppeared(@NonNull RemoteAnimationTarget[] appearedTaskTargets) { + if (mRecentsAnimationController == null) { + return; + } + boolean hasStartedTaskBefore = Arrays.stream(appearedTaskTargets).anyMatch( + mGestureState.mLastStartedTaskIdPredicate); + if (!mStateCallback.hasStates(STATE_GESTURE_COMPLETED) && !hasStartedTaskBefore) { + // This is a special case, if a task is started mid-gesture that wasn't a part of a + // previous quickswitch task launch, then cancel the animation back to the app + RemoteAnimationTarget appearedTaskTarget = appearedTaskTargets[0]; + TaskInfo taskInfo = appearedTaskTarget.taskInfo; + ActiveGestureLog.INSTANCE.addLog( + new ActiveGestureLog.CompoundString("Unexpected task appeared") + .append(" id=") + .append(taskInfo.taskId) + .append(" pkg=") + .append(taskInfo.baseIntent.getComponent().getPackageName())); + finishRecentsAnimationOnTasksAppeared(null /* onFinishComplete */); + return; + } + if (!handleTaskAppeared(appearedTaskTargets)) { + return; + } + Optional<RemoteAnimationTarget> taskTargetOptional = + Arrays.stream(appearedTaskTargets) + .filter(mGestureState.mLastStartedTaskIdPredicate) + .findFirst(); + if (!taskTargetOptional.isPresent()) { + ActiveGestureLog.INSTANCE.addLog("No appeared task matching started task id"); + finishRecentsAnimationOnTasksAppeared(null /* onFinishComplete */); + return; + } + RemoteAnimationTarget taskTarget = taskTargetOptional.get(); + TaskView taskView = mRecentsView == null + ? null : mRecentsView.getTaskViewByTaskId(taskTarget.taskId); + if (taskView == null || !taskView.getThumbnail().shouldShowSplashView()) { + ActiveGestureLog.INSTANCE.addLog("Invalid task view splash state"); + finishRecentsAnimationOnTasksAppeared(null /* onFinishComplete */); + return; + } + if (mActivity == null) { + ActiveGestureLog.INSTANCE.addLog("Activity destroyed"); + finishRecentsAnimationOnTasksAppeared(null /* onFinishComplete */); + return; + } + animateSplashScreenExit(mActivity, appearedTaskTargets, taskTarget.leash); + } - ViewGroup splashView = mActivity.getDragLayer(); - final QuickstepLauncher quickstepLauncher = mActivity instanceof QuickstepLauncher - ? (QuickstepLauncher) mActivity : null; - if (quickstepLauncher != null) { - quickstepLauncher.getDepthController().pauseBlursOnWindows(true); - } + private void animateSplashScreenExit( + @NonNull T activity, + @NonNull RemoteAnimationTarget[] appearedTaskTargets, + @NonNull SurfaceControl leash) { + ViewGroup splashView = activity.getDragLayer(); + final QuickstepLauncher quickstepLauncher = activity instanceof QuickstepLauncher + ? (QuickstepLauncher) activity : null; + if (quickstepLauncher != null) { + quickstepLauncher.getDepthController().pauseBlursOnWindows(true); + } - // When revealing the app with launcher splash screen, make the app visible - // and behind the splash view before the splash is animated away. - SurfaceTransactionApplier surfaceApplier = - new SurfaceTransactionApplier(splashView); - SurfaceTransaction transaction = new SurfaceTransaction(); - for (RemoteAnimationTarget target : appearedTaskTargets) { - transaction.forSurface(target.leash).setAlpha(1).setLayer(-1).setShow(); - } - surfaceApplier.scheduleApply(transaction); - - SplashScreenExitAnimationUtils.startAnimations(splashView, taskTarget.leash, - mSplashMainWindowShiftLength, new TransactionPool(), new Rect(), - SPLASH_ANIMATION_DURATION, SPLASH_FADE_OUT_DURATION, - /* iconStartAlpha= */ 0, /* brandingStartAlpha= */ 0, - SPLASH_APP_REVEAL_DELAY, SPLASH_APP_REVEAL_DURATION, - new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - // Hiding launcher which shows the app surface behind, then - // finishing recents to the app. After transition finish, showing - // the views on launcher again, so it can be visible when next - // animation starts. - splashView.setAlpha(0); - if (quickstepLauncher != null) { - quickstepLauncher.getDepthController() - .pauseBlursOnWindows(false); - } - finishRecentsAnimationOnTasksAppeared(() -> splashView.setAlpha(1)); - } - }); - } + // When revealing the app with launcher splash screen, make the app visible + // and behind the splash view before the splash is animated away. + SurfaceTransactionApplier surfaceApplier = + new SurfaceTransactionApplier(splashView); + SurfaceTransaction transaction = new SurfaceTransaction(); + for (RemoteAnimationTarget target : appearedTaskTargets) { + transaction.forSurface(target.leash).setAlpha(1).setLayer(-1).setShow(); } + surfaceApplier.scheduleApply(transaction); + + SplashScreenExitAnimationUtils.startAnimations(splashView, leash, + mSplashMainWindowShiftLength, new TransactionPool(), new Rect(), + SPLASH_ANIMATION_DURATION, SPLASH_FADE_OUT_DURATION, + /* iconStartAlpha= */ 0, /* brandingStartAlpha= */ 0, + SPLASH_APP_REVEAL_DELAY, SPLASH_APP_REVEAL_DURATION, + new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + // Hiding launcher which shows the app surface behind, then + // finishing recents to the app. After transition finish, showing + // the views on launcher again, so it can be visible when next + // animation starts. + splashView.setAlpha(0); + if (quickstepLauncher != null) { + quickstepLauncher.getDepthController() + .pauseBlursOnWindows(false); + } + finishRecentsAnimationOnTasksAppeared(() -> splashView.setAlpha(1)); + } + }); } private void finishRecentsAnimationOnTasksAppeared(Runnable onFinishComplete) { |