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

Commit 010ce715 authored by Jerry Chang's avatar Jerry Chang
Browse files

Consolidate animation to show divider bar

Add a fade-in animation for showing the divider bar. And make sure it
animates in-sync with task bar by deferring the fade-in animation until
keyguard dismissed.

When quickswitch or overview switch back to a split pair, the launch
split tasks remote animation will get onAnimationCancelled due to the
app transition was handled by recent animation controller. So leaves
divider bar fade-in animation to launcher when the remote animation got
cancelled.

Fix: 229613465
Fix: 208651526
Test: atest WMShellUnitTests
Test: launch a split pair and a fullscreen app, switch from overview or
      quickswitch back and forth between split pair and the fullscreen
      app. Observed divider bar animates in in-sync with task views.
Test: verified divider bar animates in-sync with task bar after keyguard
      dismissed.
Change-Id: I2f9064a089c446711545afda8204557a708545c5
parent e266bac2
Loading
Loading
Loading
Loading
+2 −0
Original line number Original line Diff line number Diff line
@@ -40,6 +40,8 @@ public enum ShellProtoLogGroup implements IProtoLogGroup {
            Consts.TAG_WM_SHELL),
            Consts.TAG_WM_SHELL),
    WM_SHELL_PICTURE_IN_PICTURE(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG,
    WM_SHELL_PICTURE_IN_PICTURE(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG,
            false, Consts.TAG_WM_SHELL),
            false, Consts.TAG_WM_SHELL),
    WM_SHELL_SPLIT_SCREEN(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false,
            Consts.TAG_WM_SHELL),
    TEST_GROUP(true, true, false, "WindowManagerShellProtoLogTest");
    TEST_GROUP(true, true, false, "WindowManagerShellProtoLogTest");


    private final boolean mEnabled;
    private final boolean mEnabled;
+90 −24
Original line number Original line Diff line number Diff line
@@ -54,6 +54,9 @@ import static com.android.wm.shell.transition.Transitions.TRANSIT_SPLIT_SCREEN_P
import static com.android.wm.shell.transition.Transitions.isClosingType;
import static com.android.wm.shell.transition.Transitions.isClosingType;
import static com.android.wm.shell.transition.Transitions.isOpeningType;
import static com.android.wm.shell.transition.Transitions.isOpeningType;


import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.annotation.CallSuper;
import android.annotation.CallSuper;
import android.annotation.NonNull;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.Nullable;
@@ -68,6 +71,7 @@ import android.content.res.Configuration;
import android.graphics.Rect;
import android.graphics.Rect;
import android.hardware.devicestate.DeviceStateManager;
import android.hardware.devicestate.DeviceStateManager;
import android.os.Bundle;
import android.os.Bundle;
import android.os.Debug;
import android.os.IBinder;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.RemoteException;
import android.util.Log;
import android.util.Log;
@@ -147,7 +151,9 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,


    private final int mDisplayId;
    private final int mDisplayId;
    private SplitLayout mSplitLayout;
    private SplitLayout mSplitLayout;
    private ValueAnimator mDividerFadeInAnimator;
    private boolean mDividerVisible;
    private boolean mDividerVisible;
    private boolean mKeyguardShowing;
    private final SyncTransactionQueue mSyncQueue;
    private final SyncTransactionQueue mSyncQueue;
    private final ShellTaskOrganizer mTaskOrganizer;
    private final ShellTaskOrganizer mTaskOrganizer;
    private final Context mContext;
    private final Context mContext;
@@ -404,6 +410,7 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
        mSplitLayout.init();
        mSplitLayout.init();
        // Set false to avoid record new bounds with old task still on top;
        // Set false to avoid record new bounds with old task still on top;
        mShouldUpdateRecents = false;
        mShouldUpdateRecents = false;
        mIsDividerRemoteAnimating = true;
        final WindowContainerTransaction wct = new WindowContainerTransaction();
        final WindowContainerTransaction wct = new WindowContainerTransaction();
        final WindowContainerTransaction evictWct = new WindowContainerTransaction();
        final WindowContainerTransaction evictWct = new WindowContainerTransaction();
        prepareEvictChildTasks(SPLIT_POSITION_TOP_OR_LEFT, evictWct);
        prepareEvictChildTasks(SPLIT_POSITION_TOP_OR_LEFT, evictWct);
