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

Commit fa9cb968 authored by Ats Jenk's avatar Ats Jenk
Browse files

Animation for launching desktop from overview

Create a RemoteTransition to run the overview to desktop animation when
user clicks on the desktop tile in recents.

Bug: 297590571
Test: atest DesktopTasksControllerTest
Change-Id: Ie8c9189bace77ba80e6be90222b3f786dfe5bb15
parent 53d29b37
Loading
Loading
Loading
Loading
+16 −11
Original line number Diff line number Diff line
@@ -37,6 +37,7 @@ import android.view.WindowManager.TRANSIT_CHANGE
import android.view.WindowManager.TRANSIT_NONE
import android.view.WindowManager.TRANSIT_OPEN
import android.view.WindowManager.TRANSIT_TO_FRONT
import android.window.RemoteTransition
import android.window.TransitionInfo
import android.window.TransitionRequestInfo
import android.window.WindowContainerTransaction
@@ -65,7 +66,9 @@ import com.android.wm.shell.sysui.ShellCommandHandler
import com.android.wm.shell.sysui.ShellController
import com.android.wm.shell.sysui.ShellInit
import com.android.wm.shell.sysui.ShellSharedConstants
import com.android.wm.shell.transition.OneShotRemoteHandler
import com.android.wm.shell.transition.Transitions
import com.android.wm.shell.transition.Transitions.TransitionHandler
import com.android.wm.shell.util.KtProtoLog
import com.android.wm.shell.windowdecor.DesktopModeWindowDecoration
import com.android.wm.shell.windowdecor.MoveToDesktopAnimator
@@ -139,22 +142,24 @@ class DesktopTasksController(
    }

    /** Show all tasks, that are part of the desktop, on top of launcher */
    fun showDesktopApps(displayId: Int) {
    fun showDesktopApps(displayId: Int, remoteTransition: RemoteTransition? = null) {
        KtProtoLog.v(WM_SHELL_DESKTOP_MODE, "DesktopTasksController: showDesktopApps")
        val wct = WindowContainerTransaction()
        // TODO(b/278084491): pass in display id
        bringDesktopAppsToFront(displayId, wct)

        // Execute transaction if there are pending operations
        if (!wct.isEmpty) {
        if (Transitions.ENABLE_SHELL_TRANSITIONS) {
                // TODO(b/268662477): add animation for the transition
                transitions.startTransition(TRANSIT_NONE, wct, null /* handler */)
            // TODO(b/255649902): ensure remote transition is supplied once state is introduced
            val transitionType = if (remoteTransition == null) TRANSIT_NONE else TRANSIT_TO_FRONT
            val handler = remoteTransition?.let {
                OneShotRemoteHandler(transitions.mainExecutor, remoteTransition)
            }
            transitions.startTransition(transitionType, wct, handler).also { t ->
                handler?.setTransition(t)
            }
        } else {
            shellTaskOrganizer.applyTransaction(wct)
        }
    }
    }

    /**
     * Stash desktop tasks on display with id [displayId].
@@ -1093,11 +1098,11 @@ class DesktopTasksController(
            controller = null
        }

        override fun showDesktopApps(displayId: Int) {
        override fun showDesktopApps(displayId: Int, remoteTransition: RemoteTransition?) {
            ExecutorUtils.executeRemoteCallWithTaskPermission(
                controller,
                "showDesktopApps"
            ) { c -> c.showDesktopApps(displayId) }
            ) { c -> c.showDesktopApps(displayId, remoteTransition) }
        }

        override fun stashDesktopApps(displayId: Int) {
+2 −1
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package com.android.wm.shell.desktopmode;

import android.app.ActivityManager.RunningTaskInfo;
import android.window.RemoteTransition;
import com.android.wm.shell.desktopmode.IDesktopTaskListener;

/**
@@ -25,7 +26,7 @@ import com.android.wm.shell.desktopmode.IDesktopTaskListener;
interface IDesktopMode {

    /** Show apps on the desktop on the given display */
    void showDesktopApps(int displayId);
    void showDesktopApps(int displayId, in RemoteTransition remoteTransition);

    /** Stash apps on the desktop to allow launching another app from home screen */
    void stashDesktopApps(int displayId);
+59 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2023 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.android.wm.shell;

import android.os.IBinder;
import android.os.RemoteException;
import android.view.SurfaceControl;
import android.window.IRemoteTransition;
import android.window.IRemoteTransitionFinishedCallback;
import android.window.TransitionInfo;
import android.window.WindowContainerTransaction;

/**
 * {@link IRemoteTransition} for testing purposes.
 * Stores info about
 * {@link #startAnimation(IBinder, TransitionInfo, SurfaceControl.Transaction,
 * IRemoteTransitionFinishedCallback)} being called.
 */
public class TestRemoteTransition extends IRemoteTransition.Stub {
    private boolean mCalled = false;
    final WindowContainerTransaction mRemoteFinishWCT = new WindowContainerTransaction();

    @Override
    public void startAnimation(IBinder transition, TransitionInfo info,
            SurfaceControl.Transaction startTransaction,
            IRemoteTransitionFinishedCallback finishCallback)
            throws RemoteException {
        mCalled = true;
        finishCallback.onTransitionFinished(mRemoteFinishWCT, null /* sct */);
    }

    @Override
    public void mergeAnimation(IBinder transition, TransitionInfo info,
            SurfaceControl.Transaction t, IBinder mergeTarget,
            IRemoteTransitionFinishedCallback finishCallback) throws RemoteException {
    }

    /**
     * Check whether this remote transition
     * {@link #startAnimation(IBinder, TransitionInfo, SurfaceControl.Transaction,
     * IRemoteTransitionFinishedCallback)} is called
     */
    public boolean isCalled() {
        return mCalled;
    }
}
+28 −19
Original line number Diff line number Diff line
@@ -28,10 +28,10 @@ import android.testing.AndroidTestingRunner
import android.view.Display.DEFAULT_DISPLAY
import android.view.WindowManager
import android.view.WindowManager.TRANSIT_CHANGE
import android.view.WindowManager.TRANSIT_NONE
import android.view.WindowManager.TRANSIT_OPEN
import android.view.WindowManager.TRANSIT_TO_FRONT
import android.window.DisplayAreaInfo
import android.window.RemoteTransition
import android.window.TransitionRequestInfo
import android.window.WindowContainerTransaction
import android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REORDER
@@ -43,6 +43,7 @@ import com.android.wm.shell.MockToken
import com.android.wm.shell.RootTaskDisplayAreaOrganizer
import com.android.wm.shell.ShellTaskOrganizer
import com.android.wm.shell.ShellTestCase
import com.android.wm.shell.TestRemoteTransition
import com.android.wm.shell.TestRunningTaskInfoBuilder
import com.android.wm.shell.TestShellExecutor
import com.android.wm.shell.common.DisplayController
@@ -57,8 +58,10 @@ import com.android.wm.shell.splitscreen.SplitScreenController
import com.android.wm.shell.sysui.ShellCommandHandler
import com.android.wm.shell.sysui.ShellController
import com.android.wm.shell.sysui.ShellInit
import com.android.wm.shell.transition.OneShotRemoteHandler
import com.android.wm.shell.transition.Transitions
import com.android.wm.shell.transition.Transitions.ENABLE_SHELL_TRANSITIONS
import com.android.wm.shell.transition.Transitions.TransitionHandler
import com.android.wm.shell.windowdecor.DesktopModeWindowDecoration
import com.google.common.truth.Truth.assertThat
import com.google.common.truth.Truth.assertWithMessage
@@ -69,6 +72,7 @@ import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentCaptor
import org.mockito.ArgumentMatchers.eq
import org.mockito.ArgumentMatchers.isA
import org.mockito.ArgumentMatchers.isNull
import org.mockito.Mock
import org.mockito.Mockito
@@ -174,9 +178,9 @@ class DesktopTasksControllerTest : ShellTestCase() {
        markTaskHidden(task1)
        markTaskHidden(task2)

        controller.showDesktopApps(DEFAULT_DISPLAY)
        controller.showDesktopApps(DEFAULT_DISPLAY, RemoteTransition(TestRemoteTransition()))

        val wct = getLatestWct(expectTransition = TRANSIT_NONE)
        val wct = getLatestWct(type = TRANSIT_OPEN, handlerClass = OneShotRemoteHandler::class.java)
        assertThat(wct.hierarchyOps).hasSize(3)
        // Expect order to be from bottom: home, task1, task2
        wct.assertReorderAt(index = 0, homeTask)
@@ -192,9 +196,9 @@ class DesktopTasksControllerTest : ShellTestCase() {
        markTaskVisible(task1)
        markTaskVisible(task2)

        controller.showDesktopApps(DEFAULT_DISPLAY)
        controller.showDesktopApps(DEFAULT_DISPLAY, RemoteTransition(TestRemoteTransition()))

        val wct = getLatestWct(expectTransition = TRANSIT_NONE)
        val wct = getLatestWct(type = TRANSIT_OPEN, handlerClass = OneShotRemoteHandler::class.java)
        assertThat(wct.hierarchyOps).hasSize(3)
        // Expect order to be from bottom: home, task1, task2
        wct.assertReorderAt(index = 0, homeTask)
@@ -210,9 +214,9 @@ class DesktopTasksControllerTest : ShellTestCase() {
        markTaskHidden(task1)
        markTaskVisible(task2)

        controller.showDesktopApps(DEFAULT_DISPLAY)
        controller.showDesktopApps(DEFAULT_DISPLAY, RemoteTransition(TestRemoteTransition()))

        val wct = getLatestWct(expectTransition = TRANSIT_NONE)
        val wct = getLatestWct(type = TRANSIT_OPEN, handlerClass = OneShotRemoteHandler::class.java)
        assertThat(wct.hierarchyOps).hasSize(3)
        // Expect order to be from bottom: home, task1, task2
        wct.assertReorderAt(index = 0, homeTask)
@@ -224,9 +228,9 @@ class DesktopTasksControllerTest : ShellTestCase() {
    fun showDesktopApps_noActiveTasks_reorderHomeToTop() {
        val homeTask = setUpHomeTask()

        controller.showDesktopApps(DEFAULT_DISPLAY)
        controller.showDesktopApps(DEFAULT_DISPLAY, RemoteTransition(TestRemoteTransition()))

        val wct = getLatestWct(expectTransition = TRANSIT_NONE)
        val wct = getLatestWct(type = TRANSIT_OPEN, handlerClass = OneShotRemoteHandler::class.java)
        assertThat(wct.hierarchyOps).hasSize(1)
        wct.assertReorderAt(index = 0, homeTask)
    }
@@ -240,9 +244,9 @@ class DesktopTasksControllerTest : ShellTestCase() {
        markTaskHidden(taskDefaultDisplay)
        markTaskHidden(taskSecondDisplay)

        controller.showDesktopApps(DEFAULT_DISPLAY)
        controller.showDesktopApps(DEFAULT_DISPLAY, RemoteTransition(TestRemoteTransition()))

        val wct = getLatestWct(expectTransition = TRANSIT_NONE)
        val wct = getLatestWct(type = TRANSIT_OPEN, handlerClass = OneShotRemoteHandler::class.java)
        assertThat(wct.hierarchyOps).hasSize(2)
        // Expect order to be from bottom: home, task
        wct.assertReorderAt(index = 0, homeTaskDefaultDisplay)
@@ -373,7 +377,7 @@ class DesktopTasksControllerTest : ShellTestCase() {
        val task = setUpFreeformTask()
        task.configuration.windowConfiguration.displayWindowingMode = WINDOWING_MODE_FULLSCREEN
        controller.moveToFullscreen(task)
        val wct = getLatestWct(expectTransition = TRANSIT_CHANGE)
        val wct = getLatestWct(type = TRANSIT_CHANGE)
        assertThat(wct.changes[task.token.asBinder()]?.windowingMode)
            .isEqualTo(WINDOWING_MODE_UNDEFINED)
    }
@@ -383,7 +387,7 @@ class DesktopTasksControllerTest : ShellTestCase() {
        val task = setUpFreeformTask()
        task.configuration.windowConfiguration.displayWindowingMode = WINDOWING_MODE_FREEFORM
        controller.moveToFullscreen(task)
        val wct = getLatestWct(expectTransition = TRANSIT_CHANGE)
        val wct = getLatestWct(type = TRANSIT_CHANGE)
        assertThat(wct.changes[task.token.asBinder()]?.windowingMode)
                .isEqualTo(WINDOWING_MODE_FULLSCREEN)
    }
@@ -401,7 +405,7 @@ class DesktopTasksControllerTest : ShellTestCase() {

        controller.moveToFullscreen(taskDefaultDisplay)

        with(getLatestWct(expectTransition = TRANSIT_CHANGE)) {
        with(getLatestWct(type = TRANSIT_CHANGE)) {
            assertThat(changes.keys).contains(taskDefaultDisplay.token.asBinder())
            assertThat(changes.keys).doesNotContain(taskSecondDisplay.token.asBinder())
        }
@@ -414,7 +418,7 @@ class DesktopTasksControllerTest : ShellTestCase() {

        controller.moveTaskToFront(task1)

        val wct = getLatestWct(expectTransition = TRANSIT_TO_FRONT)
        val wct = getLatestWct(type = TRANSIT_TO_FRONT)
        assertThat(wct.hierarchyOps).hasSize(1)
        wct.assertReorderAt(index = 0, task1)
    }
@@ -439,7 +443,7 @@ class DesktopTasksControllerTest : ShellTestCase() {

        val task = setUpFreeformTask(displayId = DEFAULT_DISPLAY)
        controller.moveToNextDisplay(task.taskId)
        with(getLatestWct(expectTransition = TRANSIT_CHANGE)) {
        with(getLatestWct(type = TRANSIT_CHANGE)) {
            assertThat(hierarchyOps).hasSize(1)
            assertThat(hierarchyOps[0].container).isEqualTo(task.token.asBinder())
            assertThat(hierarchyOps[0].isReparent).isTrue()
@@ -461,7 +465,7 @@ class DesktopTasksControllerTest : ShellTestCase() {
        val task = setUpFreeformTask(displayId = SECOND_DISPLAY)
        controller.moveToNextDisplay(task.taskId)

        with(getLatestWct(expectTransition = TRANSIT_CHANGE)) {
        with(getLatestWct(type = TRANSIT_CHANGE)) {
            assertThat(hierarchyOps).hasSize(1)
            assertThat(hierarchyOps[0].container).isEqualTo(task.token.asBinder())
            assertThat(hierarchyOps[0].isReparent).isTrue()
@@ -747,11 +751,16 @@ class DesktopTasksControllerTest : ShellTestCase() {
    }

    private fun getLatestWct(
        @WindowManager.TransitionType expectTransition: Int = TRANSIT_OPEN
            @WindowManager.TransitionType type: Int = TRANSIT_OPEN,
            handlerClass: Class<out TransitionHandler>? = null
    ): WindowContainerTransaction {
        val arg = ArgumentCaptor.forClass(WindowContainerTransaction::class.java)
        if (ENABLE_SHELL_TRANSITIONS) {
            verify(transitions).startTransition(eq(expectTransition), arg.capture(), isNull())
            if (handlerClass == null) {
                verify(transitions).startTransition(eq(type), arg.capture(), isNull())
            } else {
                verify(transitions).startTransition(eq(type), arg.capture(), isA(handlerClass))
            }
        } else {
            verify(shellTaskOrganizer).applyTransaction(arg.capture())
        }
+2 −24
Original line number Diff line number Diff line
@@ -47,11 +47,8 @@ import static org.mockito.Mockito.spy;
import android.annotation.NonNull;
import android.app.ActivityManager;
import android.os.IBinder;
import android.os.RemoteException;
import android.view.SurfaceControl;
import android.view.SurfaceSession;
import android.window.IRemoteTransition;
import android.window.IRemoteTransitionFinishedCallback;
import android.window.RemoteTransition;
import android.window.TransitionInfo;
import android.window.TransitionRequestInfo;
@@ -65,6 +62,7 @@ import com.android.launcher3.icons.IconProvider;
import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.ShellTestCase;
import com.android.wm.shell.TestRemoteTransition;
import com.android.wm.shell.TestRunningTaskInfoBuilder;
import com.android.wm.shell.TransitionInfoBuilder;
import com.android.wm.shell.common.DisplayController;
@@ -205,7 +203,7 @@ public class SplitTransitionTests extends ShellTestCase {

        // Make sure split-screen is now visible
        assertTrue(mStageCoordinator.isSplitScreenVisible());
        assertTrue(testRemote.mCalled);
        assertTrue(testRemote.isCalled());
    }

    @Test
@@ -468,24 +466,4 @@ public class SplitTransitionTests extends ShellTestCase {
        return out;
    }

    class TestRemoteTransition extends IRemoteTransition.Stub {
        boolean mCalled = false;
        final WindowContainerTransaction mRemoteFinishWCT = new WindowContainerTransaction();

        @Override
        public void startAnimation(IBinder transition, TransitionInfo info,
                SurfaceControl.Transaction startTransaction,
                IRemoteTransitionFinishedCallback finishCallback)
                throws RemoteException {
            mCalled = true;
            finishCallback.onTransitionFinished(mRemoteFinishWCT, null /* sct */);
        }

        @Override
        public void mergeAnimation(IBinder transition, TransitionInfo info,
                SurfaceControl.Transaction t, IBinder mergeTarget,
                IRemoteTransitionFinishedCallback finishCallback) throws RemoteException {
        }
    }

}