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

Commit 732446ae authored by Winson Chung's avatar Winson Chung
Browse files

Allow launcher to control home app surfaces during recents animation

- Previously, the app leashes were reparented to the standard animation
  layer which was always above the home layer. Now we reparent both to the
  home animation layer for the duration of the app-controlled recents
  animation. This allows launcher to reorder the home surface above the app
  during the swipe gesture and draw above the app.

Bug: 70341013
Test: atest FrameworksServicesTests:com.android.server.wm.RecentsAnimationControllerTest
Test: Swipe up, and ensure that the home app surface is also being animated
Change-Id: I2c0fa79c7bc1fffaf1374beb45386faea14ec20c
parent c3c71728
Loading
Loading
Loading
Loading
+26 −11
Original line number Diff line number Diff line
@@ -20,8 +20,8 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.view.RemoteAnimationTarget.MODE_CLOSING;
import static android.view.RemoteAnimationTarget.MODE_OPENING;
import static android.view.WindowManager.INPUT_CONSUMER_RECENTS_ANIMATION;

import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
import static com.android.server.wm.ActivityTaskManagerInternal.APP_TRANSITION_RECENTS_ANIM;
import static com.android.server.wm.AnimationAdapterProto.REMOTE;
@@ -48,16 +48,13 @@ import android.view.IRecentsAnimationRunner;
import android.view.RemoteAnimationTarget;
import android.view.SurfaceControl;
import android.view.SurfaceControl.Transaction;

import com.android.internal.annotations.VisibleForTesting;
import com.android.server.LocalServices;
import com.android.server.input.InputWindowHandle;
import com.android.server.inputmethod.InputMethodManagerInternal;
import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback;
import com.android.server.wm.utils.InsetUtils;

import com.google.android.collect.Sets;

import java.io.PrintWriter;
import java.util.ArrayList;

