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

Commit a29cb610 authored by Ats Jenk's avatar Ats Jenk Committed by Android (Google) Code Review
Browse files

Merge "Animation for launching desktop from overview" into main

parents ba34b5f5 fa9cb968
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 {
        }
    }

}