@@ -417,7 +424,6 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
                    RemoteAnimationTarget[] wallpapers,
                    RemoteAnimationTarget[] wallpapers,
                    RemoteAnimationTarget[] nonApps,
                    RemoteAnimationTarget[] nonApps,
                    final IRemoteAnimationFinishedCallback finishedCallback) {
                    final IRemoteAnimationFinishedCallback finishedCallback) {
                mIsDividerRemoteAnimating = true;
                RemoteAnimationTarget[] augmentedNonApps =
                RemoteAnimationTarget[] augmentedNonApps =
                        new RemoteAnimationTarget[nonApps.length + 1];
                        new RemoteAnimationTarget[nonApps.length + 1];
                for (int i = 0; i < nonApps.length; ++i) {
                for (int i = 0; i < nonApps.length; ++i) {
@@ -494,8 +500,10 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
        }
        }
        // Using legacy transitions, so we can't use blast sync since it conflicts.
        // Using legacy transitions, so we can't use blast sync since it conflicts.
        mTaskOrganizer.applyTransaction(wct);
        mTaskOrganizer.applyTransaction(wct);
        mSyncQueue.runInSync(t ->
        mSyncQueue.runInSync(t -> {
                updateSurfaceBounds(mSplitLayout, t, false /* applyResizingOffset */));
            setDividerVisibility(true, t);
            updateSurfaceBounds(mSplitLayout, t, false /* applyResizingOffset */);
        });
    }
    }


    private void onRemoteAnimationFinishedOrCancelled(WindowContainerTransaction evictWct) {
    private void onRemoteAnimationFinishedOrCancelled(WindowContainerTransaction evictWct) {
@@ -510,10 +518,6 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
                        ? mSideStage : mMainStage, EXIT_REASON_UNKNOWN));
                        ? mSideStage : mMainStage, EXIT_REASON_UNKNOWN));
        } else {
        } else {
            mSyncQueue.queue(evictWct);
            mSyncQueue.queue(evictWct);
            mSyncQueue.runInSync(t -> {
                setDividerVisibility(true, t);
                updateSurfaceBounds(mSplitLayout, t, false /* applyResizingOffset */);
            });
        }
        }
    }
    }


@@ -623,16 +627,12 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
    }
    }


    void onKeyguardVisibilityChanged(boolean showing) {
    void onKeyguardVisibilityChanged(boolean showing) {
        mKeyguardShowing = showing;
        if (!mMainStage.isActive()) {
        if (!mMainStage.isActive()) {
            return;
            return;
        }
        }


        if (ENABLE_SHELL_TRANSITIONS) {
        if (!mKeyguardShowing && mTopStageAfterFoldDismiss != STAGE_TYPE_UNDEFINED) {
            // Update divider visibility so it won't float on top of keyguard.
            setDividerVisibility(!showing, null /* transaction */);
        }

        if (!showing && mTopStageAfterFoldDismiss != STAGE_TYPE_UNDEFINED) {
            if (ENABLE_SHELL_TRANSITIONS) {
            if (ENABLE_SHELL_TRANSITIONS) {
                final WindowContainerTransaction wct = new WindowContainerTransaction();
                final WindowContainerTransaction wct = new WindowContainerTransaction();
                prepareExitSplitScreen(mTopStageAfterFoldDismiss, wct);
                prepareExitSplitScreen(mTopStageAfterFoldDismiss, wct);
@@ -643,7 +643,10 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
                        mTopStageAfterFoldDismiss == STAGE_TYPE_MAIN ? mMainStage : mSideStage,
                        mTopStageAfterFoldDismiss == STAGE_TYPE_MAIN ? mMainStage : mSideStage,
                        EXIT_REASON_DEVICE_FOLDED);
                        EXIT_REASON_DEVICE_FOLDED);
            }
            }
            return;
        }
        }

        setDividerVisibility(!mKeyguardShowing, null);
    }
    }


    void onFinishedWakingUp() {
    void onFinishedWakingUp() {
@@ -727,6 +730,7 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
            setResizingSplits(false /* resizing */);
            setResizingSplits(false /* resizing */);
            t.setWindowCrop(mMainStage.mRootLeash, null)
            t.setWindowCrop(mMainStage.mRootLeash, null)
                    .setWindowCrop(mSideStage.mRootLeash, null);
                    .setWindowCrop(mSideStage.mRootLeash, null);
            setDividerVisibility(false, t);
        });
        });


        // Hide divider and reset its position.
        // Hide divider and reset its position.
