From 7dece749a329fa4984c90a68dbc0345586fa9e88 Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Wed, 19 Jan 2022 17:19:24 +0530 Subject: [PATCH 1/5] Updating logic to check if icon needs badging Bug: 209503720 Test: Manual Change-Id: I66f0dbaf81be3190a106323fe3ce87717626d8e7 --- .../com/android/quickstep/TaskIconCache.java | 22 +++++++++++++++---- .../launcher3/model/PackageUpdatedTask.java | 16 ++++++-------- src/com/android/launcher3/util/FlagOp.java | 16 -------------- 3 files changed, 25 insertions(+), 29 deletions(-) delete mode 100644 src/com/android/launcher3/util/FlagOp.java diff --git a/quickstep/src/com/android/quickstep/TaskIconCache.java b/quickstep/src/com/android/quickstep/TaskIconCache.java index b5d6fae73a..6c71da9a0e 100644 --- a/quickstep/src/com/android/quickstep/TaskIconCache.java +++ b/quickstep/src/com/android/quickstep/TaskIconCache.java @@ -28,6 +28,7 @@ import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.os.UserHandle; import android.text.TextUtils; +import android.util.SparseArray; import android.view.accessibility.AccessibilityManager; import androidx.annotation.WorkerThread; @@ -62,7 +63,9 @@ public class TaskIconCache implements DisplayInfoChangeListener { private final Context mContext; private final TaskKeyLruCache mIconCache; - private final BitmapInfo[] mDefaultIcons = new BitmapInfo[1]; + private final SparseArray mDefaultIcons = new SparseArray<>(); + private BitmapInfo mDefaultIconBase = null; + private final IconProvider mIconProvider; private BaseIconFactory mIconFactory; @@ -208,12 +211,23 @@ public class TaskIconCache implements DisplayInfoChangeListener { @WorkerThread private Drawable getDefaultIcon(int userId) { synchronized (mDefaultIcons) { - if (mDefaultIcons[0] == null) { + if (mDefaultIconBase == null) { try (BaseIconFactory bif = getIconFactory()) { - mDefaultIcons[0] = bif.makeDefaultIcon(); + mDefaultIconBase = bif.makeDefaultIcon(); + } + } + + int index; + if ((index = mDefaultIcons.indexOfKey(userId)) >= 0) { + return mDefaultIcons.valueAt(index).newIcon(mContext); + } else { + try (BaseIconFactory li = getIconFactory()) { + BitmapInfo info = mDefaultIconBase.withFlags( + li.getBitmapFlagOp(new IconOptions().setUser(UserHandle.of(userId)))); + mDefaultIcons.put(userId, info); + return info.newIcon(mContext); } } - return mDefaultIcons[0].clone().withUser(UserHandle.of(userId)).newIcon(mContext); } } diff --git a/src/com/android/launcher3/model/PackageUpdatedTask.java b/src/com/android/launcher3/model/PackageUpdatedTask.java index 83fb3d1582..d47edff223 100644 --- a/src/com/android/launcher3/model/PackageUpdatedTask.java +++ b/src/com/android/launcher3/model/PackageUpdatedTask.java @@ -112,7 +112,7 @@ public class PackageUpdatedTask extends BaseModelUpdateTask { activitiesLists.put( packages[i], appsList.addPackage(context, packages[i], mUser)); } - flagOp = FlagOp.removeFlag(WorkspaceItemInfo.FLAG_DISABLED_NOT_AVAILABLE); + flagOp = FlagOp.NO_OP.removeFlag(WorkspaceItemInfo.FLAG_DISABLED_NOT_AVAILABLE); break; } case OP_UPDATE: @@ -134,7 +134,7 @@ public class PackageUpdatedTask extends BaseModelUpdateTask { } } // Since package was just updated, the target must be available now. - flagOp = FlagOp.removeFlag(WorkspaceItemInfo.FLAG_DISABLED_NOT_AVAILABLE); + flagOp = FlagOp.NO_OP.removeFlag(WorkspaceItemInfo.FLAG_DISABLED_NOT_AVAILABLE); break; case OP_REMOVE: { for (int i = 0; i < N; i++) { @@ -148,13 +148,12 @@ public class PackageUpdatedTask extends BaseModelUpdateTask { if (DEBUG) Log.d(TAG, "mAllAppsList.removePackage " + packages[i]); appsList.removePackage(packages[i], mUser); } - flagOp = FlagOp.addFlag(WorkspaceItemInfo.FLAG_DISABLED_NOT_AVAILABLE); + flagOp = FlagOp.NO_OP.addFlag(WorkspaceItemInfo.FLAG_DISABLED_NOT_AVAILABLE); break; case OP_SUSPEND: case OP_UNSUSPEND: - flagOp = mOp == OP_SUSPEND ? - FlagOp.addFlag(WorkspaceItemInfo.FLAG_DISABLED_SUSPENDED) : - FlagOp.removeFlag(WorkspaceItemInfo.FLAG_DISABLED_SUSPENDED); + flagOp = FlagOp.NO_OP.setFlag( + WorkspaceItemInfo.FLAG_DISABLED_SUSPENDED, mOp == OP_SUSPEND); if (DEBUG) Log.d(TAG, "mAllAppsList.(un)suspend " + N); appsList.updateDisabledFlags(matcher, flagOp); break; @@ -162,9 +161,8 @@ public class PackageUpdatedTask extends BaseModelUpdateTask { UserManagerState ums = new UserManagerState(); ums.init(UserCache.INSTANCE.get(context), context.getSystemService(UserManager.class)); - flagOp = ums.isUserQuiet(mUser) - ? FlagOp.addFlag(WorkspaceItemInfo.FLAG_DISABLED_QUIET_USER) - : FlagOp.removeFlag(WorkspaceItemInfo.FLAG_DISABLED_QUIET_USER); + flagOp = FlagOp.NO_OP.setFlag( + WorkspaceItemInfo.FLAG_DISABLED_QUIET_USER, ums.isUserQuiet(mUser)); appsList.updateDisabledFlags(matcher, flagOp); // We are not synchronizing here, as int operations are atomic diff --git a/src/com/android/launcher3/util/FlagOp.java b/src/com/android/launcher3/util/FlagOp.java deleted file mode 100644 index bd40eb9fa8..0000000000 --- a/src/com/android/launcher3/util/FlagOp.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.android.launcher3.util; - -public interface FlagOp { - - FlagOp NO_OP = i -> i; - - int apply(int flags); - - static FlagOp addFlag(int flag) { - return i -> i | flag; - } - - static FlagOp removeFlag(int flag) { - return i -> i & ~flag; - } -} From 68c38e40c47ed3b9048308207314178a2e22e807 Mon Sep 17 00:00:00 2001 From: wilsonshih Date: Wed, 5 Jan 2022 16:59:50 +0800 Subject: [PATCH 2/5] Fix NPE crash when merge transition to remote transition. After enable shell transition, the opening/closing target is for the app. In legacy RecentsAnimationController, the mode of the new RemoteAnimationTarget is decide based on the recents activity type, so basically the mode for all non-home/recents activity is closing. So while create the recents window animator, the target apps will be filter out in RemoteAnimationTargets#ctor because the mode is changed. To make the remote animation targets compatible with shell transition, there should only need to check the opening apps as target. Also fix that the topMostSimulators can be null if the size of remoteTargetHandles is zero. Bug: 207297486 Test: Enable shell transition, run atest TaplTestsQuickstep#testQuickSwitchFromApp Test: Enable shell transition, enter recents, swipe to right-most page( the page shows "Clear all"), then click the task and verify Launcher won't crash. Test on both NexusLauncher and 3rd-party Launcher. Change-Id: I9bde3d7864d3edd54145c66acae0cd1013d89c6b --- quickstep/src/com/android/quickstep/TaskViewUtils.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/quickstep/src/com/android/quickstep/TaskViewUtils.java b/quickstep/src/com/android/quickstep/TaskViewUtils.java index 0a09e34754..db1d7e7ea9 100644 --- a/quickstep/src/com/android/quickstep/TaskViewUtils.java +++ b/quickstep/src/com/android/quickstep/TaskViewUtils.java @@ -36,6 +36,7 @@ import static com.android.launcher3.anim.Interpolators.TOUCH_RESPONSE_INTERPOLAT import static com.android.launcher3.anim.Interpolators.clampToProgress; import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE; import static com.android.launcher3.statehandlers.DepthController.DEPTH; +import static com.android.quickstep.TaskAnimationManager.ENABLE_SHELL_TRANSITIONS; import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_CLOSING; import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_OPENING; @@ -168,7 +169,7 @@ public final class TaskViewUtils { ENABLE_QUICKSTEP_LIVE_TILE.get() && v.getRecentsView().getRunningTaskIndex() != -1; final RemoteAnimationTargets targets = new RemoteAnimationTargets(appTargets, wallpaperTargets, nonAppTargets, - inLiveTileMode ? MODE_CLOSING : MODE_OPENING); + !ENABLE_SHELL_TRANSITIONS && inLiveTileMode ? MODE_CLOSING : MODE_OPENING); final RemoteAnimationTargetCompat navBarTarget = targets.getNavBarRemoteAnimationTarget(); SurfaceTransactionApplier applier = new SurfaceTransactionApplier(v); @@ -282,7 +283,8 @@ public final class TaskViewUtils { topMostSimulators = remoteTargetHandles; } - if (!skipViewChanges && parallaxCenterAndAdjacentTask && topMostSimulators.length > 0) { + if (!skipViewChanges && parallaxCenterAndAdjacentTask && topMostSimulators != null + && topMostSimulators.length > 0) { out.addFloat(v, VIEW_ALPHA, 1, 0, clampToProgress(LINEAR, 0.2f, 0.4f)); RemoteTargetHandle[] simulatorCopies = topMostSimulators; From 231c9229bf6a8793bfa843875792616525c6f376 Mon Sep 17 00:00:00 2001 From: Josh Tsuji Date: Tue, 11 Jan 2022 20:43:59 -0500 Subject: [PATCH 3/5] Adds Launcher in-window animations, and reworks how the unlock flow works. Bug: 197636887 Test: atest SystemUITests Change-Id: Idab7249e4a761040863578d546f0831794efaf4a --- .../com/android/quickstep/SystemUiProxy.java | 55 ++++++++++--- .../quickstep/TouchInteractionService.java | 12 +-- .../quickstep/util/WorkspaceUnlockAnim.java | 82 +++++++++++++++++++ src/com/android/launcher3/Launcher.java | 11 +++ src/com/android/launcher3/Workspace.java | 12 +++ .../statemanager/StatefulActivity.java | 2 +- 6 files changed, 155 insertions(+), 19 deletions(-) create mode 100644 quickstep/src/com/android/quickstep/util/WorkspaceUnlockAnim.java diff --git a/quickstep/src/com/android/quickstep/SystemUiProxy.java b/quickstep/src/com/android/quickstep/SystemUiProxy.java index b428b67aa0..22a30e92f6 100644 --- a/quickstep/src/com/android/quickstep/SystemUiProxy.java +++ b/quickstep/src/com/android/quickstep/SystemUiProxy.java @@ -44,8 +44,9 @@ import com.android.launcher3.util.SplitConfigurationOptions; import com.android.systemui.shared.recents.ISystemUiProxy; import com.android.systemui.shared.recents.model.Task; import com.android.systemui.shared.system.RemoteTransitionCompat; -import com.android.systemui.shared.system.smartspace.ISmartspaceCallback; -import com.android.systemui.shared.system.smartspace.ISmartspaceTransitionController; +import com.android.systemui.shared.system.smartspace.ILauncherUnlockAnimationController; +import com.android.systemui.shared.system.smartspace.ISysuiUnlockAnimationController; +import com.android.systemui.shared.system.smartspace.SmartspaceState; import com.android.wm.shell.onehanded.IOneHanded; import com.android.wm.shell.pip.IPip; import com.android.wm.shell.pip.IPipAnimationListener; @@ -73,7 +74,7 @@ public class SystemUiProxy implements ISystemUiProxy, private ISystemUiProxy mSystemUiProxy; private IPip mPip; - private ISmartspaceTransitionController mSmartspaceTransitionController; + private ISysuiUnlockAnimationController mSysuiUnlockAnimationController; private ISplitScreen mSplitScreen; private IOneHanded mOneHanded; private IShellTransitions mShellTransitions; @@ -90,7 +91,7 @@ public class SystemUiProxy implements ISystemUiProxy, private IPipAnimationListener mPipAnimationListener; private ISplitScreenListener mSplitScreenListener; private IStartingWindowListener mStartingWindowListener; - private ISmartspaceCallback mSmartspaceCallback; + private ILauncherUnlockAnimationController mPendingLauncherUnlockAnimationController; private IRecentTasksListener mRecentTasksListener; private final ArrayList mRemoteTransitions = new ArrayList<>(); @@ -157,7 +158,8 @@ public class SystemUiProxy implements ISystemUiProxy, public void setProxy(ISystemUiProxy proxy, IPip pip, ISplitScreen splitScreen, IOneHanded oneHanded, IShellTransitions shellTransitions, IStartingWindow startingWindow, IRecentTasks recentTasks, - ISmartspaceTransitionController smartSpaceTransitionController) { + ISysuiUnlockAnimationController sysuiUnlockAnimationController) { + unlinkToDeath(); mSystemUiProxy = proxy; mPip = pip; @@ -165,7 +167,7 @@ public class SystemUiProxy implements ISystemUiProxy, mOneHanded = oneHanded; mShellTransitions = shellTransitions; mStartingWindow = startingWindow; - mSmartspaceTransitionController = smartSpaceTransitionController; + mSysuiUnlockAnimationController = sysuiUnlockAnimationController; mRecentTasks = recentTasks; linkToDeath(); // re-attach the listeners once missing due to setProxy has not been initialized yet. @@ -178,8 +180,10 @@ public class SystemUiProxy implements ISystemUiProxy, if (mStartingWindowListener != null && mStartingWindow != null) { setStartingWindowListener(mStartingWindowListener); } - if (mSmartspaceCallback != null && mSmartspaceTransitionController != null) { - setSmartspaceCallback(mSmartspaceCallback); + if (mPendingLauncherUnlockAnimationController != null + && mSysuiUnlockAnimationController != null) { + setLauncherUnlockAnimationController(mPendingLauncherUnlockAnimationController); + mPendingLauncherUnlockAnimationController = null; } for (int i = mRemoteTransitions.size() - 1; i >= 0; --i) { registerRemoteTransition(mRemoteTransitions.get(i)); @@ -731,15 +735,42 @@ public class SystemUiProxy implements ISystemUiProxy, // SmartSpace transitions // - public void setSmartspaceCallback(ISmartspaceCallback callback) { - if (mSmartspaceTransitionController != null) { + /** + * Sets the instance of {@link ILauncherUnlockAnimationController} that System UI should use to + * control the launcher side of the unlock animation. This will also cause us to dispatch the + * current state of the smartspace to System UI (this will subsequently happen if the state + * changes). + */ + public void setLauncherUnlockAnimationController( + ILauncherUnlockAnimationController controller) { + if (mSysuiUnlockAnimationController != null) { try { - mSmartspaceTransitionController.setSmartspace(callback); + mSysuiUnlockAnimationController.setLauncherUnlockController(controller); + + if (controller != null) { + controller.dispatchSmartspaceStateToSysui(); + } } catch (RemoteException e) { Log.w(TAG, "Failed call setStartingWindowListener", e); } + } else { + mPendingLauncherUnlockAnimationController = controller; + } + } + + /** + * Tells System UI that the Launcher's smartspace state has been updated, so that it can prepare + * the unlock animation accordingly. + */ + public void notifySysuiSmartspaceStateUpdated(SmartspaceState state) { + if (mSysuiUnlockAnimationController != null) { + try { + mSysuiUnlockAnimationController.onLauncherSmartspaceStateUpdated(state); + } catch (RemoteException e) { + Log.w(TAG, "Failed call notifySysuiSmartspaceStateUpdated", e); + e.printStackTrace(); + } } - mSmartspaceCallback = callback; } // diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java index a3d48da4f7..42af12d662 100644 --- a/quickstep/src/com/android/quickstep/TouchInteractionService.java +++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java @@ -31,8 +31,8 @@ import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SHE import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SHELL_SHELL_TRANSITIONS; import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SHELL_SPLIT_SCREEN; import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SHELL_STARTING_WINDOW; -import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SMARTSPACE_TRANSITION_CONTROLLER; import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SYSUI_PROXY; +import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_UNLOCK_ANIMATION_CONTROLLER; import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED; import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_TRACING_ENABLED; @@ -105,7 +105,7 @@ import com.android.systemui.shared.system.ActivityManagerWrapper; import com.android.systemui.shared.system.InputChannelCompat.InputEventReceiver; import com.android.systemui.shared.system.InputConsumerController; import com.android.systemui.shared.system.InputMonitorCompat; -import com.android.systemui.shared.system.smartspace.ISmartspaceTransitionController; +import com.android.systemui.shared.system.smartspace.ISysuiUnlockAnimationController; import com.android.systemui.shared.tracing.ProtoTraceable; import com.android.wm.shell.onehanded.IOneHanded; import com.android.wm.shell.pip.IPip; @@ -162,15 +162,15 @@ public class TouchInteractionService extends Service bundle.getBinder(KEY_EXTRA_SHELL_SHELL_TRANSITIONS)); IStartingWindow startingWindow = IStartingWindow.Stub.asInterface( bundle.getBinder(KEY_EXTRA_SHELL_STARTING_WINDOW)); - ISmartspaceTransitionController smartspaceTransitionController = - ISmartspaceTransitionController.Stub.asInterface( - bundle.getBinder(KEY_EXTRA_SMARTSPACE_TRANSITION_CONTROLLER)); + ISysuiUnlockAnimationController launcherUnlockAnimationController = + ISysuiUnlockAnimationController.Stub.asInterface( + bundle.getBinder(KEY_EXTRA_UNLOCK_ANIMATION_CONTROLLER)); IRecentTasks recentTasks = IRecentTasks.Stub.asInterface( bundle.getBinder(KEY_EXTRA_RECENT_TASKS)); MAIN_EXECUTOR.execute(() -> { SystemUiProxy.INSTANCE.get(TouchInteractionService.this).setProxy(proxy, pip, splitscreen, onehanded, shellTransitions, startingWindow, recentTasks, - smartspaceTransitionController); + launcherUnlockAnimationController); TouchInteractionService.this.initInputMonitor(); preloadOverview(true /* fromInit */); }); diff --git a/quickstep/src/com/android/quickstep/util/WorkspaceUnlockAnim.java b/quickstep/src/com/android/quickstep/util/WorkspaceUnlockAnim.java new file mode 100644 index 0000000000..b01447ed27 --- /dev/null +++ b/quickstep/src/com/android/quickstep/util/WorkspaceUnlockAnim.java @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.quickstep.util; + +import com.android.launcher3.Launcher; +import com.android.launcher3.Utilities; + +/** + * Animation to animate in a workspace during the unlock transition. + */ +public class WorkspaceUnlockAnim { + /** Scale for the workspace icons at the beginning of the animation. */ + private static final float START_SCALE = 0.9f; + + /** + * Starting translation Y values for the animation. We use a larger value if we're animating in + * from a swipe, since there is more perceived upward movement when we unlock from a swipe. + */ + private static final int START_TRANSLATION_DP = 15; + private static final int START_TRANSLATION_SWIPE_DP = 60; + + private Launcher mLauncher; + private float mUnlockAmount = 0f; + + public WorkspaceUnlockAnim(Launcher launcher) { + mLauncher = launcher; + } + + /** + * Called when we're about to make the Launcher window visible and play the unlock animation. + * + * This is a blocking call so that System UI knows it's safe to show the Launcher window without + * causing the Launcher contents to flicker on screen. Do not do anything expensive here. + */ + public void prepareForUnlock() { + mLauncher.getWorkspace().setAlpha(0f); + mLauncher.getHotseat().setAlpha(0f); + + mUnlockAmount = 0f; + } + + public void setUnlockAmount(float amount, boolean fromSwipe) { + mUnlockAmount = amount; + + final float amountInverse = 1f - amount; + final float scale = START_SCALE + (1f - START_SCALE) * amount; + + mLauncher.getWorkspace().setScaleX(scale); + mLauncher.getWorkspace().setScaleY(scale); + mLauncher.getWorkspace().setAlpha(amount); + mLauncher.getWorkspace().setPivotToScaleWithSelf(mLauncher.getHotseat()); + + mLauncher.getHotseat().setScaleX(scale); + mLauncher.getHotseat().setScaleY(scale); + mLauncher.getHotseat().setAlpha(amount); + + if (fromSwipe) { + mLauncher.getWorkspace().setTranslationY( + Utilities.dpToPx(START_TRANSLATION_SWIPE_DP) * amountInverse); + mLauncher.getHotseat().setTranslationY( + Utilities.dpToPx(START_TRANSLATION_SWIPE_DP) * amountInverse); + } else { + mLauncher.getWorkspace().setTranslationY( + Utilities.dpToPx(START_TRANSLATION_DP) * amountInverse); + mLauncher.getHotseat().setTranslationY( + Utilities.dpToPx(START_TRANSLATION_DP) * amountInverse); + } + } +} diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java index bed4fa958b..700e042c41 100644 --- a/src/com/android/launcher3/Launcher.java +++ b/src/com/android/launcher3/Launcher.java @@ -2786,6 +2786,17 @@ public class Launcher extends StatefulActivity implements Launche getDragLayer().announceForAccessibility(getString(stringResId)); } + /** + * Informs us that the overlay (-1 screen, typically), has either become visible or invisible. + */ + public void onOverlayVisibilityChanged(boolean visible) {} + + /** + * Informs us that the page transition has ended, so that we can react to the newly selected + * page if we want to. + */ + public void onPageEndTransition() {} + /** * Add the icons for all apps. * diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java index 65006ff87f..b3ff38fff1 100644 --- a/src/com/android/launcher3/Workspace.java +++ b/src/com/android/launcher3/Workspace.java @@ -1135,6 +1135,10 @@ public class Workspace extends PagedView stripEmptyScreens(); mStripScreensOnPageStopMoving = false; } + + // Inform the Launcher activity that the page transition ended so that it can react to the + // newly visible page if it wants to. + mLauncher.onPageEndTransition(); } public void setLauncherOverlay(LauncherOverlay overlay) { @@ -1211,6 +1215,10 @@ public class Workspace extends PagedView .log(LAUNCHER_SWIPELEFT); } mOverlayShown = true; + + // Let the Launcher activity know that the overlay is now visible. + mLauncher.onOverlayVisibilityChanged(mOverlayShown); + // Not announcing the overlay page for accessibility since it announces itself. } else if (Float.compare(scroll, 0f) == 0) { if (mOverlayShown) { @@ -1234,6 +1242,10 @@ public class Workspace extends PagedView announcePageForAccessibility(); } mOverlayShown = false; + + // Let the Launcher activity know that the overlay is no longer visible. + mLauncher.onOverlayVisibilityChanged(mOverlayShown); + tryRunOverlayCallback(); } diff --git a/src/com/android/launcher3/statemanager/StatefulActivity.java b/src/com/android/launcher3/statemanager/StatefulActivity.java index e03694321e..b45c97b6e2 100644 --- a/src/com/android/launcher3/statemanager/StatefulActivity.java +++ b/src/com/android/launcher3/statemanager/StatefulActivity.java @@ -152,7 +152,7 @@ public abstract class StatefulActivity> /** * Called if the Activity UI changed while the activity was not visible */ - protected void onUiChangedWhileSleeping() { } + public void onUiChangedWhileSleeping() { } private void handleDeferredResume() { if (hasBeenResumed() && !getStateManager().getState().hasFlag(FLAG_NON_INTERACTIVE)) { From 3f40a17e5472fb191fe4f79bca10688cde701200 Mon Sep 17 00:00:00 2001 From: Winson Chung Date: Fri, 21 Jan 2022 06:17:10 +0000 Subject: [PATCH 4/5] Add fallback for missing remote animation callbacks - In some cases WM won't callback the remote animation callbacks (neither start nor cancel) and Launcher never finishes executing the pending command (preventing the subsequent commands from running). For the time being, just cancel the current state to allow the commands to be processed. Bug: 194011186 Test: Mash on overview and home buttons with a 3p launcher Signed-off-by: Winson Chung Change-Id: I1b1296fab316b979f441ebb474d1475e3fa68f95 --- .../quickstep/OverviewCommandHelper.java | 9 +++++++++ .../android/quickstep/RecentsActivity.java | 19 +++++++++++++++++++ .../quickstep/TouchInteractionService.java | 3 +++ 3 files changed, 31 insertions(+) diff --git a/quickstep/src/com/android/quickstep/OverviewCommandHelper.java b/quickstep/src/com/android/quickstep/OverviewCommandHelper.java index 75e8dd1f7a..17baa3ad91 100644 --- a/quickstep/src/com/android/quickstep/OverviewCommandHelper.java +++ b/quickstep/src/com/android/quickstep/OverviewCommandHelper.java @@ -38,6 +38,7 @@ import com.android.quickstep.views.TaskView; import com.android.systemui.shared.recents.model.ThumbnailData; import com.android.systemui.shared.system.InteractionJankMonitorWrapper; +import java.io.PrintWriter; import java.util.ArrayList; import java.util.HashMap; @@ -271,6 +272,14 @@ public class OverviewCommandHelper { scheduleNextTask(cmd); } + public void dump(PrintWriter pw) { + pw.println("OverviewCommandHelper:"); + pw.println(" mPendingCommands=" + mPendingCommands.size()); + if (!mPendingCommands.isEmpty()) { + pw.println(" pendingCommandType=" + mPendingCommands.get(0).type); + } + } + private static class CommandInfo { public final long createTime = SystemClock.elapsedRealtime(); public final int type; diff --git a/quickstep/src/com/android/quickstep/RecentsActivity.java b/quickstep/src/com/android/quickstep/RecentsActivity.java index 3e0027947d..db92e339cd 100644 --- a/quickstep/src/com/android/quickstep/RecentsActivity.java +++ b/quickstep/src/com/android/quickstep/RecentsActivity.java @@ -100,6 +100,7 @@ public final class RecentsActivity extends StatefulActivity { private Handler mUiHandler = new Handler(Looper.getMainLooper()); private static final long HOME_APPEAR_DURATION = 250; + private static final long RECENTS_ANIMATION_TIMEOUT = 1000; private RecentsDragLayer mDragLayer; private ScrimView mScrimView; @@ -116,6 +117,11 @@ public final class RecentsActivity extends StatefulActivity { // Strong refs to runners which are cleared when the activity is destroyed private RemoteAnimationFactory mActivityLaunchAnimationRunner; + // For handling degenerate cases where starting an activity doesn't actually trigger the remote + // animation callback + private final Handler mHandler = new Handler(); + private final Runnable mAnimationStartTimeoutRunnable = this::onAnimationStartTimeout; + /** * Init drag layer and overview panel views. */ @@ -220,6 +226,16 @@ public final class RecentsActivity extends StatefulActivity { // TODO(b/137318995) This should go home, but doing so removes freeform windows } + /** + * Called if the remote animation callback from #getActivityLaunchOptions() hasn't called back + * in a reasonable time due to a conflict with the recents animation. + */ + private void onAnimationStartTimeout() { + if (mActivityLaunchAnimationRunner != null) { + mActivityLaunchAnimationRunner.onAnimationCancelled(); + } + } + @Override public ActivityOptionsWrapper getActivityLaunchOptions(final View v, @Nullable ItemInfo item) { if (!(v instanceof TaskView)) { @@ -234,6 +250,7 @@ public final class RecentsActivity extends StatefulActivity { public void onCreateAnimation(int transit, RemoteAnimationTargetCompat[] appTargets, RemoteAnimationTargetCompat[] wallpaperTargets, RemoteAnimationTargetCompat[] nonAppTargets, AnimationResult result) { + mHandler.removeCallbacks(mAnimationStartTimeoutRunnable); AnimatorSet anim = composeRecentsLaunchAnimator(taskView, appTargets, wallpaperTargets, nonAppTargets); anim.addListener(resetStateListener()); @@ -243,6 +260,7 @@ public final class RecentsActivity extends StatefulActivity { @Override public void onAnimationCancelled() { + mHandler.removeCallbacks(mAnimationStartTimeoutRunnable); onEndCallback.executeAllAndDestroy(); } }; @@ -260,6 +278,7 @@ public final class RecentsActivity extends StatefulActivity { activityOptions.options.setLaunchDisplayId( (v != null && v.getDisplay() != null) ? v.getDisplay().getDisplayId() : Display.DEFAULT_DISPLAY); + mHandler.postDelayed(mAnimationStartTimeoutRunnable, RECENTS_ANIMATION_TIMEOUT); return activityOptions; } diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java index a3d48da4f7..d09a5d4def 100644 --- a/quickstep/src/com/android/quickstep/TouchInteractionService.java +++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java @@ -942,6 +942,9 @@ public class TouchInteractionService extends Service if (mOverviewComponentObserver != null) { mOverviewComponentObserver.dump(pw); } + if (mOverviewCommandHelper != null) { + mOverviewCommandHelper.dump(pw); + } if (mGestureState != null) { mGestureState.dump(pw); } From 1a9ef839883b0832ef6d2c577cba419c01698666 Mon Sep 17 00:00:00 2001 From: Alex Chau Date: Mon, 24 Jan 2022 15:16:24 +0000 Subject: [PATCH 5/5] Add ScreenRecord for a flaky test Bug: 215672979 Test: none Change-Id: I3bfd0275a4d551c0b6d614a7a76d696f14ce3ca3 --- .../com/android/launcher3/ui/widget/AddConfigWidgetTest.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/src/com/android/launcher3/ui/widget/AddConfigWidgetTest.java b/tests/src/com/android/launcher3/ui/widget/AddConfigWidgetTest.java index 2c9785c93d..4740097f36 100644 --- a/tests/src/com/android/launcher3/ui/widget/AddConfigWidgetTest.java +++ b/tests/src/com/android/launcher3/ui/widget/AddConfigWidgetTest.java @@ -33,6 +33,7 @@ import com.android.launcher3.tapl.Widgets; import com.android.launcher3.testcomponent.WidgetConfigActivity; import com.android.launcher3.ui.AbstractLauncherUiTest; import com.android.launcher3.ui.TestViewHelpers; +import com.android.launcher3.util.rule.ScreenRecordRule.ScreenRecord; import com.android.launcher3.util.rule.ShellCommandRule; import com.android.launcher3.widget.LauncherAppWidgetProviderInfo; @@ -72,6 +73,7 @@ public class AddConfigWidgetTest extends AbstractLauncherUiTest { @Test @PortraitLandscape + @ScreenRecord // b/215672979 public void testConfigCancelled() throws Throwable { runTest(false); }