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

Commit 119b6def authored by Gaurav Bhola's avatar Gaurav Bhola
Browse files

A few updates to task views to enable shell transitions on auto.

- Call base.onTaskView as part of prepareOpenAnimation as that is
  effectively when the task in taskview appears now
- Add a new method startRootTask(); to start an already create root task
  inside the task view. It uses prepareOpenAnimatino() but without the
  start and finish transition surface-controls
- Add a new method to reorderTaskViewTask via shell transitions and also
  add support for reorder as part of setTaskViewVisible.

Bug: 333096229
Test: <pending>
Change-Id: I906a080095870131d721f8a5365c80c7a5350d1f
parent d588b98d
Loading
Loading
Loading
Loading
+5 −1
Original line number Diff line number Diff line
@@ -30,7 +30,6 @@ import android.graphics.Insets;
import android.graphics.Rect;
import android.graphics.Region;
import android.os.Handler;
import android.os.Looper;
import android.view.SurfaceControl;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
@@ -121,6 +120,11 @@ public class TaskView extends SurfaceView implements SurfaceHolder.Callback,

    @Override
    public void onTaskAppeared(ActivityManager.RunningTaskInfo taskInfo, SurfaceControl leash) {
        if (mTaskViewTaskController.isUsingShellTransitions()) {
            // No need for additional work as it is already taken care of during
            // prepareOpenAnimation().
            return;
        }
        onLocationChanged();
        if (taskInfo.taskDescription != null) {
            final int bgColor = taskInfo.taskDescription.getBackgroundColor();
+69 −11
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package com.android.wm.shell.taskview;

import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
import static android.view.WindowManager.TRANSIT_CHANGE;

import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -48,6 +49,23 @@ import java.util.concurrent.Executor;
 * TaskView} to {@link TaskViewTaskController} interactions are done via direct method calls.
 *
 * The reverse communication is done via the {@link TaskViewBase} interface.
 *
 * <ul>
 *     <li>The entry point for an activity based task view is {@link
 *     TaskViewTaskController#startActivity(PendingIntent, Intent, ActivityOptions, Rect)}</li>
 *
 *     <li>The entry point for an activity (represented by {@link ShortcutInfo}) based task view
 *     is {@link TaskViewTaskController#startShortcutActivity(ShortcutInfo, ActivityOptions, Rect)}
 *     </li>
 *
 *     <li>The entry point for a root-task based task view is {@link
 *     TaskViewTaskController#startRootTask(ActivityManager.RunningTaskInfo, SurfaceControl,
 *     WindowContainerTransaction)}.
 *     This method is special as it doesn't create a root task and instead expects that the
 *     launch root task is already created and started. This method just attaches the taskInfo to
 *     the TaskView.
 *     </li>
 * </ul>
 */
public class TaskViewTaskController implements ShellTaskOrganizer.TaskListener {

@@ -208,6 +226,35 @@ public class TaskViewTaskController implements ShellTaskOrganizer.TaskListener {
        }
    }


    /**
     * Attaches the given root task {@code taskInfo} in the task view.
     *
     * <p> Since {@link ShellTaskOrganizer#createRootTask(int, int,
     * ShellTaskOrganizer.TaskListener)} does not use the shell transitions flow, this method is
     * used as an entry point for an already-created root-task in the task view.
     *
     * @param taskInfo the task info of the root task.
     * @param leash    the {@link android.content.pm.ShortcutInfo.Surface} of the root task
     * @param wct      The Window container work that should happen as part of this set up.
     */
    public void startRootTask(ActivityManager.RunningTaskInfo taskInfo, SurfaceControl leash,
            @Nullable WindowContainerTransaction wct) {
        if (wct == null) {
            wct = new WindowContainerTransaction();
        }
        // This method skips the regular flow where an activity task is launched as part of a new
        // transition in taskview and then transition is intercepted using the launchcookie.
        // The task here is already created and running, it just needs to be reparented, resized
        // and tracked correctly inside taskview. Which is done by calling
        // prepareOpenAnimationInternal() and then manually enqueuing the resulting window container
        // transaction.
        prepareOpenAnimationInternal(true /* newTask */, mTransaction /* startTransaction */,
                null /* finishTransaction */, taskInfo, leash, wct);
        mTransaction.apply();
        mTaskViewTransitions.startInstantTransition(TRANSIT_CHANGE, wct);
    }

    private void prepareActivityOptions(ActivityOptions options, Rect launchBounds) {
        final Binder launchCookie = new Binder();
        mShellExecutor.execute(() -> {
@@ -342,7 +389,6 @@ public class TaskViewTaskController implements ShellTaskOrganizer.TaskListener {
        final SurfaceControl taskLeash = mTaskLeash;
        handleAndNotifyTaskRemoval(mTaskInfo);

        // Unparent the task when this surface is destroyed
        mTransaction.reparent(taskLeash, null).apply();
        resetTaskInfo();
    }
@@ -597,6 +643,15 @@ public class TaskViewTaskController implements ShellTaskOrganizer.TaskListener {
            @NonNull SurfaceControl.Transaction finishTransaction,
            ActivityManager.RunningTaskInfo taskInfo, SurfaceControl leash,
            WindowContainerTransaction wct) {
        prepareOpenAnimationInternal(newTask, startTransaction, finishTransaction, taskInfo, leash,
                wct);
    }

    private void prepareOpenAnimationInternal(final boolean newTask,
            SurfaceControl.Transaction startTransaction,
            SurfaceControl.Transaction finishTransaction,
            ActivityManager.RunningTaskInfo taskInfo, SurfaceControl leash,
            WindowContainerTransaction wct) {
        mPendingInfo = null;
        mTaskInfo = taskInfo;
        mTaskToken = mTaskInfo.token;
@@ -608,10 +663,12 @@ public class TaskViewTaskController implements ShellTaskOrganizer.TaskListener {
            // Also reparent on finishTransaction since the finishTransaction will reparent back
            // to its "original" parent by default.
            Rect boundsOnScreen = mTaskViewBase.getCurrentBoundsOnScreen();
            if (finishTransaction != null) {
                finishTransaction.reparent(mTaskLeash, mSurfaceControl)
                        .setPosition(mTaskLeash, 0, 0)
                        // TODO: maybe once b/280900002 is fixed this will be unnecessary
                        .setWindowCrop(mTaskLeash, boundsOnScreen.width(), boundsOnScreen.height());
            }
            mTaskViewTransitions.updateBoundsState(this, boundsOnScreen);
            mTaskViewTransitions.updateVisibilityState(this, true /* visible */);
            wct.setBounds(mTaskToken, boundsOnScreen);
@@ -632,6 +689,7 @@ public class TaskViewTaskController implements ShellTaskOrganizer.TaskListener {
            mTaskViewBase.setResizeBgColor(startTransaction, backgroundColor);
        }

        mTaskViewBase.onTaskAppeared(mTaskInfo, mTaskLeash);
        if (mListener != null) {
            final int taskId = mTaskInfo.taskId;
            final ComponentName baseActivity = mTaskInfo.baseActivity;
+51 −4
Original line number Diff line number Diff line
@@ -122,6 +122,7 @@ public class TaskViewTransitions implements Transitions.TransitionHandler {
    /**
     * Looks through the pending transitions for a closing transaction that matches the provided
     * `taskView`.
     *
     * @param taskView the pending transition should be for this.
     */
    private PendingTransition findPendingCloseTransition(TaskViewTaskController taskView) {
@@ -134,9 +135,18 @@ public class TaskViewTransitions implements Transitions.TransitionHandler {
        return null;
    }

    /**
     * Starts a transition outside of the handler associated with {@link TaskViewTransitions}.
     */
    public void startInstantTransition(@WindowManager.TransitionType int type,
            WindowContainerTransaction wct) {
        mTransitions.startTransition(type, wct, null);
    }

    /**
     * Looks through the pending transitions for a opening transaction that matches the provided
     * `taskView`.
     *
     * @param taskView the pending transition should be for this.
     */
    @VisibleForTesting
@@ -152,6 +162,7 @@ public class TaskViewTransitions implements Transitions.TransitionHandler {

    /**
     * Looks through the pending transitions for one matching `taskView`.
     *
     * @param taskView the pending transition should be for this.
     * @param type     the type of transition it's looking for
     */
@@ -220,7 +231,24 @@ public class TaskViewTransitions implements Transitions.TransitionHandler {
        startNextTransition();
    }

    void setTaskViewVisible(TaskViewTaskController taskView, boolean visible) {
    /** Starts a new transition to make the given {@code taskView} visible. */
    public void setTaskViewVisible(TaskViewTaskController taskView, boolean visible) {
        setTaskViewVisible(taskView, visible, false /* reorder */);
    }

    /**
     * Starts a new transition to make the given {@code taskView} visible and optionally change
     * the task order.
     *
     * @param taskView the task view which the visibility is being changed for
     * @param visible  the new visibility of the task view
     * @param reorder  whether to reorder the task or not. If this is {@code true}, the task will be
     *                 reordered as per the given {@code visible}. For {@code visible = true}, task
     *                 will be reordered to top. For {@code visible = false}, task will be reordered
     *                 to the bottom
     */
    public void setTaskViewVisible(TaskViewTaskController taskView, boolean visible,
            boolean reorder) {
        if (mTaskViews.get(taskView) == null) return;
        if (mTaskViews.get(taskView).mVisible == visible) return;
        if (taskView.getTaskInfo() == null) {
@@ -231,6 +259,9 @@ public class TaskViewTransitions implements Transitions.TransitionHandler {
        final WindowContainerTransaction wct = new WindowContainerTransaction();
        wct.setHidden(taskView.getTaskInfo().token, !visible /* hidden */);
        wct.setBounds(taskView.getTaskInfo().token, mTaskViews.get(taskView).mBounds);
        if (reorder) {
            wct.reorder(taskView.getTaskInfo().token, visible /* onTop */);
        }
        PendingTransition pending = new PendingTransition(
                visible ? TRANSIT_TO_FRONT : TRANSIT_TO_BACK, wct, taskView, null /* cookie */);
        mPending.add(pending);
@@ -238,6 +269,22 @@ public class TaskViewTransitions implements Transitions.TransitionHandler {
        // visibility is reported in transition.
    }

    /** Starts a new transition to reorder the given {@code taskView}'s task. */
    public void reorderTaskViewTask(TaskViewTaskController taskView, boolean onTop) {
        if (mTaskViews.get(taskView) == null) return;
        if (taskView.getTaskInfo() == null) {
            // Nothing to update, task is not yet available
            return;
        }
        final WindowContainerTransaction wct = new WindowContainerTransaction();
        wct.reorder(taskView.getTaskInfo().token, onTop /* onTop */);
        PendingTransition pending = new PendingTransition(
                onTop ? TRANSIT_TO_FRONT : TRANSIT_TO_BACK, wct, taskView, null /* cookie */);
        mPending.add(pending);
        startNextTransition();
        // visibility is reported in transition.
    }

    void updateBoundsState(TaskViewTaskController taskView, Rect boundsOnScreen) {
        TaskViewRequestedState state = mTaskViews.get(taskView);
        if (state == null) return;
+25 −1
Original line number Diff line number Diff line
@@ -44,7 +44,6 @@ import android.graphics.Color;
import android.graphics.Insets;
import android.graphics.Rect;
import android.graphics.Region;
import android.os.Handler;
import android.os.Looper;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
@@ -497,6 +496,31 @@ public class TaskViewTest extends ShellTestCase {
        assertThat(insetsInfo.touchableRegion.contains(30, 30)).isFalse();
    }

    @Test
    public void testStartRootTask_setsBoundsAndVisibility() {
        assumeTrue(Transitions.ENABLE_SHELL_TRANSITIONS);

        TaskViewBase taskViewBase = mock(TaskViewBase.class);
        Rect bounds = new Rect(0, 0, 100, 100);
        when(taskViewBase.getCurrentBoundsOnScreen()).thenReturn(bounds);
        mTaskViewTaskController.setTaskViewBase(taskViewBase);

        // Surface created, but task not available so bounds / visibility isn't set
        mTaskView.surfaceCreated(mock(SurfaceHolder.class));
        verify(mTaskViewTransitions, never()).updateVisibilityState(
                eq(mTaskViewTaskController), eq(true));

        // Make the task available
        WindowContainerTransaction wct = mock(WindowContainerTransaction.class);
        mTaskViewTaskController.startRootTask(mTaskInfo, mLeash, wct);

        // Bounds got set
        verify(wct).setBounds(any(WindowContainerToken.class), eq(bounds));
        // Visibility & bounds state got set
        verify(mTaskViewTransitions).updateVisibilityState(eq(mTaskViewTaskController), eq(true));
        verify(mTaskViewTransitions).updateBoundsState(eq(mTaskViewTaskController), eq(bounds));
    }

    @Test
    public void testTaskViewPrepareOpenAnimationSetsBoundsAndVisibility() {
        assumeTrue(Transitions.ENABLE_SHELL_TRANSITIONS);
+43 −0
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package com.android.wm.shell.taskview;

import static android.view.WindowManager.TRANSIT_CHANGE;
import static android.view.WindowManager.TRANSIT_OPEN;
import static android.view.WindowManager.TRANSIT_TO_BACK;
import static android.view.WindowManager.TRANSIT_TO_FRONT;

import static com.google.common.truth.Truth.assertThat;
@@ -207,6 +208,48 @@ public class TaskViewTransitionsTest extends ShellTestCase {
                new Rect(0, 0, 100, 100));
    }

    @Test
    public void testReorderTask_movedToFrontTransaction() {
        assumeTrue(Transitions.ENABLE_SHELL_TRANSITIONS);

        mTaskViewTransitions.reorderTaskViewTask(mTaskViewTaskController, true);
        // Consume the pending transaction from order change
        TaskViewTransitions.PendingTransition pending =
                mTaskViewTransitions.findPending(mTaskViewTaskController, TRANSIT_TO_FRONT);
        assertThat(pending).isNotNull();
        mTaskViewTransitions.startAnimation(pending.mClaimed,
                mock(TransitionInfo.class),
                new SurfaceControl.Transaction(),
                new SurfaceControl.Transaction(),
                mock(Transitions.TransitionFinishCallback.class));

        // Verify it was consumed
        TaskViewTransitions.PendingTransition pending2 =
                mTaskViewTransitions.findPending(mTaskViewTaskController, TRANSIT_TO_FRONT);
        assertThat(pending2).isNull();
    }

    @Test
    public void testReorderTask_movedToBackTransaction() {
        assumeTrue(Transitions.ENABLE_SHELL_TRANSITIONS);

        mTaskViewTransitions.reorderTaskViewTask(mTaskViewTaskController, false);
        // Consume the pending transaction from order change
        TaskViewTransitions.PendingTransition pending =
                mTaskViewTransitions.findPending(mTaskViewTaskController, TRANSIT_TO_BACK);
        assertThat(pending).isNotNull();
        mTaskViewTransitions.startAnimation(pending.mClaimed,
                mock(TransitionInfo.class),
                new SurfaceControl.Transaction(),
                new SurfaceControl.Transaction(),
                mock(Transitions.TransitionFinishCallback.class));

        // Verify it was consumed
        TaskViewTransitions.PendingTransition pending2 =
                mTaskViewTransitions.findPending(mTaskViewTaskController, TRANSIT_TO_BACK);
        assertThat(pending2).isNull();
    }

    @Test
    public void test_startAnimation_setsTaskNotFound() {
        assumeTrue(Transitions.ENABLE_SHELL_TRANSITIONS);