@@ -1055,8 +1059,31 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
    }
    }


    private void setDividerVisibility(boolean visible, @Nullable SurfaceControl.Transaction t) {
    private void setDividerVisibility(boolean visible, @Nullable SurfaceControl.Transaction t) {
        if (visible == mDividerVisible) {
            return;
        }

        ProtoLog.d(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN,
                "%s: Request to %s divider bar from %s.", TAG,
                (visible ? "show" : "hide"), Debug.getCaller());

        // Defer showing divider bar after keyguard dismissed, so it won't interfere with keyguard
        // dismissing animation.
        if (visible && mKeyguardShowing) {
            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN,
                    "%s:   Defer showing divider bar due to keyguard showing.", TAG);
            return;
        }

        mDividerVisible = visible;
        mDividerVisible = visible;
        sendSplitVisibilityChanged();
        sendSplitVisibilityChanged();

        if (mIsDividerRemoteAnimating) {
            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN,
                    "%s:   Skip animating divider bar due to it's remote animating.", TAG);
            return;
        }

        if (t != null) {
        if (t != null) {
            applyDividerVisibility(t);
            applyDividerVisibility(t);
        } else {
        } else {
@@ -1066,15 +1093,56 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,


    private void applyDividerVisibility(SurfaceControl.Transaction t) {
    private void applyDividerVisibility(SurfaceControl.Transaction t) {
        final SurfaceControl dividerLeash = mSplitLayout.getDividerLeash();
        final SurfaceControl dividerLeash = mSplitLayout.getDividerLeash();
        if (mIsDividerRemoteAnimating || dividerLeash == null) return;
        if (dividerLeash == null) {
            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN,
                    "%s:   Skip animating divider bar due to divider leash not ready.", TAG);
            return;
        }
        if (mIsDividerRemoteAnimating) {
            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN,
                    "%s:   Skip animating divider bar due to it's remote animating.", TAG);
            return;
        }

        if (mDividerFadeInAnimator != null && mDividerFadeInAnimator.isRunning()) {
            mDividerFadeInAnimator.cancel();
        }


        if (mDividerVisible) {
        if (mDividerVisible) {
            t.show(dividerLeash);
            final SurfaceControl.Transaction transaction = mTransactionPool.acquire();
            t.setAlpha(dividerLeash, 1);
            mDividerFadeInAnimator = ValueAnimator.ofFloat(0f, 1f);
            t.setLayer(dividerLeash, Integer.MAX_VALUE);
            mDividerFadeInAnimator.addUpdateListener(animation -> {
            t.setPosition(dividerLeash,
                if (dividerLeash == null) {
                    mDividerFadeInAnimator.cancel();
                    return;
                }
                transaction.setAlpha(dividerLeash, (float) animation.getAnimatedValue());
                transaction.apply();
            });
            mDividerFadeInAnimator.addListener(new AnimatorListenerAdapter() {
                @Override
                public void onAnimationStart(Animator animation) {
                    if (dividerLeash == null) {
                        mDividerFadeInAnimator.cancel();
                        return;
                    }
                    transaction.show(dividerLeash);
                    transaction.setAlpha(dividerLeash, 0);
                    transaction.setLayer(dividerLeash, Integer.MAX_VALUE);
                    transaction.setPosition(dividerLeash,
                                    mSplitLayout.getRefDividerBounds().left,
                                    mSplitLayout.getRefDividerBounds().left,
                                    mSplitLayout.getRefDividerBounds().top);
                                    mSplitLayout.getRefDividerBounds().top);
                    transaction.apply();
                }

                @Override
                public void onAnimationEnd(Animator animation) {
                    mTransactionPool.release(transaction);
                    mDividerFadeInAnimator = null;
                }
            });

            mDividerFadeInAnimator.start();
        } else {
        } else {
            t.hide(dividerLeash);
            t.hide(dividerLeash);
        }
        }
@@ -1096,10 +1164,8 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
            mSplitLayout.init();
            mSplitLayout.init();
            prepareEnterSplitScreen(wct);
            prepareEnterSplitScreen(wct);
            mSyncQueue.queue(wct);
            mSyncQueue.queue(wct);
            mSyncQueue.runInSync(t -> {
            mSyncQueue.runInSync(t ->
                updateSurfaceBounds(mSplitLayout, t, false /* applyResizingOffset */);
                    updateSurfaceBounds(mSplitLayout, t, false /* applyResizingOffset */));
                setDividerVisibility(true, t);
            });
        }
        }
        if (mMainStageListener.mHasChildren && mSideStageListener.mHasChildren) {
        if (mMainStageListener.mHasChildren && mSideStageListener.mHasChildren) {
            mShouldUpdateRecents = true;
            mShouldUpdateRecents = true;
+8 −0
Original line number Original line Diff line number Diff line
@@ -139,6 +139,7 @@ public class SplitTransitionTests extends ShellTestCase {
    }
    }


    @Test
    @Test
    @UiThreadTest
    public void testLaunchToSide() {
    public void testLaunchToSide() {
        ActivityManager.RunningTaskInfo newTask = new TestRunningTaskInfoBuilder()
        ActivityManager.RunningTaskInfo newTask = new TestRunningTaskInfoBuilder()
                .setParentTaskId(mSideStage.mRootTaskInfo.taskId).build();
                .setParentTaskId(mSideStage.mRootTaskInfo.taskId).build();
@@ -173,6 +174,7 @@ public class SplitTransitionTests extends ShellTestCase {
    }
    }


    @Test
    @Test
    @UiThreadTest
    public void testLaunchPair() {
    public void testLaunchPair() {
        TransitionInfo info = createEnterPairInfo();
        TransitionInfo info = createEnterPairInfo();


@@ -195,6 +197,7 @@ public class SplitTransitionTests extends ShellTestCase {
    }
    }


    @Test
    @Test
    @UiThreadTest
    public void testMonitorInSplit() {
    public void testMonitorInSplit() {
        enterSplit();
        enterSplit();


@@ -251,6 +254,7 @@ public class SplitTransitionTests extends ShellTestCase {
    }
    }


    @Test
    @Test
    @UiThreadTest
    public void testEnterRecents() {
    public void testEnterRecents() {
        enterSplit();
        enterSplit();


@@ -288,6 +292,7 @@ public class SplitTransitionTests extends ShellTestCase {
    }
    }


    @Test
    @Test
    @UiThreadTest
    public void testDismissFromBeingOccluded() {
    public void testDismissFromBeingOccluded() {
        enterSplit();
        enterSplit();


@@ -325,6 +330,7 @@ public class SplitTransitionTests extends ShellTestCase {
    }
    }


    @Test
    @Test
    @UiThreadTest
    public void testDismissFromMultiWindowSupport() {
    public void testDismissFromMultiWindowSupport() {
        enterSplit();
        enterSplit();


@@ -346,6 +352,7 @@ public class SplitTransitionTests extends ShellTestCase {
    }
    }


    @Test
    @Test
    @UiThreadTest
    public void testDismissSnap() {
    public void testDismissSnap() {
        enterSplit();
        enterSplit();


@@ -370,6 +377,7 @@ public class SplitTransitionTests extends ShellTestCase {
    }
    }


    @Test
    @Test
    @UiThreadTest
    public void testDismissFromAppFinish() {
    public void testDismissFromAppFinish() {
        enterSplit();
        enterSplit();