Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8d9edd29 authored by Nicolo' Mazzucato's avatar Nicolo' Mazzucato
Browse files

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
parent 2e16aa87
Loading
Loading
Loading
Loading
+73 −30
Original line number Diff line number Diff line
@@ -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,13 +846,24 @@ public class QuickstepLauncher extends Launcher {
    private void initUnfoldTransitionProgressProvider() {
        final UnfoldTransitionConfig config = new ResourceUnfoldTransitionConfig();
        if (config.isEnabled()) {
            if (RECEIVE_UNFOLD_EVENTS_FROM_SYSUI.get()) {
                initRemotelyCalculatedUnfoldAnimation(config);
            } else {
                initLocallyCalculatedUnfoldAnimation(config);
            }

        }
    }

    /** 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),
                                getSystemService(DeviceStateManager.class), /* context= */ this),
                        new ActivityManagerActivityTypeProvider(
                                getSystemService(ActivityManager.class)),
                        getSystemService(SensorManager.class),
@@ -866,15 +879,45 @@ public class QuickstepLauncher extends Launcher {
                        "Trying to create UnfoldTransitionProgressProvider when the "
                                + "transition is disabled"));

            mRotationChangeProvider = unfoldComponent.getRotationChangeProvider();
        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(),
                    mUnfoldTransitionProgressProvider,
                    mRotationChangeProvider
                progressProvider,
                rotationChangeProvider
        );
    }
    }

    public void setTaskbarUIController(LauncherTaskbarUIController taskbarUIController) {
        mTaskbarUIController = taskbarUIController;
+29 −2
Original line number Diff line number Diff line
@@ -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<RemoteTransition, TransitionFilter> 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);
        }
    }
}
+6 −1
Original line number Diff line number Diff line
@@ -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 */);
            });
+0 −1
Original line number Diff line number Diff line
@@ -56,7 +56,6 @@ public abstract class BaseUnfoldMoveFromCenterAnimator implements TransitionProg
        mAnimationInProgress = true;
        mMoveFromCenterAnimation.updateDisplayProperties();
        onPrepareViewsForAnimation();
        onTransitionProgress(0f);
        mRotationChangeProvider.addCallback(mRotationListener);
    }

+5 −0
Original line number Diff line number Diff line
@@ -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) {