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

Commit 3d55e090 authored by Sergey Pinkevich's avatar Sergey Pinkevich Committed by Android (Google) Code Review
Browse files

Merge "Check if the display is desktop first for Notification shade launch" into main

parents 3bb74cdc 5419b31e
Loading
Loading
Loading
Loading
+143 −4
Original line number Diff line number Diff line
@@ -42,6 +42,7 @@ import com.android.systemui.animation.LaunchableView
import com.android.systemui.assist.AssistManager
import com.android.systemui.communal.domain.interactor.CommunalSceneInteractor
import com.android.systemui.communal.domain.interactor.CommunalSettingsInteractor
import com.android.systemui.desktop.DesktopFirstRepository
import com.android.systemui.keyguard.KeyguardViewMediator
import com.android.systemui.keyguard.WakefulnessLifecycle
import com.android.systemui.kosmos.testScope
@@ -118,11 +119,14 @@ class LegacyActivityStarterInternalImplTest : SysuiTestCase() {
    @Mock private lateinit var perDisplaySysUiStateRepository: PerDisplayRepository<SysUiState>
    @Mock private lateinit var sysUIState: SysUiState
    @Mock private lateinit var remoteAnimationAdapter: RemoteAnimationAdapter
    @Mock private lateinit var mDesktopFirstRepository: DesktopFirstRepository
    private lateinit var underTest: LegacyActivityStarterInternalImpl
    private val kosmos = testKosmos()
    private val mainExecutor = FakeExecutor(FakeSystemClock())
    private val shadeAnimationInteractor =
        ShadeAnimationInteractorLegacyImpl(ShadeAnimationRepository(), FakeShadeRepository())
    private val desktopFirstStateForDefaultDisplay = mutableMapOf(DISPLAY_ID to true)
    private val nonDesktopFirstStateForDefaultDisplay = mutableMapOf(DISPLAY_ID to false)

    @Before
    fun setUp() {
@@ -158,12 +162,15 @@ class LegacyActivityStarterInternalImplTest : SysuiTestCase() {
                communalSceneInteractor = communalSceneInteractor,
                communalSettingsInteractor = communalSettingsInteractor,
                perDisplaySysUiStateRepository = perDisplaySysUiStateRepository,
                desktopFirstRepository = mDesktopFirstRepository,
            )
        `when`(userTracker.userHandle).thenReturn(UserHandle.OWNER)
        `when`(communalSceneInteractor.isCommunalVisible).thenReturn(MutableStateFlow(false))
        `when`(communalSceneInteractor.isIdleOnCommunal).thenReturn(MutableStateFlow(false))
        `when`(communalSceneInteractor.isLaunchingWidget).thenReturn(MutableStateFlow(false))
        `when`(shadeDialogContextInteractor.context).thenReturn(context)
        `when`(mDesktopFirstRepository.isDisplayDesktopFirst)
            .thenReturn(nonDesktopFirstStateForDefaultDisplay)
    }

    @Test
@@ -1003,8 +1010,10 @@ class LegacyActivityStarterInternalImplTest : SysuiTestCase() {
        Flags.FLAG_SHADE_APP_LAUNCH_ANIMATION_SKIP_IN_DESKTOP,
    )
    @Test
    fun startActivity_skipAnimInDesktop_flagEnabled_inDesktop_noAnimate() {
    fun startActivity_skipAnimInDesktop_flagEnabled_inDesktop_desktopFirst_noAnimate() {
        setupDesktopMode(enabled = true)
        `when`(mDesktopFirstRepository.isDisplayDesktopFirst)
            .thenReturn(desktopFirstStateForDefaultDisplay)
        val (controller, pendingIntent) = setupLaunchWithOccludedKeyguard()

        underTest.startPendingIntentDismissingKeyguard(
@@ -1028,11 +1037,75 @@ 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_notDesktopFirst_noAnimate() {
        setupDesktopMode(enabled = true)
        `when`(mDesktopFirstRepository.isDisplayDesktopFirst)
            .thenReturn(nonDesktopFirstStateForDefaultDisplay)
        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_desktopFirst_doAnimate() {
        setupDesktopMode(enabled = true)
        `when`(mDesktopFirstRepository.isDisplayDesktopFirst)
            .thenReturn(desktopFirstStateForDefaultDisplay)
        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_inDesktop_doAnimate() {
    fun startActivity_skipAnimInDesktop_flagDisabled_inDesktop_noDesktopFirst_doAnimate() {
        setupDesktopMode(enabled = true)
        `when`(mDesktopFirstRepository.isDisplayDesktopFirst)
            .thenReturn(nonDesktopFirstStateForDefaultDisplay)
        val (controller, pendingIntent) = setupLaunchWithOccludedKeyguard()

        underTest.startPendingIntentDismissingKeyguard(
@@ -1061,8 +1134,72 @@ class LegacyActivityStarterInternalImplTest : SysuiTestCase() {
        Flags.FLAG_SHADE_APP_LAUNCH_ANIMATION_SKIP_IN_DESKTOP,
    )
    @Test
    fun startActivity_skipAnimInDesktop_flagEnabled_notInDesktop_doAnimate() {
    fun startActivity_skipAnimInDesktop_flagEnabled_notInDesktop_desktopFirst_notAnimate() {
        setupDesktopMode(enabled = false)
        `when`(mDesktopFirstRepository.isDisplayDesktopFirst)
            .thenReturn(desktopFirstStateForDefaultDisplay)
        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,
        Flags.FLAG_SHADE_APP_LAUNCH_ANIMATION_SKIP_IN_DESKTOP,
    )
    @Test
    fun startActivity_skipAnimInDesktop_flagEnabled_notInDesktop_notDesktopFirst_doAnimate() {
        setupDesktopMode(enabled = false)
        `when`(mDesktopFirstRepository.isDisplayDesktopFirst)
            .thenReturn(nonDesktopFirstStateForDefaultDisplay)
        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_desktopFirst_doAnimate() {
        setupDesktopMode(enabled = false)
        `when`(mDesktopFirstRepository.isDisplayDesktopFirst)
            .thenReturn(desktopFirstStateForDefaultDisplay)
        val (controller, pendingIntent) = setupLaunchWithOccludedKeyguard()

        underTest.startPendingIntentDismissingKeyguard(
@@ -1089,8 +1226,10 @@ class LegacyActivityStarterInternalImplTest : SysuiTestCase() {
    @EnableFlags(Flags.FLAG_ANIMATION_LIBRARY_SHELL_MIGRATION)
    @DisableFlags(Flags.FLAG_SHADE_APP_LAUNCH_ANIMATION_SKIP_IN_DESKTOP)
    @Test
    fun startActivity_skipAnimInDesktop_flagDisabled_notInDesktop_doAnimate() {
    fun startActivity_skipAnimInDesktop_flagDisabled_notInDesktop_notDesktopFirst_doAnimate() {
        setupDesktopMode(enabled = false)
        `when`(mDesktopFirstRepository.isDisplayDesktopFirst)
            .thenReturn(nonDesktopFirstStateForDefaultDisplay)
        val (controller, pendingIntent) = setupLaunchWithOccludedKeyguard()

        underTest.startPendingIntentDismissingKeyguard(
+48 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2025 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.systemui.desktop

import com.android.systemui.dagger.SysUISingleton
import com.android.wm.shell.desktopmode.DesktopMode
import com.android.wm.shell.shared.desktopmode.DesktopFirstListener
import java.util.Optional
import javax.inject.Inject

/**
 * Repository that tracks whether a display is in "Desktop First" mode.
 *
 * "Desktop First" mode for a display means that newly opened applications on that particular
 * display will launch in [WindowConfiguration.WINDOWING_MODE_FREEFORM].
 *
 * This repository listens to changes from [DesktopMode] and maintains the state for each display
 * ID.
 */
@SysUISingleton
class DesktopFirstRepository @Inject constructor(desktopMode: Optional<DesktopMode>) :
    DesktopFirstListener {

    private val _isDisplayDesktopFirst: MutableMap<Int, Boolean> = mutableMapOf()
    val isDisplayDesktopFirst: Map<Int, Boolean> = _isDisplayDesktopFirst.toMap()

    init {
        desktopMode.ifPresent { desktopMode.get().registerDesktopFirstListener(this) }
    }

    override fun onStateChanged(displayId: Int, isDesktopFirstEnabled: Boolean) {
        _isDisplayDesktopFirst[displayId] = isDesktopFirstEnabled
    }
}
+31 −21
Original line number Diff line number Diff line
@@ -46,6 +46,7 @@ import com.android.systemui.communal.shared.model.CommunalScenes
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.desktop.DesktopFirstRepository
import com.android.systemui.deviceentry.domain.interactor.DeviceEntryInteractor
import com.android.systemui.keyguard.KeyguardViewMediator
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
@@ -107,20 +108,22 @@ constructor(
    private val commandQueue: CommandQueue,
    private val lockScreenUserManager: NotificationLockscreenUserManager,
    private val perDisplaySysUiStateRepository: PerDisplayRepository<SysUiState>,
    private val desktopFirstRepository: DesktopFirstRepository,
) : ActivityStarterInternal {
    private val centralSurfaces: CentralSurfaces?
        get() = centralSurfacesOptLazy.get().getOrNull()

    private val context: Context
    private val currentShadeContext: Context
        get() = contextInteractor.context

    private val displayId: Int
        get() = context.displayId
    private val currentShadeDisplayId: Int
        get() = currentShadeContext.displayId

    private val isInDesktopMode: Boolean
        get() =
            ((perDisplaySysUiStateRepository[displayId]?.flags ?: 0) and
                SYSUI_STATE_FREEFORM_ACTIVE_IN_DESKTOP_MODE) != 0L
    private val shadeSysUiState: Long
        get() = perDisplaySysUiStateRepository[currentShadeDisplayId]?.flags ?: 0

    private val isInDesktopModeOnCurrentShadeDisplay: Boolean
        get() = (shadeSysUiState and SYSUI_STATE_FREEFORM_ACTIVE_IN_DESKTOP_MODE) != 0L

    override fun registerTransition(
        cookie: ActivityTransitionAnimator.TransitionCookie,
@@ -228,7 +231,7 @@ constructor(
                )

                intent.sendAndReturnResult(
                    context,
                    currentShadeContext,
                    0,
                    fillInIntent,
                    null,
@@ -253,7 +256,7 @@ constructor(
                                ): Int {
                                    return startIntent(
                                        createActivityOptions(
                                            displayId,
                                            currentShadeDisplayId,
                                            transition,
                                            controllerWithCookie?.transitionCookie,
                                        )
@@ -272,7 +275,10 @@ constructor(
                                animationAdapter: RemoteAnimationAdapter?
                            ): Int {
                                return startIntent(
                                    CentralSurfaces.getActivityOptions(displayId, animationAdapter)
                                    CentralSurfaces.getActivityOptions(
                                        currentShadeDisplayId,
                                        animationAdapter,
                                    )
                                )
                            }
                        },
@@ -421,10 +427,10 @@ constructor(
                    result[0] =
                        activityTaskManager.startActivityAsUser(
                            null,
                            context.basePackageName,
                            context.attributionTag,
                            currentShadeContext.basePackageName,
                            currentShadeContext.attributionTag,
                            intent,
                            intent.resolveTypeIfNeeded(context.contentResolver),
                            intent.resolveTypeIfNeeded(currentShadeContext.contentResolver),
                            null,
                            null,
                            0,
@@ -448,7 +454,7 @@ constructor(
                ) { transition: RemoteTransition? ->
                    startIntent(
                        createActivityOptions(
                            displayId,
                            currentShadeDisplayId,
                            transition,
                            controllerWithCookie?.transitionCookie,
                        )
@@ -460,7 +466,7 @@ constructor(
                    animate,
                    intent.getPackage(),
                ) { adapter: RemoteAnimationAdapter? ->
                    startIntent(CentralSurfaces.getActivityOptions(displayId, adapter))
                    startIntent(CentralSurfaces.getActivityOptions(currentShadeDisplayId, adapter))
                }
            }

@@ -545,11 +551,11 @@ constructor(
                animate = animate,
                showOverLockscreen = showOverLockscreenWhenLocked,
            ) { transition: RemoteTransition? ->
                TaskStackBuilder.create(context)
                TaskStackBuilder.create(currentShadeContext)
                    .addNextIntent(intent)
                    .startActivities(
                        createActivityOptions(
                            displayId,
                            currentShadeDisplayId,
                            transition,
                            controllerWithCookie?.transitionCookie,
                        ),
@@ -563,10 +569,10 @@ constructor(
                intent.getPackage(),
                showOverLockscreenWhenLocked,
            ) { adapter: RemoteAnimationAdapter? ->
                TaskStackBuilder.create(context)
                TaskStackBuilder.create(currentShadeContext)
                    .addNextIntent(intent)
                    .startActivities(
                        CentralSurfaces.getActivityOptions(displayId, adapter),
                        CentralSurfaces.getActivityOptions(currentShadeDisplayId, adapter),
                        userHandle,
                    )
            }
@@ -656,7 +662,11 @@ constructor(
            return false
        }

        if (shadeAppLaunchAnimationSkipInDesktop() && isInDesktopMode) {
        if (
            shadeAppLaunchAnimationSkipInDesktop() &&
                (isInDesktopModeOnCurrentShadeDisplay ||
                    desktopFirstRepository.isDisplayDesktopFirst[currentShadeDisplayId] == true)
        ) {
            return false
        }

@@ -732,7 +742,7 @@ constructor(
                    shadeControllerLazy.get(),
                    notifShadeWindowControllerLazy.get(),
                    commandQueue,
                    displayId,
                    currentShadeDisplayId,
                    isLaunchForActivity,
                )
            }
+33 −22
Original line number Diff line number Diff line
@@ -45,6 +45,7 @@ import com.android.systemui.communal.domain.interactor.CommunalSettingsInteracto
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.desktop.DesktopFirstRepository
import com.android.systemui.keyguard.KeyguardViewMediator
import com.android.systemui.keyguard.WakefulnessLifecycle
import com.android.systemui.model.SysUiState
@@ -103,20 +104,22 @@ constructor(
    private val communalSceneInteractor: CommunalSceneInteractor,
    private val communalSettingsInteractor: CommunalSettingsInteractor,
    private val perDisplaySysUiStateRepository: PerDisplayRepository<SysUiState>,
    private val desktopFirstRepository: DesktopFirstRepository,
) : ActivityStarterInternal {
    private val centralSurfaces: CentralSurfaces?
        get() = centralSurfacesOptLazy.get().getOrNull()

    private val context: Context
    private val currentShadeContext: Context
        get() = contextInteractor.context

    private val displayId: Int
        get() = context.displayId
    private val currentShadeDisplayId: Int
        get() = currentShadeContext.displayId

    private val isInDesktopMode: Boolean
        get() =
            ((perDisplaySysUiStateRepository[displayId]?.flags ?: 0) and
                SYSUI_STATE_FREEFORM_ACTIVE_IN_DESKTOP_MODE) != 0L
    private val shadeSysUiState: Long
        get() = perDisplaySysUiStateRepository[currentShadeDisplayId]?.flags ?: 0

    private val isInDesktopModeOnCurrentShadeDisplay: Boolean
        get() = (shadeSysUiState and SYSUI_STATE_FREEFORM_ACTIVE_IN_DESKTOP_MODE) != 0L

    override fun registerTransition(
        cookie: ActivityTransitionAnimator.TransitionCookie,
@@ -260,10 +263,10 @@ constructor(
                    result[0] =
                        activityTaskManager.startActivityAsUser(
                            null,
                            context.basePackageName,
                            context.attributionTag,
                            currentShadeContext.basePackageName,
                            currentShadeContext.attributionTag,
                            intent,
                            intent.resolveTypeIfNeeded(context.contentResolver),
                            intent.resolveTypeIfNeeded(currentShadeContext.contentResolver),
                            null,
                            null,
                            0,
@@ -287,7 +290,7 @@ constructor(
                ) { transition: RemoteTransition? ->
                    startIntent(
                        createActivityOptions(
                            displayId,
                            currentShadeDisplayId,
                            transition,
                            controllerWithCookie?.transitionCookie,
                        )
@@ -299,7 +302,7 @@ constructor(
                    animate,
                    intent.getPackage(),
                ) { adapter: RemoteAnimationAdapter? ->
                    startIntent(CentralSurfaces.getActivityOptions(displayId, adapter))
                    startIntent(CentralSurfaces.getActivityOptions(currentShadeDisplayId, adapter))
                }
            }

@@ -399,7 +402,7 @@ constructor(
                )

                intent.sendAndReturnResult(
                    context,
                    currentShadeContext,
                    0,
                    fillInIntent,
                    null,
@@ -424,7 +427,7 @@ constructor(
                                ): Int {
                                    return startIntent(
                                        createActivityOptions(
                                            displayId,
                                            currentShadeDisplayId,
                                            transition,
                                            controllerWithCookie?.transitionCookie,
                                        )
@@ -443,7 +446,10 @@ constructor(
                                animationAdapter: RemoteAnimationAdapter?
                            ): Int {
                                return startIntent(
                                    CentralSurfaces.getActivityOptions(displayId, animationAdapter)
                                    CentralSurfaces.getActivityOptions(
                                        currentShadeDisplayId,
                                        animationAdapter,
                                    )
                                )
                            }
                        },
@@ -540,11 +546,11 @@ constructor(
                animate = animate,
                showOverLockscreen = showOverLockscreenWhenLocked,
            ) { transition: RemoteTransition? ->
                TaskStackBuilder.create(context)
                TaskStackBuilder.create(currentShadeContext)
                    .addNextIntent(intent)
                    .startActivities(
                        createActivityOptions(
                            displayId,
                            currentShadeDisplayId,
                            transition,
                            controllerWithCookie?.transitionCookie,
                        ),
@@ -558,10 +564,10 @@ constructor(
                intent.getPackage(),
                showOverLockscreenWhenLocked,
            ) { adapter: RemoteAnimationAdapter? ->
                TaskStackBuilder.create(context)
                TaskStackBuilder.create(currentShadeContext)
                    .addNextIntent(intent)
                    .startActivities(
                        CentralSurfaces.getActivityOptions(displayId, adapter),
                        CentralSurfaces.getActivityOptions(currentShadeDisplayId, adapter),
                        userHandle,
                    )
            }
@@ -690,7 +696,7 @@ constructor(
                    shadeControllerLazy.get(),
                    notifShadeWindowControllerLazy.get(),
                    commandQueue,
                    displayId,
                    currentShadeDisplayId,
                    isLaunchForActivity,
                )
            }
@@ -767,7 +773,8 @@ constructor(

    /** Retrieves the current user handle to start the Activity. */
    private fun getActivityUserHandle(intent: Intent): UserHandle {
        val packages: Array<String> = context.resources.getStringArray(R.array.system_ui_packages)
        val packages: Array<String> =
            currentShadeContext.resources.getStringArray(R.array.system_ui_packages)
        for (pkg in packages) {
            val componentName = intent.component ?: break
            if (pkg == componentName.packageName) {
@@ -792,7 +799,11 @@ constructor(
            return false
        }

        if (shadeAppLaunchAnimationSkipInDesktop() && isInDesktopMode) {
        if (
            shadeAppLaunchAnimationSkipInDesktop() &&
                (isInDesktopModeOnCurrentShadeDisplay ||
                    desktopFirstRepository.isDisplayDesktopFirst[currentShadeDisplayId] == true)
        ) {
            return false
        }