@@ -93,6 +90,7 @@ public class RecentsAnimationController implements DeathRecipient {

    // The recents component app token that is shown behind the visibile tasks
    private AppWindowToken mTargetAppToken;
    private int mTargetActivityType;
    private Rect mMinimizedHomeBounds = new Rect();

    // We start the RecentsAnimationController in a pending-start state since we need to wait for
@@ -259,23 +257,37 @@ public class RecentsAnimationController implements DeathRecipient {
        mDisplayId = displayId;
    }

    public void initialize(int targetActivityType, SparseBooleanArray recentTaskIds) {
        initialize(mService.mRoot.getDisplayContent(mDisplayId), targetActivityType, recentTaskIds);
    }

    /**
     * Initializes the recents animation controller. This is a separate call from the constructor
     * because it may call cancelAnimation() which needs to properly clean up the controller
     * in the window manager.
     */
    public void initialize(int targetActivityType, SparseBooleanArray recentTaskIds) {
        // Make leashes for each of the visible tasks and add it to the recents animation to be
        // started
        final DisplayContent dc = mService.mRoot.getDisplayContent(mDisplayId);
    @VisibleForTesting
    void initialize(DisplayContent dc, int targetActivityType, SparseBooleanArray recentTaskIds) {
        mTargetActivityType = targetActivityType;

        // Make leashes for each of the visible/target tasks and add it to the recents animation to
        // be started
        final ArrayList<Task> visibleTasks = dc.getVisibleTasks();
        final TaskStack targetStack = dc.getStack(WINDOWING_MODE_UNDEFINED, targetActivityType);
        if (targetStack != null) {
            for (int i = targetStack.getChildCount() - 1; i >= 0; i--) {
                final Task t = targetStack.getChildAt(i);
                if (!visibleTasks.contains(t)) {
                    visibleTasks.add(t);
                }
            }
        }
        final int taskCount = visibleTasks.size();
        for (int i = 0; i < taskCount; i++) {
            final Task task = visibleTasks.get(i);
            final WindowConfiguration config = task.getWindowConfiguration();
            if (config.tasksAreFloating()
                    || config.getWindowingMode() == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
                    || config.getActivityType() == targetActivityType) {
                    || config.getWindowingMode() == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
                continue;
            }
            addAnimation(task, !recentTaskIds.get(task.mTaskId));
@@ -586,7 +598,10 @@ public class RecentsAnimationController implements DeathRecipient {
            final Rect insets = new Rect();
            mainWindow.getContentInsets(insets);
            InsetUtils.addInsets(insets, mainWindow.mAppToken.getLetterboxInsets());
            mTarget = new RemoteAnimationTarget(mTask.mTaskId, MODE_CLOSING, mCapturedLeash,
            final int mode = topApp.getActivityType() == mTargetActivityType
                    ? MODE_OPENING
                    : MODE_CLOSING;
            mTarget = new RemoteAnimationTarget(mTask.mTaskId, mode, mCapturedLeash,
                    !topApp.fillsParent(), mainWindow.mWinAnimator.mLastClipRect,
                    insets, mTask.getPrefixOrderIndex(), mPosition, mBounds,
                    mTask.getWindowConfiguration(), mIsRecentTaskInvisible);
+4 −3
Original line number Diff line number Diff line
@@ -561,9 +561,10 @@ class Task extends WindowContainer<AppWindowToken> {

    @Override
    public SurfaceControl getAnimationLeashParent() {
        // Reparent to the animation layer so that we aren't clipped by the non-minimized
        // stack bounds, currently we only animate the task for the recents animation
        return getAppAnimationLayer(ANIMATION_LAYER_STANDARD);
        // Currently, only the recents animation will create animation leashes for tasks. In this
        // case, reparent the task to the home animation layer while it is being animated to allow
        // the home activity to reorder the app windows relative to its own.
        return getAppAnimationLayer(ANIMATION_LAYER_HOME);
    }

    boolean isTaskAnimating() {
+2 −3
Original line number Diff line number Diff line
@@ -42,10 +42,8 @@ import android.view.MagnificationSpec;
import android.view.SurfaceControl;
import android.view.SurfaceControl.Builder;
import android.view.SurfaceSession;

import com.android.internal.util.ToBooleanFunction;
import com.android.server.wm.SurfaceAnimator.Animatable;

import java.io.PrintWriter;
import java.util.Comparator;
import java.util.LinkedList;
@@ -71,7 +69,8 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<

    /**
     * Animation layer that is reserved for {@link WindowConfiguration#ACTIVITY_TYPE_HOME}
     * activities that happens below all {@link TaskStack}s.
     * activities and all activities that are being controlled by the recents animation. This
     * layer is generally below all {@link TaskStack}s.
     */
    static final int ANIMATION_LAYER_HOME = 2;

+6 −0
Original line number Diff line number Diff line
@@ -227,6 +227,7 @@ import android.view.WindowManagerGlobal;
import android.view.WindowManagerPolicyConstants.PointerEventListener;

import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.os.IResultReceiver;
import com.android.internal.policy.IKeyguardDismissCallback;
import com.android.internal.policy.IShortcutService;
@@ -2714,6 +2715,11 @@ public class WindowManagerService extends IWindowManager.Stub
        }
    }

    @VisibleForTesting
    void setRecentsAnimationController(RecentsAnimationController controller) {
        mRecentsAnimationController = controller;
    }

    public RecentsAnimationController getRecentsAnimationController() {
        return mRecentsAnimationController;
    }
+22 −0
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package com.android.server.wm;

import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.view.Display.DEFAULT_DISPLAY;
@@ -24,6 +25,8 @@ import static com.android.server.wm.RecentsAnimationController.REORDER_KEEP_IN_P
import static com.android.server.wm.RecentsAnimationController.REORDER_MOVE_TO_ORIGINAL_POSITION;

import static org.junit.Assert.fail;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.atLeast;
import static org.mockito.Mockito.verify;
@@ -33,6 +36,7 @@ import static org.mockito.Mockito.when;
import android.os.Binder;
import android.os.IInterface;
import android.platform.test.annotations.Presubmit;
import android.util.SparseBooleanArray;
import android.view.IRecentsAnimationRunner;
import android.view.SurfaceControl;

@@ -109,6 +113,24 @@ public class RecentsAnimationControllerTest extends WindowTestsBase {
        }
    }

    @Test
    public void testIncludedApps_expectTargetAndVisible() throws Exception {
        sWm.setRecentsAnimationController(mController);
        final AppWindowToken homeAppWindow = createAppWindowToken(mDisplayContent,
                WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME);
        final AppWindowToken appWindow = createAppWindowToken(mDisplayContent,
                WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
        final AppWindowToken hiddenAppWindow = createAppWindowToken(mDisplayContent,
                WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
        hiddenAppWindow.setHidden(true);
        mController.initialize(mDisplayContent, ACTIVITY_TYPE_HOME, new SparseBooleanArray());

        // Ensure that we are animating the target activity as well
        assertTrue(mController.isAnimatingTask(homeAppWindow.getTask()));
        assertTrue(mController.isAnimatingTask(appWindow.getTask()));
        assertFalse(mController.isAnimatingTask(hiddenAppWindow.getTask()));
    }

    private static void verifyNoMoreInteractionsExceptAsBinder(IInterface binder) {
        verify(binder, atLeast(0)).asBinder();
        verifyNoMoreInteractions(binder);