diff options
Diffstat (limited to 'quickstep/src')
12 files changed, 207 insertions, 47 deletions
diff --git a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java index a3e8b5ccfd..ca30e72609 100644 --- a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java +++ b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java @@ -19,6 +19,7 @@ import static com.android.launcher3.taskbar.TaskbarLauncherStateController.FLAG_ import static com.android.systemui.shared.system.WindowManagerWrapper.ITYPE_EXTRA_NAVIGATION_BAR; import android.animation.Animator; +import android.animation.AnimatorSet; import android.annotation.ColorInt; import android.os.RemoteException; import android.util.Log; @@ -28,6 +29,7 @@ import android.view.TaskTransitionSpec; import android.view.WindowManagerGlobal; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; import com.android.launcher3.BaseQuickstepLauncher; @@ -140,6 +142,24 @@ public class LauncherTaskbarUIController extends TaskbarUIController { } /** + * Adds the Launcher resume animator to the given animator set. + * + * This should be used to run a Launcher resume animation whose progress matches a + * swipe progress. + * + * @param placeholderDuration a placeholder duration to be used to ensure all full-length + * sub-animations are properly coordinated. This duration should not + * actually be used since this animation tracks a swipe progress. + */ + protected void addLauncherResumeAnimation(AnimatorSet animation, int placeholderDuration) { + animation.play(onLauncherResumedOrPaused( + /* isResumed= */ true, + /* fromInit= */ false, + /* startAnimation= */ false, + placeholderDuration)); + } + + /** * Should be called from onResume() and onPause(), and animates the Taskbar accordingly. */ public void onLauncherResumedOrPaused(boolean isResumed) { @@ -147,9 +167,19 @@ public class LauncherTaskbarUIController extends TaskbarUIController { } private void onLauncherResumedOrPaused(boolean isResumed, boolean fromInit) { + onLauncherResumedOrPaused( + isResumed, + fromInit, + /* startAnimation= */ true, + QuickstepTransitionManager.CONTENT_ALPHA_DURATION); + } + + @Nullable + private Animator onLauncherResumedOrPaused( + boolean isResumed, boolean fromInit, boolean startAnimation, int duration) { if (mKeyguardController.isScreenOff()) { if (!isResumed) { - return; + return null; } else { // Resuming implicitly means device unlocked mKeyguardController.setScreenOn(); @@ -157,8 +187,7 @@ public class LauncherTaskbarUIController extends TaskbarUIController { } mTaskbarLauncherStateController.updateStateForFlag(FLAG_RESUMED, isResumed); - mTaskbarLauncherStateController.applyState( - fromInit ? 0 : QuickstepTransitionManager.CONTENT_ALPHA_DURATION); + return mTaskbarLauncherStateController.applyState(fromInit ? 0 : duration, startAnimation); } /** diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java index 2f322199f3..ed1001cead 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java @@ -29,6 +29,7 @@ import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_N import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_QUICK_SETTINGS_EXPANDED; import android.animation.AnimatorSet; +import android.animation.ValueAnimator; import android.app.ActivityOptions; import android.content.ActivityNotFoundException; import android.content.Context; @@ -60,6 +61,8 @@ import com.android.launcher3.BubbleTextView; import com.android.launcher3.DeviceProfile; import com.android.launcher3.LauncherSettings.Favorites; import com.android.launcher3.R; +import com.android.launcher3.anim.AnimatorPlaybackController; +import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.dot.DotInfo; import com.android.launcher3.folder.Folder; import com.android.launcher3.folder.FolderIcon; @@ -735,6 +738,45 @@ public class TaskbarActivityContext extends BaseTaskbarContext { } /** + * Displays a single frame of the Launcher start from SUW animation. + * + * This animation is a combination of the Launcher resume animation, which animates the hotseat + * icons into position, the Taskbar unstash to hotseat animation, which animates the Taskbar + * stash bar into the hotseat icons, and an override to prevent showing the Taskbar all apps + * button. + * + * This should be used to run a Taskbar unstash to hotseat animation whose progress matches a + * swipe progress. + * + * @param duration a placeholder duration to be used to ensure all full-length + * sub-animations are properly coordinated. This duration should not actually + * be used since this animation tracks a swipe progress. + */ + protected AnimatorPlaybackController createLauncherStartFromSuwAnim(int duration) { + AnimatorSet fullAnimation = new AnimatorSet(); + fullAnimation.setDuration(duration); + + TaskbarUIController uiController = mControllers.uiController; + if (uiController instanceof LauncherTaskbarUIController) { + ((LauncherTaskbarUIController) uiController).addLauncherResumeAnimation( + fullAnimation, duration); + } + mControllers.taskbarStashController.addUnstashToHotseatAnimation(fullAnimation, duration); + + if (!FeatureFlags.ENABLE_ALL_APPS_BUTTON_IN_HOTSEAT.get()) { + ValueAnimator alphaOverride = ValueAnimator.ofFloat(0, 1); + alphaOverride.setDuration(duration); + alphaOverride.addUpdateListener(a -> { + // Override the alpha updates in the icon alignment animation. + mControllers.taskbarViewController.getAllAppsButtonView().setAlpha(0); + }); + fullAnimation.play(alphaOverride); + } + + return AnimatorPlaybackController.wrap(fullAnimation, duration); + } + + /** * Called when we determine the touchable region. * * @param exclude {@code true} then the magnification region computation will omit the window. diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt index 9870a2e0bf..21d7af9d69 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt @@ -16,10 +16,11 @@ package com.android.launcher3.taskbar import android.graphics.Insets +import android.graphics.Region +import android.view.InsetsState.ITYPE_BOTTOM_MANDATORY_GESTURES import android.view.WindowManager import com.android.launcher3.AbstractFloatingView import com.android.launcher3.AbstractFloatingView.TYPE_TASKBAR_ALL_APPS -import com.android.launcher3.R import com.android.launcher3.anim.AlphaUpdateListener import com.android.launcher3.taskbar.TaskbarControllers.LoggableTaskbarController import com.android.quickstep.KtR @@ -36,6 +37,7 @@ class TaskbarInsetsController(val context: TaskbarActivityContext): LoggableTask /** The bottom insets taskbar provides to the IME when IME is visible. */ val taskbarHeightForIme: Int = context.resources.getDimensionPixelSize( KtR.dimen.taskbar_ime_size) + private val contentRegion: Region = Region() // Initialized in init. private lateinit var controllers: TaskbarControllers @@ -50,7 +52,8 @@ class TaskbarInsetsController(val context: TaskbarActivityContext): LoggableTask windowLayoutParams, intArrayOf( ITYPE_EXTRA_NAVIGATION_BAR, - ITYPE_BOTTOM_TAPPABLE_ELEMENT + ITYPE_BOTTOM_TAPPABLE_ELEMENT, + ITYPE_BOTTOM_MANDATORY_GESTURES ) ) @@ -67,14 +70,20 @@ class TaskbarInsetsController(val context: TaskbarActivityContext): LoggableTask fun onTaskbarWindowHeightOrInsetsChanged() { var reducingSize = getReducingInsetsForTaskbarInsetsHeight( controllers.taskbarStashController.contentHeightToReportToApps) + + contentRegion.set(0, reducingSize.top, + context.dragLayer.width, windowLayoutParams.height) windowLayoutParams.providedInternalInsets[ITYPE_EXTRA_NAVIGATION_BAR] = reducingSize + windowLayoutParams.providedInternalInsets[ITYPE_BOTTOM_MANDATORY_GESTURES] = reducingSize reducingSize = getReducingInsetsForTaskbarInsetsHeight( controllers.taskbarStashController.tappableHeightToReportToApps) windowLayoutParams.providedInternalInsets[ITYPE_BOTTOM_TAPPABLE_ELEMENT] = reducingSize + windowLayoutParams.providedInternalInsets[ITYPE_BOTTOM_MANDATORY_GESTURES] = reducingSize reducingSize = getReducingInsetsForTaskbarInsetsHeight(taskbarHeightForIme) windowLayoutParams.providedInternalImeInsets[ITYPE_EXTRA_NAVIGATION_BAR] = reducingSize windowLayoutParams.providedInternalImeInsets[ITYPE_BOTTOM_TAPPABLE_ELEMENT] = reducingSize + windowLayoutParams.providedInternalImeInsets[ITYPE_BOTTOM_MANDATORY_GESTURES] = reducingSize } /** @@ -121,7 +130,8 @@ class TaskbarInsetsController(val context: TaskbarActivityContext): LoggableTask if (context.isTaskbarWindowFullscreen) { InsetsInfo.TOUCHABLE_INSETS_FRAME } else { - InsetsInfo.TOUCHABLE_INSETS_CONTENT + insetsInfo.touchableRegion.set(contentRegion) + InsetsInfo.TOUCHABLE_INSETS_REGION } ) insetsIsTouchableRegion = false diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java index 2e37170952..ef7bab9832 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java @@ -39,6 +39,7 @@ import androidx.annotation.Nullable; import com.android.launcher3.BaseQuickstepLauncher; import com.android.launcher3.DeviceProfile; import com.android.launcher3.LauncherAppState; +import com.android.launcher3.anim.AnimatorPlaybackController; import com.android.launcher3.statemanager.StatefulActivity; import com.android.launcher3.taskbar.unfold.NonDestroyableScopedUnfoldTransitionProgressProvider; import com.android.launcher3.util.DisplayController; @@ -183,6 +184,17 @@ public class TaskbarManager { } /** + * Displays a frame of the first Launcher reveal animation. + * + * This should be used to run a first Launcher reveal animation whose progress matches a swipe + * progress. + */ + public AnimatorPlaybackController createLauncherStartFromSuwAnim(int duration) { + return mTaskbarActivityContext == null + ? null : mTaskbarActivityContext.createLauncherStartFromSuwAnim(duration); + } + + /** * Called when the user is unlocked */ public void onUserUnlocked() { diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java index 7d95743bc9..fc9f9d002b 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java @@ -35,6 +35,8 @@ import android.view.WindowInsets; import com.android.launcher3.DeviceProfile; import com.android.launcher3.Utilities; +import com.android.launcher3.anim.AnimatorListeners; +import com.android.launcher3.taskbar.allapps.TaskbarAllAppsSlideInView; import com.android.launcher3.testing.TestProtocol; import com.android.launcher3.util.MultiValueAlpha.AlphaProperty; import com.android.quickstep.AnimatedFloat; @@ -368,12 +370,33 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba } /** + * Adds the Taskbar unstash to Hotseat animator to the animator set. + * + * This should be used to run a Taskbar unstash to Hotseat animation whose progress matches a + * swipe progress. + * + * @param placeholderDuration a placeholder duration to be used to ensure all full-length + * sub-animations are properly coordinated. This duration should not + * actually be used since this animation tracks a swipe progress. + */ + protected void addUnstashToHotseatAnimation(AnimatorSet animation, int placeholderDuration) { + createAnimToIsStashed( + /* isStashed= */ false, + placeholderDuration, + /* startDelay= */ 0, + /* animateBg= */ false); + animation.play(mAnimator); + } + + /** * Create a stash animation and save to {@link #mAnimator}. * @param isStashed whether it's a stash animation or an unstash animation * @param duration duration of the animation * @param startDelay how many milliseconds to delay the animation after starting it. + * @param animateBg whether the taskbar's background should be animated */ - private void createAnimToIsStashed(boolean isStashed, long duration, long startDelay) { + private void createAnimToIsStashed( + boolean isStashed, long duration, long startDelay, boolean animateBg) { if (mAnimator != null) { mAnimator.cancel(); } @@ -408,10 +431,14 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba secondHalfDurationScale = 0.5f; final float stashTranslation = (mUnstashedHeight - mStashedHeight) / 2f; - fullLengthAnimatorSet.playTogether( - mTaskbarBackgroundOffset.animateToValue(1), - mIconTranslationYForStash.animateToValue(stashTranslation) - ); + fullLengthAnimatorSet.play(mIconTranslationYForStash.animateToValue(stashTranslation)); + if (animateBg) { + fullLengthAnimatorSet.play(mTaskbarBackgroundOffset.animateToValue(1)); + } else { + fullLengthAnimatorSet.addListener(AnimatorListeners.forEndCallback( + () -> mTaskbarBackgroundOffset.updateValue(1))); + } + firstHalfAnimatorSet.playTogether( mIconAlphaForStash.animateToValue(0), mIconScaleForStash.animateToValue(STASHED_TASKBAR_SCALE) @@ -424,10 +451,15 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba secondHalfDurationScale = 0.75f; fullLengthAnimatorSet.playTogether( - mTaskbarBackgroundOffset.animateToValue(0), mIconScaleForStash.animateToValue(1), - mIconTranslationYForStash.animateToValue(0) - ); + mIconTranslationYForStash.animateToValue(0)); + if (animateBg) { + fullLengthAnimatorSet.play(mTaskbarBackgroundOffset.animateToValue(0)); + } else { + fullLengthAnimatorSet.addListener(AnimatorListeners.forEndCallback( + () -> mTaskbarBackgroundOffset.updateValue(0))); + } + firstHalfAnimatorSet.playTogether( mTaskbarStashedHandleAlpha.animateToValue(0) ); @@ -728,7 +760,7 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba mIsStashed = isStashed; // This sets mAnimator. - createAnimToIsStashed(mIsStashed, duration, startDelay); + createAnimToIsStashed(mIsStashed, duration, startDelay, /* animateBg= */ true); if (start) { mAnimator.start(); } diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java index 5db495db43..3dd7932a9a 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java @@ -258,21 +258,21 @@ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbar setter.addOnFrameListener(anim -> mActivity.setTaskbarWindowHeight( anim.getAnimatedFraction() > 0 ? expandedHeight : collapsedHeight)); - int count = mTaskbarView.getChildCount(); - for (int i = 0; i < count; i++) { + for (int i = 0; i < mTaskbarView.getChildCount(); i++) { View child = mTaskbarView.getChildAt(i); - int positionInHotseat = -1; - boolean isRtl = Utilities.isRtl(child.getResources()); + int positionInHotseat; if (FeatureFlags.ENABLE_ALL_APPS_IN_TASKBAR.get() - && ((isRtl && i == 0) || (!isRtl && i == count - 1))) { + && child == mTaskbarView.getAllAppsButtonView()) { // Note that there is no All Apps button in the hotseat, this position is only used // as its convenient for animation purposes. - positionInHotseat = isRtl + positionInHotseat = Utilities.isRtl(child.getResources()) ? -1 : mActivity.getDeviceProfile().numShownHotseatIcons; - setter.setViewAlpha(child, 0, LINEAR); + if (!FeatureFlags.ENABLE_ALL_APPS_BUTTON_IN_HOTSEAT.get()) { + setter.setViewAlpha(child, 0, LINEAR); + } } else if (child.getTag() instanceof ItemInfo) { positionInHotseat = ((ItemInfo) child.getTag()).screenId; } else { diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java index f60b2253e4..21728ad9cb 100644 --- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java +++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java @@ -151,6 +151,7 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>, // Null if the recents animation hasn't started yet or has been canceled or finished. protected @Nullable RecentsAnimationController mRecentsAnimationController; + protected @Nullable RecentsAnimationController mDeferredCleanupRecentsAnimationController; protected RecentsAnimationTargets mRecentsAnimationTargets; protected T mActivity; protected Q mRecentsView; @@ -435,6 +436,9 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>, mRecentsView.switchToScreenshot(snapshots, () -> { if (mRecentsAnimationController != null) { mRecentsAnimationController.cleanupScreenshot(); + } else if (mDeferredCleanupRecentsAnimationController != null) { + mDeferredCleanupRecentsAnimationController.cleanupScreenshot(); + mDeferredCleanupRecentsAnimationController = null; } }); mRecentsView.onRecentsAnimationComplete(); @@ -839,6 +843,9 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>, public void onRecentsAnimationCanceled(HashMap<Integer, ThumbnailData> thumbnailDatas) { ActiveGestureLog.INSTANCE.addLog("cancelRecentsAnimation"); mActivityInitListener.unregister(); + // Cache the recents animation controller so we can defer its cleanup to after having + // properly cleaned up the screenshot without accidentally using it. + mDeferredCleanupRecentsAnimationController = mRecentsAnimationController; mStateCallback.setStateOnUiThread(STATE_GESTURE_CANCELLED | STATE_HANDLER_INVALIDATED); if (mRecentsAnimationTargets != null) { @@ -1025,19 +1032,19 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>, return RECENTS; } final GestureEndTarget endTarget; - final boolean canGoToNewTask; + final boolean goingToNewTask; if (mRecentsView != null) { 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 - canGoToNewTask = true; + goingToNewTask = true; } else { final int runningTaskIndex = mRecentsView.getRunningTaskIndex(); final int taskToLaunch = mRecentsView.getNextPage(); - canGoToNewTask = runningTaskIndex >= 0 && taskToLaunch != runningTaskIndex; + goingToNewTask = runningTaskIndex >= 0 && taskToLaunch != runningTaskIndex; } } else { - canGoToNewTask = false; + goingToNewTask = false; } final boolean reachedOverviewThreshold = mCurrentShift.value >= MIN_PROGRESS_FOR_OVERVIEW; final boolean isFlingX = Math.abs(velocity.x) > mContext.getResources() @@ -1046,13 +1053,13 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>, if (isCancel) { endTarget = LAST_TASK; } else if (mDeviceState.isFullyGesturalNavMode()) { - if (canGoToNewTask && isFlingX) { + if (goingToNewTask && isFlingX) { // Flinging towards new task takes precedence over mIsMotionPaused (which only // checks y-velocity). endTarget = NEW_TASK; } else if (mIsMotionPaused) { endTarget = RECENTS; - } else if (canGoToNewTask) { + } else if (goingToNewTask) { endTarget = NEW_TASK; } else { endTarget = !reachedOverviewThreshold ? LAST_TASK : HOME; @@ -1060,22 +1067,26 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>, } else { endTarget = reachedOverviewThreshold && mGestureStarted ? RECENTS - : canGoToNewTask + : goingToNewTask ? NEW_TASK : LAST_TASK; } } else { // If swiping at a diagonal, base end target on the faster velocity. boolean isSwipeUp = endVelocity < 0; - boolean willGoToNewTask = - canGoToNewTask && Math.abs(velocity.x) > Math.abs(endVelocity); - - if (mDeviceState.isFullyGesturalNavMode() && isSwipeUp) { - endTarget = willGoToNewTask ? NEW_TASK : HOME; + boolean willGoToNewTaskOnSwipeUp = + goingToNewTask && Math.abs(velocity.x) > Math.abs(endVelocity); + + if (mDeviceState.isFullyGesturalNavMode() && isSwipeUp && !willGoToNewTaskOnSwipeUp) { + endTarget = HOME; + } else if (mDeviceState.isFullyGesturalNavMode() && isSwipeUp) { + // If swiping at a diagonal, base end target on the faster velocity. + endTarget = NEW_TASK; } else if (isSwipeUp) { - endTarget = (!reachedOverviewThreshold && willGoToNewTask) ? NEW_TASK : RECENTS; + endTarget = !reachedOverviewThreshold && willGoToNewTaskOnSwipeUp + ? NEW_TASK : RECENTS; } else { - endTarget = willGoToNewTask ? NEW_TASK : LAST_TASK; // Swipe is downward. + endTarget = goingToNewTask ? NEW_TASK : LAST_TASK; } } @@ -1160,8 +1171,6 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>, duration = Math.max(duration, mRecentsView.getScroller().getDuration()); } } - } else if (endTarget == LAST_TASK && mRecentsView != null) { - mRecentsView.snapToPage(mRecentsView.getCurrentPage(), Math.toIntExact(duration)); } // Let RecentsView handle the scrolling to the task, which we launch in startNewTask() diff --git a/quickstep/src/com/android/quickstep/TopTaskTracker.java b/quickstep/src/com/android/quickstep/TopTaskTracker.java index 80bc329620..39c5f2ad98 100644 --- a/quickstep/src/com/android/quickstep/TopTaskTracker.java +++ b/quickstep/src/com/android/quickstep/TopTaskTracker.java @@ -25,6 +25,7 @@ import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.ACT import android.app.ActivityManager.RunningTaskInfo; import android.content.Context; +import androidx.annotation.Nullable; import androidx.annotation.UiThread; import com.android.launcher3.util.MainThreadInitializedObject; @@ -183,30 +184,31 @@ public class TopTaskTracker extends ISplitScreenListener.Stub implements TaskSta */ public static class CachedTaskInfo { + @Nullable private final RunningTaskInfo mTopTask; private final List<RunningTaskInfo> mAllCachedTasks; CachedTaskInfo(List<RunningTaskInfo> allCachedTasks) { mAllCachedTasks = allCachedTasks; - mTopTask = allCachedTasks.get(0); + mTopTask = allCachedTasks.isEmpty() ? null : allCachedTasks.get(0); } public int getTaskId() { - return mTopTask.taskId; + return mTopTask == null ? -1 : mTopTask.taskId; } /** * Returns true if the root of the task chooser activity */ public boolean isRootChooseActivity() { - return ACTION_CHOOSER.equals(mTopTask.baseIntent.getAction()); + return mTopTask != null && ACTION_CHOOSER.equals(mTopTask.baseIntent.getAction()); } /** * Returns true if the given task holds an Assistant activity that is excluded from recents */ public boolean isExcludedAssistant() { - return mTopTask.configuration.windowConfiguration + return mTopTask != null && mTopTask.configuration.windowConfiguration .getActivityType() == ACTIVITY_TYPE_ASSISTANT && (mTopTask.baseIntent.getFlags() & FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) != 0; } @@ -215,7 +217,7 @@ public class TopTaskTracker extends ISplitScreenListener.Stub implements TaskSta * Returns true if this represents the HOME task */ public boolean isHomeTask() { - return mTopTask.configuration.windowConfiguration + return mTopTask != null && mTopTask.configuration.windowConfiguration .getActivityType() == ACTIVITY_TYPE_HOME; } @@ -224,7 +226,8 @@ public class TopTaskTracker extends ISplitScreenListener.Stub implements TaskSta * is loaded by the model */ public Task[] getPlaceholderTasks() { - return new Task[] {Task.from(new TaskKey(mTopTask), mTopTask, false)}; + return mTopTask == null ? new Task[0] + : new Task[] {Task.from(new TaskKey(mTopTask), mTopTask, false)}; } /** @@ -232,6 +235,9 @@ public class TopTaskTracker extends ISplitScreenListener.Stub implements TaskSta * placeholder until the true object is loaded by the model */ public Task[] getPlaceholderTasks(int[] taskIds) { + if (mTopTask == null) { + return new Task[0]; + } Task[] result = new Task[taskIds.length]; for (int i = 0; i < taskIds.length; i++) { final int index = i; diff --git a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java index 3e68c7f304..ab3201a27e 100644 --- a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java +++ b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java @@ -56,6 +56,7 @@ import java.util.ArrayList; public class FallbackRecentsView extends RecentsView<RecentsActivity, RecentsState> implements StateListener<RecentsState> { + @Nullable private Task mHomeTask; public FallbackRecentsView(Context context, AttributeSet attrs) { @@ -89,7 +90,7 @@ public class FallbackRecentsView extends RecentsView<RecentsActivity, RecentsSta RotationTouchHelper rotationTouchHelper) { // TODO(b/195607777) General fallback love, but this might be correct // Home task should be defined as the front-most task info I think? - mHomeTask = homeTask[0]; + mHomeTask = homeTask.length > 0 ? homeTask[0] : null; onGestureAnimationStart(homeTask, rotationTouchHelper); } diff --git a/quickstep/src/com/android/quickstep/interaction/AllSetActivity.java b/quickstep/src/com/android/quickstep/interaction/AllSetActivity.java index 269b3c2268..a379aada4a 100644 --- a/quickstep/src/com/android/quickstep/interaction/AllSetActivity.java +++ b/quickstep/src/com/android/quickstep/interaction/AllSetActivity.java @@ -17,6 +17,7 @@ package com.android.quickstep.interaction; import static com.android.launcher3.Utilities.mapBoundToRange; import static com.android.launcher3.Utilities.mapRange; +import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN; import static com.android.launcher3.anim.Interpolators.LINEAR; import android.animation.Animator; @@ -54,6 +55,7 @@ import androidx.core.graphics.ColorUtils; import com.android.launcher3.InvariantDeviceProfile; import com.android.launcher3.R; import com.android.launcher3.Utilities; +import com.android.launcher3.anim.AnimatorPlaybackController; import com.android.launcher3.util.Executors; import com.android.quickstep.AnimatedFloat; import com.android.quickstep.GestureState; @@ -78,6 +80,8 @@ public class AllSetActivity extends Activity { private static final float HINT_BOTTOM_FACTOR = 1 - .94f; + private static final int MAX_SWIPE_DURATION = 350; + private TISBindHelper mTISBindHelper; private TISBinder mBinder; @@ -90,6 +94,8 @@ public class AllSetActivity extends Activity { private LottieAnimationView mAnimatedBackground; private Animator.AnimatorListener mBackgroundAnimatorListener; + private AnimatorPlaybackController mLauncherStartAnim = null; + @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -237,11 +243,20 @@ public class AllSetActivity extends Activity { private void onSwipeProgressUpdate() { mBackground.setProgress(mSwipeProgress.value); - float alpha = Utilities.mapBoundToRange(mSwipeProgress.value, 0, HINT_BOTTOM_FACTOR, - 1, 0, LINEAR); + float alpha = Utilities.mapBoundToRange( + mSwipeProgress.value, 0, HINT_BOTTOM_FACTOR, 1, 0, LINEAR); mContentView.setAlpha(alpha); mContentView.setTranslationY((alpha - 1) * mSwipeUpShift); + if (mLauncherStartAnim == null) { + mLauncherStartAnim = mBinder.getTaskbarManager().createLauncherStartFromSuwAnim( + MAX_SWIPE_DURATION); + } + if (mLauncherStartAnim != null) { + mLauncherStartAnim.setPlayFraction(Utilities.mapBoundToRange( + mSwipeProgress.value, 0, 1, 0, 1, FAST_OUT_SLOW_IN)); + } + if (alpha == 0f) { mAnimatedBackground.pauseAnimation(); } else if (!mAnimatedBackground.isAnimating()) { diff --git a/quickstep/src/com/android/quickstep/util/SurfaceTransactionApplier.java b/quickstep/src/com/android/quickstep/util/SurfaceTransactionApplier.java index 3b1c150563..4757d4bc7d 100644 --- a/quickstep/src/com/android/quickstep/util/SurfaceTransactionApplier.java +++ b/quickstep/src/com/android/quickstep/util/SurfaceTransactionApplier.java @@ -53,6 +53,7 @@ public class SurfaceTransactionApplier extends ReleaseCheck { mTargetViewRootImpl = targetView.getViewRootImpl(); mBarrierSurfaceControl = mTargetViewRootImpl.getSurfaceControl(); mApplyHandler = new Handler(this::onApplyMessage); + setCanRelease(true); } protected boolean onApplyMessage(Message msg) { diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java index b6345180a3..2360396cf7 100644 --- a/quickstep/src/com/android/quickstep/views/RecentsView.java +++ b/quickstep/src/com/android/quickstep/views/RecentsView.java @@ -2257,6 +2257,9 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T * is called. Also scrolls the view to this task. */ private void showCurrentTask(Task[] runningTasks) { + if (runningTasks.length == 0) { + return; + } int runningTaskViewId = -1; boolean needGroupTaskView = runningTasks.length > 1; if (shouldAddStubTaskView(runningTasks)) { |