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

Commit c38085ac authored by Sergey Pinkevich's avatar Sergey Pinkevich
Browse files

Don't use a custom animation for Notification shader in Desktop Windowing mode

Bug: 383061244
Flag: com.android.systemui.shade_app_launch_animation_skip_in_desktop
Test: atest com.android.systemui.statusbar.phone.LegacyActivityStarterInternalImplTest com.android.systemui.animation.ActivityTransitionAnimatorTest com.android.systemui.statusbar.phone.StatusBarNotificationActivityStarterTest

Change-Id: I466569bdd0c817e1617bb1e3334caa0b1b33cb23
parent dd4a629a
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -42,6 +42,15 @@ public interface DesktopMode {
    void addVisibleTasksListener(DesktopRepository.VisibleTasksListener listener,
            Executor callbackExecutor);

    /**
     * Adds a listener to find out about desk changes.
     *
     * @param listener the listener to add.
     * @param callbackExecutor the executor to call the listener on.
     */
    void addDeskChangeListener(DesktopRepository.DeskChangeListener listener,
            Executor callbackExecutor);

    /**
     * Adds a consumer to listen for Desktop task corner changes. This is used for gesture
     * exclusion. The SparseArray contains a list of four corner resize handles mapped to each
+19 −1
Original line number Diff line number Diff line
@@ -5724,6 +5724,16 @@ class DesktopTasksController(
        userRepositories.current.addVisibleTasksListener(listener, callbackExecutor)
    }

    /**
     * Adds a listener to find out about desk changes.
     *
     * @param listener the listener to add.
     * @param callbackExecutor the executor to call the listener on.
     */
    fun addDeskChangeListener(listener: DeskChangeListener, callbackExecutor: Executor) {
        userRepositories.current.addDeskChangeListener(listener, callbackExecutor)
    }

    /**
     * Adds a listener to track changes to desktop task gesture exclusion regions
     *
@@ -5800,7 +5810,6 @@ class DesktopTasksController(
                ) {
                    // Inherit parent's bounds.
                    newWindowBounds.set(taskInfo.configuration.windowConfiguration.bounds)

                } else {
                    newWindowBounds.set(calculateDefaultDesktopTaskBounds(displayLayout))
                }
@@ -5963,6 +5972,15 @@ class DesktopTasksController(
            }
        }

        override fun addDeskChangeListener(
            listener: DeskChangeListener,
            callbackExecutor: Executor,
        ) {
            mainExecutor.execute {
                this@DesktopTasksController.addDeskChangeListener(listener, callbackExecutor)
            }
        }

        override fun addDesktopGestureExclusionRegionListener(
            listener: Consumer<Region>,
            callbackExecutor: Executor,
+10 −0
Original line number Diff line number Diff line
@@ -1322,6 +1322,16 @@ flag {
    }
}

flag {
    name: "shade_app_launch_animation_skip_in_desktop"
    namespace: "systemui"
    description: "Fixes the animation for notification shade entry points in Desktop Mode"
    bug: "383061244"
    metadata {
        purpose: PURPOSE_BUGFIX
    }
}

flag {
  namespace: "systemui"
  name: "enable_view_capture_tracing"
+149 −0
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@ import android.widget.FrameLayout
import android.window.SplashScreen.SPLASH_SCREEN_STYLE_SOLID_COLOR
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.app.displaylib.PerDisplayRepository
import com.android.keyguard.KeyguardUpdateMonitor
import com.android.systemui.ActivityIntentHelper
import com.android.systemui.Flags
@@ -42,6 +43,7 @@ import com.android.systemui.communal.domain.interactor.CommunalSettingsInteracto
import com.android.systemui.keyguard.KeyguardViewMediator
import com.android.systemui.keyguard.WakefulnessLifecycle
import com.android.systemui.kosmos.testScope
import com.android.systemui.model.SysUiState
import com.android.systemui.plugins.ActivityStarter.OnDismissAction
import com.android.systemui.settings.UserTracker
import com.android.systemui.shade.ShadeController
@@ -49,6 +51,7 @@ import com.android.systemui.shade.data.repository.FakeShadeRepository
import com.android.systemui.shade.data.repository.ShadeAnimationRepository
import com.android.systemui.shade.domain.interactor.ShadeAnimationInteractorLegacyImpl
import com.android.systemui.shade.domain.interactor.ShadeDialogContextInteractor
import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_FREEFORM_ACTIVE_IN_DESKTOP_MODE
import com.android.systemui.statusbar.CommandQueue
import com.android.systemui.statusbar.NotificationLockscreenUserManager
import com.android.systemui.statusbar.NotificationShadeWindowController
@@ -108,6 +111,8 @@ class LegacyActivityStarterInternalImplTest : SysuiTestCase() {
    @Mock private lateinit var activityIntentHelper: ActivityIntentHelper
    @Mock private lateinit var communalSceneInteractor: CommunalSceneInteractor
    @Mock private lateinit var communalSettingsInteractor: CommunalSettingsInteractor
    @Mock private lateinit var perDisplaySysUiStateRepository: PerDisplayRepository<SysUiState>
    @Mock private lateinit var sysUIState: SysUiState
    private lateinit var underTest: LegacyActivityStarterInternalImpl
    private val kosmos = testKosmos()
    private val mainExecutor = FakeExecutor(FakeSystemClock())
@@ -118,6 +123,7 @@ class LegacyActivityStarterInternalImplTest : SysuiTestCase() {
    fun setUp() {
        MockitoAnnotations.initMocks(this)
        `when`(statusBarWindowControllerStore.defaultDisplay).thenReturn(statusBarWindowController)
        `when`(perDisplaySysUiStateRepository[anyInt()]).thenReturn(sysUIState)
        underTest =
            LegacyActivityStarterInternalImpl(
                centralSurfacesOptLazy = { Optional.of(centralSurfaces) },
@@ -145,6 +151,7 @@ class LegacyActivityStarterInternalImplTest : SysuiTestCase() {
                applicationScope = kosmos.testScope,
                communalSceneInteractor = communalSceneInteractor,
                communalSettingsInteractor = communalSettingsInteractor,
                perDisplaySysUiStateRepository = perDisplaySysUiStateRepository,
            )
        `when`(userTracker.userHandle).thenReturn(UserHandle.OWNER)
        `when`(communalSceneInteractor.isCommunalVisible).thenReturn(MutableStateFlow(false))
@@ -945,6 +952,148 @@ class LegacyActivityStarterInternalImplTest : SysuiTestCase() {
        )
    }

    @EnableFlags(
        Flags.FLAG_ANIMATION_LIBRARY_SHELL_MIGRATION,
        Flags.FLAG_SHADE_APP_LAUNCH_ANIMATION_SKIP_IN_DESKTOP,
    )
    @Test
    fun startActivity_skipAnimInDesktop_flagEnabled_inDesktop_noAnimate() {
        setupDesktopMode(enabled = true)
        val (controller, pendingIntent) = setupLaunchWithOccludedKeyguard()

        underTest.startPendingIntentDismissingKeyguard(
            intent = pendingIntent,
            dismissShade = true,
            animationController = controller,
            showOverLockscreen = true,
            skipLockscreenChecks = true,
        )
        mainExecutor.runAllReady()

        // Verify animate parameter is false
        verify(activityTransitionAnimator)
            .startPendingIntentWithAnimation(
                nullable(ActivityTransitionAnimator.Controller::class.java),
                eq(kosmos.testScope),
                /* animate */ eq(false),
                eq(false),
                eq(true),
                any(),
            )
    }

    @EnableFlags(Flags.FLAG_ANIMATION_LIBRARY_SHELL_MIGRATION)
    @DisableFlags(Flags.FLAG_SHADE_APP_LAUNCH_ANIMATION_SKIP_IN_DESKTOP)
    @Test
    fun startActivity_skipAnimInDesktop_flagDisabled_inDesktop_doAnimate() {
        setupDesktopMode(enabled = true)
        val (controller, pendingIntent) = setupLaunchWithOccludedKeyguard()

        underTest.startPendingIntentDismissingKeyguard(
            intent = pendingIntent,
            dismissShade = true,
            animationController = controller,
            showOverLockscreen = true,
            skipLockscreenChecks = true,
        )
        mainExecutor.runAllReady()

        // Verify animate parameter is true
        verify(activityTransitionAnimator)
            .startPendingIntentWithAnimation(
                nullable(ActivityTransitionAnimator.Controller::class.java),
                eq(kosmos.testScope),
                /* animate */ eq(true),
                eq(false),
                eq(true),
                any(),
            )
    }

    @EnableFlags(
        Flags.FLAG_ANIMATION_LIBRARY_SHELL_MIGRATION,
        Flags.FLAG_SHADE_APP_LAUNCH_ANIMATION_SKIP_IN_DESKTOP,
    )
    @Test
    fun startActivity_skipAnimInDesktop_flagEnabled_notInDesktop_doAnimate() {
        setupDesktopMode(enabled = false)
        val (controller, pendingIntent) = setupLaunchWithOccludedKeyguard()

        underTest.startPendingIntentDismissingKeyguard(
            intent = pendingIntent,
            dismissShade = true,
            animationController = controller,
            showOverLockscreen = true,
            skipLockscreenChecks = true,
        )
        mainExecutor.runAllReady()

        // Verify animate parameter is true
        verify(activityTransitionAnimator)
            .startPendingIntentWithAnimation(
                nullable(ActivityTransitionAnimator.Controller::class.java),
                eq(kosmos.testScope),
                /* animate */ eq(true),
                eq(false),
                eq(true),
                any(),
            )
    }

    @EnableFlags(Flags.FLAG_ANIMATION_LIBRARY_SHELL_MIGRATION)
    @DisableFlags(Flags.FLAG_SHADE_APP_LAUNCH_ANIMATION_SKIP_IN_DESKTOP)
    @Test
    fun startActivity_skipAnimInDesktop_flagDisabled_notInDesktop_doAnimate() {
        setupDesktopMode(enabled = false)
        val (controller, pendingIntent) = setupLaunchWithOccludedKeyguard()

        underTest.startPendingIntentDismissingKeyguard(
            intent = pendingIntent,
            dismissShade = true,
            animationController = controller,
            showOverLockscreen = true,
            skipLockscreenChecks = true,
        )
        mainExecutor.runAllReady()

        // Verify animate parameter is true
        verify(activityTransitionAnimator)
            .startPendingIntentWithAnimation(
                nullable(ActivityTransitionAnimator.Controller::class.java),
                eq(kosmos.testScope),
                /* animate */ eq(true),
                eq(false),
                eq(true),
                any(),
            )
    }

    private fun setupDesktopMode(enabled: Boolean) {
        val flags =
            if (enabled) {
                SYSUI_STATE_FREEFORM_ACTIVE_IN_DESKTOP_MODE
            } else {
                0L
            }
        `when`(sysUIState.flags).thenReturn(flags)
    }

    private fun setupLaunchWithOccludedKeyguard():
        Pair<ActivityTransitionAnimator.Controller?, PendingIntent> {
        val parent = FrameLayout(context)
        val view =
            object : View(context), LaunchableView {
                override fun setShouldBlockVisibilityChanges(block: Boolean) {}
            }
        parent.addView(view)
        val controller = ActivityTransitionAnimator.Controller.fromView(view)
        val pendingIntent = mock(PendingIntent::class.java)
        `when`(pendingIntent.isActivity).thenReturn(true)
        `when`(keyguardStateController.isShowing).thenReturn(true)
        `when`(keyguardStateController.isOccluded).thenReturn(true)
        return Pair(controller, pendingIntent)
    }

    private companion object {
        private const val DISPLAY_ID = 0
    }
