From 8d9edd292bf4c302da69a776d603a7733d5acc82 Mon Sep 17 00:00:00 2001 From: Nicolo' Mazzucato Date: Mon, 6 Feb 2023 18:38:50 +0000 Subject: [PATCH] Drive Launcher unfold animation from System UI Before this cl, both Launcher and System UI processes were registering for hinge angle and device state (e.g. folded/unfolded) change events to calculate the current unfold animation progress. In some cases, launcher ui thread was busy, delaying the progress calculation from the hinge angle value (that was received ~at the same time by both processes). This resulted in launcher and sysui unfold animation not being synchronized in some cases. With this cl, System UI process uses OverviewProxyService to send the unfold events to Launcher. In this way, both process always have the exact same progress (+- 1 frame) This is currently guarded by a launcher flag, by default with the new behaviour, to allow devs to compare the experience and easily debug potential regressions. Bug: 268490854 Test: Analysed perfetto trace + RemoteUnfoldTransitionProgressProviderTest + manual Change-Id: If15fd6fe39abb3d922c5fdb327100206dfa3665d --- .../uioverrides/QuickstepLauncher.java | 101 +++++++++++++----- .../com/android/quickstep/SystemUiProxy.java | 31 +++++- .../quickstep/TouchInteractionService.java | 7 +- .../BaseUnfoldMoveFromCenterAnimator.java | 1 - .../launcher3/config/FeatureFlags.java | 5 + 5 files changed, 112 insertions(+), 33 deletions(-) diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java index 55378785d3..92008992d1 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java +++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java @@ -35,6 +35,7 @@ import static com.android.launcher3.compat.AccessibilityManagerCompat.sendCustom import static com.android.launcher3.config.FeatureFlags.ENABLE_SPLIT_FROM_WORKSPACE; import static com.android.launcher3.config.FeatureFlags.ENABLE_SPLIT_FROM_WORKSPACE_TO_WORKSPACE; import static com.android.launcher3.config.FeatureFlags.ENABLE_WIDGET_PICKER_DEPTH; +import static com.android.launcher3.config.FeatureFlags.RECEIVE_UNFOLD_EVENTS_FROM_SYSUI; import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_APP_LAUNCH_TAP; import static com.android.launcher3.model.data.ItemInfo.NO_MATCHING_ID; import static com.android.launcher3.popup.QuickstepSystemShortcut.getSplitSelectShortcutByPosition; @@ -166,11 +167,13 @@ import com.android.quickstep.views.RecentsView; import com.android.quickstep.views.TaskView; import com.android.systemui.shared.recents.model.Task; import com.android.systemui.shared.system.ActivityManagerWrapper; +import com.android.systemui.unfold.RemoteUnfoldSharedComponent; import com.android.systemui.unfold.UnfoldSharedComponent; import com.android.systemui.unfold.UnfoldTransitionFactory; import com.android.systemui.unfold.UnfoldTransitionProgressProvider; import com.android.systemui.unfold.config.ResourceUnfoldTransitionConfig; import com.android.systemui.unfold.config.UnfoldTransitionConfig; +import com.android.systemui.unfold.progress.RemoteUnfoldTransitionReceiver; import com.android.systemui.unfold.system.ActivityManagerActivityTypeProvider; import com.android.systemui.unfold.system.DeviceStateManagerFoldProvider; import com.android.systemui.unfold.updates.RotationChangeProvider; @@ -204,7 +207,6 @@ public class QuickstepLauncher extends Launcher { // Will be updated when dragging from taskbar. private @Nullable DragOptions mNextWorkspaceDragOptions = null; private @Nullable UnfoldTransitionProgressProvider mUnfoldTransitionProgressProvider; - private @Nullable RotationChangeProvider mRotationChangeProvider; private @Nullable LauncherUnfoldAnimationController mLauncherUnfoldAnimationController; private SplitSelectStateController mSplitSelectStateController; @@ -844,38 +846,79 @@ public class QuickstepLauncher extends Launcher { private void initUnfoldTransitionProgressProvider() { final UnfoldTransitionConfig config = new ResourceUnfoldTransitionConfig(); if (config.isEnabled()) { - UnfoldSharedComponent unfoldComponent = - UnfoldTransitionFactory.createUnfoldSharedComponent( - /* context= */ this, - config, - ProxyScreenStatusProvider.INSTANCE, - new DeviceStateManagerFoldProvider( - getSystemService(DeviceStateManager.class), /* context */this), - new ActivityManagerActivityTypeProvider( - getSystemService(ActivityManager.class)), - getSystemService(SensorManager.class), - getMainThreadHandler(), - getMainExecutor(), - /* backgroundExecutor= */ UI_HELPER_EXECUTOR, - /* tracingTagPrefix= */ "launcher", - WindowManagerGlobal.getWindowManagerService() - ); + if (RECEIVE_UNFOLD_EVENTS_FROM_SYSUI.get()) { + initRemotelyCalculatedUnfoldAnimation(config); + } else { + initLocallyCalculatedUnfoldAnimation(config); + } - mUnfoldTransitionProgressProvider = unfoldComponent.getUnfoldTransitionProvider() - .orElseThrow(() -> new IllegalStateException( - "Trying to create UnfoldTransitionProgressProvider when the " - + "transition is disabled")); - - mRotationChangeProvider = unfoldComponent.getRotationChangeProvider(); - mLauncherUnfoldAnimationController = new LauncherUnfoldAnimationController( - /* launcher= */ this, - getWindowManager(), - mUnfoldTransitionProgressProvider, - mRotationChangeProvider - ); } } + /** Registers hinge angle listener and calculates the animation progress in this process. */ + private void initLocallyCalculatedUnfoldAnimation(UnfoldTransitionConfig config) { + UnfoldSharedComponent unfoldComponent = + UnfoldTransitionFactory.createUnfoldSharedComponent( + /* context= */ this, + config, + ProxyScreenStatusProvider.INSTANCE, + new DeviceStateManagerFoldProvider( + getSystemService(DeviceStateManager.class), /* context= */ this), + new ActivityManagerActivityTypeProvider( + getSystemService(ActivityManager.class)), + getSystemService(SensorManager.class), + getMainThreadHandler(), + getMainExecutor(), + /* backgroundExecutor= */ UI_HELPER_EXECUTOR, + /* tracingTagPrefix= */ "launcher", + WindowManagerGlobal.getWindowManagerService() + ); + + mUnfoldTransitionProgressProvider = unfoldComponent.getUnfoldTransitionProvider() + .orElseThrow(() -> new IllegalStateException( + "Trying to create UnfoldTransitionProgressProvider when the " + + "transition is disabled")); + + initUnfoldAnimationController(mUnfoldTransitionProgressProvider, + unfoldComponent.getRotationChangeProvider()); + } + + /** Receives animation progress from sysui process. */ + private void initRemotelyCalculatedUnfoldAnimation(UnfoldTransitionConfig config) { + RemoteUnfoldSharedComponent unfoldComponent = + UnfoldTransitionFactory.createRemoteUnfoldSharedComponent( + /* context= */ this, + config, + getMainExecutor(), + /* backgroundExecutor= */ UI_HELPER_EXECUTOR, + /* tracingTagPrefix= */ "launcher", + WindowManagerGlobal.getWindowManagerService() + ); + + final RemoteUnfoldTransitionReceiver remoteUnfoldTransitionProgressProvider = + unfoldComponent.getRemoteTransitionProgress().orElseThrow( + () -> new IllegalStateException( + "Trying to create getRemoteTransitionProgress when the transition " + + "is disabled")); + mUnfoldTransitionProgressProvider = remoteUnfoldTransitionProgressProvider; + + SystemUiProxy.INSTANCE.get(this).setUnfoldAnimationListener( + remoteUnfoldTransitionProgressProvider); + + initUnfoldAnimationController(mUnfoldTransitionProgressProvider, + unfoldComponent.getRotationChangeProvider()); + } + + private void initUnfoldAnimationController(UnfoldTransitionProgressProvider progressProvider, + RotationChangeProvider rotationChangeProvider) { + mLauncherUnfoldAnimationController = new LauncherUnfoldAnimationController( + /* launcher= */ this, + getWindowManager(), + progressProvider, + rotationChangeProvider + ); + } + public void setTaskbarUIController(LauncherTaskbarUIController taskbarUIController) { mTaskbarUIController = taskbarUIController; } diff --git a/quickstep/src/com/android/quickstep/SystemUiProxy.java b/quickstep/src/com/android/quickstep/SystemUiProxy.java index 2200b35865..e46b365617 100644 --- a/quickstep/src/com/android/quickstep/SystemUiProxy.java +++ b/quickstep/src/com/android/quickstep/SystemUiProxy.java @@ -57,6 +57,8 @@ import com.android.systemui.shared.recents.ISystemUiProxy; 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.systemui.unfold.progress.IUnfoldAnimation; +import com.android.systemui.unfold.progress.IUnfoldTransitionListener; import com.android.wm.shell.back.IBackAnimation; import com.android.wm.shell.desktopmode.IDesktopMode; import com.android.wm.shell.onehanded.IOneHanded; @@ -96,6 +98,7 @@ public class SystemUiProxy implements ISystemUiProxy { private IRecentTasks mRecentTasks; private IBackAnimation mBackAnimation; private IDesktopMode mDesktopMode; + private IUnfoldAnimation mUnfoldAnimation; private final DeathRecipient mSystemUiProxyDeathRecipient = () -> { MAIN_EXECUTOR.execute(() -> clearProxy()); }; @@ -109,6 +112,7 @@ public class SystemUiProxy implements ISystemUiProxy { private IStartingWindowListener mStartingWindowListener; private ILauncherUnlockAnimationController mLauncherUnlockAnimationController; private IRecentTasksListener mRecentTasksListener; + private IUnfoldTransitionListener mUnfoldAnimationListener; private final LinkedHashMap mRemoteTransitions = new LinkedHashMap<>(); private IOnBackInvokedCallback mBackToLauncherCallback; @@ -171,7 +175,8 @@ public class SystemUiProxy implements ISystemUiProxy { IOneHanded oneHanded, IShellTransitions shellTransitions, IStartingWindow startingWindow, IRecentTasks recentTasks, ISysuiUnlockAnimationController sysuiUnlockAnimationController, - IBackAnimation backAnimation, IDesktopMode desktopMode) { + IBackAnimation backAnimation, IDesktopMode desktopMode, + IUnfoldAnimation unfoldAnimation) { unlinkToDeath(); mSystemUiProxy = proxy; mPip = pip; @@ -183,6 +188,7 @@ public class SystemUiProxy implements ISystemUiProxy { mRecentTasks = recentTasks; mBackAnimation = backAnimation; mDesktopMode = desktopMode; + mUnfoldAnimation = unfoldAnimation; linkToDeath(); // re-attach the listeners once missing due to setProxy has not been initialized yet. if (mPipAnimationListener != null && mPip != null) { @@ -204,10 +210,13 @@ public class SystemUiProxy implements ISystemUiProxy { if (mBackAnimation != null && mBackToLauncherCallback != null) { setBackToLauncherCallback(mBackToLauncherCallback); } + if (unfoldAnimation != null && mUnfoldAnimationListener != null) { + setUnfoldAnimationListener(mUnfoldAnimationListener); + } } public void clearProxy() { - setProxy(null, null, null, null, null, null, null, null, null, null); + setProxy(null, null, null, null, null, null, null, null, null, null, null); } // TODO(141886704): Find a way to remove this @@ -961,4 +970,22 @@ public class SystemUiProxy implements ISystemUiProxy { } return 0; } + + // + // Unfold transition + // + + /** Sets the unfold animation lister to sysui. */ + public void setUnfoldAnimationListener(IUnfoldTransitionListener callback) { + mUnfoldAnimationListener = callback; + if (mUnfoldAnimation == null) { + return; + } + try { + Log.d(TAG, "Registering unfold animation receiver"); + mUnfoldAnimation.setListener(callback); + } catch (RemoteException e) { + Log.e(TAG, "Failed call setUnfoldAnimationListener", e); + } + } } diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java index 687ed36677..287b468a4a 100644 --- a/quickstep/src/com/android/quickstep/TouchInteractionService.java +++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java @@ -28,6 +28,7 @@ import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.MOTION_UP; import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_RECENTS; import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SYSUI_PROXY; +import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_UNFOLD_ANIMATION_FORWARDER; import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_UNLOCK_ANIMATION_CONTROLLER; import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_FREEFORM_ACTIVE_IN_DESKTOP_MODE; import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED; @@ -114,6 +115,7 @@ import com.android.systemui.shared.system.InputConsumerController; import com.android.systemui.shared.system.InputMonitorCompat; import com.android.systemui.shared.system.smartspace.ISysuiUnlockAnimationController; import com.android.systemui.shared.tracing.ProtoTraceable; +import com.android.systemui.unfold.progress.IUnfoldAnimation; import com.android.wm.shell.back.IBackAnimation; import com.android.wm.shell.desktopmode.IDesktopMode; import com.android.wm.shell.onehanded.IOneHanded; @@ -174,10 +176,13 @@ public class TouchInteractionService extends Service bundle.getBinder(KEY_EXTRA_SHELL_BACK_ANIMATION)); IDesktopMode desktopMode = IDesktopMode.Stub.asInterface( bundle.getBinder(KEY_EXTRA_SHELL_DESKTOP_MODE)); + IUnfoldAnimation unfoldTransition = IUnfoldAnimation.Stub.asInterface( + bundle.getBinder(KEY_EXTRA_UNFOLD_ANIMATION_FORWARDER)); MAIN_EXECUTOR.execute(() -> { SystemUiProxy.INSTANCE.get(TouchInteractionService.this).setProxy(proxy, pip, splitscreen, onehanded, shellTransitions, startingWindow, - recentTasks, launcherUnlockAnimationController, backAnimation, desktopMode); + recentTasks, launcherUnlockAnimationController, backAnimation, desktopMode, + unfoldTransition); TouchInteractionService.this.initInputMonitor("TISBinder#onInitialize()"); preloadOverview(true /* fromInit */); }); diff --git a/quickstep/src/com/android/quickstep/util/BaseUnfoldMoveFromCenterAnimator.java b/quickstep/src/com/android/quickstep/util/BaseUnfoldMoveFromCenterAnimator.java index 2a513ee7ee..543ca897a2 100644 --- a/quickstep/src/com/android/quickstep/util/BaseUnfoldMoveFromCenterAnimator.java +++ b/quickstep/src/com/android/quickstep/util/BaseUnfoldMoveFromCenterAnimator.java @@ -56,7 +56,6 @@ public abstract class BaseUnfoldMoveFromCenterAnimator implements TransitionProg mAnimationInProgress = true; mMoveFromCenterAnimation.updateDisplayProperties(); onPrepareViewsForAnimation(); - onTransitionProgress(0f); mRotationChangeProvider.addCallback(mRotationListener); } diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java index ff0a867641..70f4fde1af 100644 --- a/src/com/android/launcher3/config/FeatureFlags.java +++ b/src/com/android/launcher3/config/FeatureFlags.java @@ -394,6 +394,11 @@ public final class FeatureFlags { "ENABLE_GRID_ONLY_OVERVIEW", false, "Enable a grid-only overview without a focused task."); + public static final BooleanFlag RECEIVE_UNFOLD_EVENTS_FROM_SYSUI = getDebugFlag( + "RECEIVE_UNFOLD_EVENTS_FROM_SYSUI", true, + "Enables receiving unfold animation events from sysui instead of calculating " + + "them in launcher process using hinge sensor values."); + public static void initialize(Context context) { synchronized (sDebugFlags) { for (DebugFlag flag : sDebugFlags) {