summaryrefslogtreecommitdiff
path: root/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
diff options
context:
space:
mode:
Diffstat (limited to 'quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java')
-rw-r--r--quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java327
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) {