+127 −1
Original line number Diff line number Diff line
@@ -19,16 +19,19 @@ import android.content.pm.UserInfo
import android.graphics.Color
import android.platform.test.annotations.DisableFlags
import android.platform.test.annotations.EnableFlags
import android.view.Display
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.keyguard.keyguardUpdateMonitor
import com.android.systemui.Flags.FLAG_COMMUNAL_HUB
import com.android.systemui.Flags.FLAG_GLANCEABLE_HUB_BLURRED_BACKGROUND
import com.android.systemui.Flags.FLAG_SHADE_APP_LAUNCH_ANIMATION_SKIP_IN_DESKTOP
import com.android.systemui.SysuiTestCase
import com.android.systemui.communal.domain.interactor.setCommunalAvailable
import com.android.systemui.communal.ui.viewmodel.communalTransitionViewModel
import com.android.systemui.communal.util.fakeCommunalColors
import com.android.systemui.concurrency.fakeExecutor
import com.android.systemui.display.data.repository.createPerDisplayInstanceSysUIStateRepository
import com.android.systemui.flags.Flags.COMMUNAL_SERVICE_ENABLED
import com.android.systemui.flags.fakeFeatureFlagsClassic
import com.android.systemui.keyguard.ScreenLifecycle
@@ -44,6 +47,7 @@ import com.android.systemui.model.sysUiState
import com.android.systemui.notetask.NoteTaskInitializer
import com.android.systemui.settings.FakeDisplayTracker
import com.android.systemui.settings.userTracker
import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_FREEFORM_ACTIVE_IN_DESKTOP_MODE
import com.android.systemui.statusbar.CommandQueue
import com.android.systemui.statusbar.commandQueue
import com.android.systemui.statusbar.commandline.commandRegistry
@@ -53,6 +57,7 @@ import com.android.systemui.testKosmos
import com.android.systemui.user.data.repository.fakeUserRepository
import com.android.systemui.util.kotlin.javaAdapter
import com.android.wm.shell.desktopmode.DesktopMode
import com.android.wm.shell.desktopmode.data.DesktopRepository
import com.android.wm.shell.desktopmode.data.DesktopRepository.VisibleTasksListener
import com.android.wm.shell.onehanded.OneHanded
import com.android.wm.shell.onehanded.OneHandedEventCallback
@@ -61,12 +66,13 @@ import com.android.wm.shell.pip.Pip
import com.android.wm.shell.recents.RecentTasks
import com.android.wm.shell.splitscreen.SplitScreen
import com.android.wm.shell.sysui.ShellInterface
import com.google.common.truth.Truth.assertThat
import java.util.Optional
import java.util.concurrent.Executor
import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentCaptor
import org.mockito.ArgumentMatchers.any
import org.mockito.Mockito.never
import org.mockito.Mockito.verify
@@ -91,6 +97,8 @@ class WMShellTest : SysuiTestCase() {
    private val Kosmos.screenLifecycle by Kosmos.Fixture { mock<ScreenLifecycle>() }
    private val Kosmos.displayTracker by Kosmos.Fixture { FakeDisplayTracker(context) }
    private val Kosmos.shellInterface by Kosmos.Fixture { mock<ShellInterface>() }
    private val Kosmos.perDisplayRepository by
        Kosmos.Fixture { createPerDisplayInstanceSysUIStateRepository() }

    private val Kosmos.underTest by
        Kosmos.Fixture {
@@ -116,6 +124,7 @@ class WMShellTest : SysuiTestCase() {
                /* communalTransitionViewModel = */ communalTransitionViewModel,
                /* javaAdapter = */ javaAdapter,
                /* sysUiMainExecutor = */ fakeExecutor,
                /* perDisplayRepository= */ perDisplayRepository,
            )
        }

@@ -152,6 +161,123 @@ class WMShellTest : SysuiTestCase() {
                    any(VisibleTasksListener::class.java),
                    any(Executor::class.java),
                )
            verify(desktopMode)
                .addDeskChangeListener(
                    any(DesktopRepository.DeskChangeListener::class.java),
                    any(Executor::class.java),
                )
        }

    @Test
    @EnableFlags(FLAG_SHADE_APP_LAUNCH_ANIMATION_SKIP_IN_DESKTOP)
    fun onActiveDeskChanged_enterDesktop_desktopStateIsActive() =
        kosmos.runTest {
            val displayId = Display.DEFAULT_DISPLAY
            val displaySysUiState = perDisplayRepository[displayId]
            underTest.initDesktopMode(desktopMode)
            val listenerCaptor =
                ArgumentCaptor.forClass(DesktopRepository.DeskChangeListener::class.java)
            verify(desktopMode)
                .addDeskChangeListener(listenerCaptor.capture(), any(Executor::class.java))
            val listener = listenerCaptor.value
            displaySysUiState
                ?.setFlag(SYSUI_STATE_FREEFORM_ACTIVE_IN_DESKTOP_MODE, false)
                ?.commitUpdate()

            listener.onActiveDeskChanged(
                displayId,
                newActiveDeskId = 1,
                oldActiveDeskId = DesktopRepository.INVALID_DESK_ID,
            )
            fakeExecutor.runAllReady()

            assertThat(
                    displaySysUiState?.isFlagEnabled(SYSUI_STATE_FREEFORM_ACTIVE_IN_DESKTOP_MODE)
                )
                .isTrue()
        }

    @Test
    @EnableFlags(FLAG_SHADE_APP_LAUNCH_ANIMATION_SKIP_IN_DESKTOP)
    fun onActiveDeskChanged_exitDesktop_desktopStateIsNotActive() =
        kosmos.runTest {
            val displayId = Display.DEFAULT_DISPLAY
            val displaySysUiState = perDisplayRepository[displayId]
            underTest.initDesktopMode(desktopMode)
            val listenerCaptor =
                ArgumentCaptor.forClass(DesktopRepository.DeskChangeListener::class.java)
            verify(desktopMode)
                .addDeskChangeListener(listenerCaptor.capture(), any(Executor::class.java))
            val listener = listenerCaptor.value
            displaySysUiState
                ?.setFlag(SYSUI_STATE_FREEFORM_ACTIVE_IN_DESKTOP_MODE, true)
                ?.commitUpdate()

            listener.onActiveDeskChanged(
                displayId,
                newActiveDeskId = DesktopRepository.INVALID_DESK_ID,
                oldActiveDeskId = 1,
            )
            fakeExecutor.runAllReady()

            assertThat(
                    displaySysUiState?.isFlagEnabled(SYSUI_STATE_FREEFORM_ACTIVE_IN_DESKTOP_MODE)
                )
                .isFalse()
        }

    @Test
    @EnableFlags(FLAG_SHADE_APP_LAUNCH_ANIMATION_SKIP_IN_DESKTOP)
    fun onActiveDeskChanged_stayInDesktop_desktopStateIsActive() =
        kosmos.runTest {
            val displayId = Display.DEFAULT_DISPLAY
            val displaySysUiState = perDisplayRepository[displayId]
            underTest.initDesktopMode(desktopMode)
            val listenerCaptor =
                ArgumentCaptor.forClass(DesktopRepository.DeskChangeListener::class.java)
            verify(desktopMode)
                .addDeskChangeListener(listenerCaptor.capture(), any(Executor::class.java))
            val listener = listenerCaptor.value
            displaySysUiState
                ?.setFlag(SYSUI_STATE_FREEFORM_ACTIVE_IN_DESKTOP_MODE, true)
                ?.commitUpdate()

            listener.onActiveDeskChanged(displayId, newActiveDeskId = 2, oldActiveDeskId = 1)
            fakeExecutor.runAllReady()

            assertThat(
                    displaySysUiState?.isFlagEnabled(SYSUI_STATE_FREEFORM_ACTIVE_IN_DESKTOP_MODE)
                )
                .isTrue()
        }

    @Test
    @EnableFlags(FLAG_SHADE_APP_LAUNCH_ANIMATION_SKIP_IN_DESKTOP)
    fun onActiveDeskChanged_stayOutsideDesktop_desktopStateIsNotActive() =
        kosmos.runTest {
            val displayId = Display.DEFAULT_DISPLAY
            val displaySysUiState = perDisplayRepository[displayId]
            underTest.initDesktopMode(desktopMode)
            val listenerCaptor =
                ArgumentCaptor.forClass(DesktopRepository.DeskChangeListener::class.java)
            verify(desktopMode)
                .addDeskChangeListener(listenerCaptor.capture(), any(Executor::class.java))
            val listener = listenerCaptor.value
            displaySysUiState
                ?.setFlag(SYSUI_STATE_FREEFORM_ACTIVE_IN_DESKTOP_MODE, false)
                ?.commitUpdate()

            listener.onActiveDeskChanged(
                displayId,
                newActiveDeskId = DesktopRepository.INVALID_DESK_ID,
                oldActiveDeskId = DesktopRepository.INVALID_DESK_ID,
            )
            fakeExecutor.runAllReady()

            assertThat(
                    displaySysUiState?.isFlagEnabled(SYSUI_STATE_FREEFORM_ACTIVE_IN_DESKTOP_MODE)
                )
                .isFalse()
        }

    @Test
Loading