Move showUserSwitcher to UserInteractor

This method will be needed by the status bar user chip, and has the
equivalent behavior that was defined in `FooterActionsInteractor`. This
CL moves the implementation + tests up from `FooterActionsInteractor` to
a new dependency on `UserInteractor`

Test: atest UserInteractorTest
Bug: 254246505
Change-Id: Ia78513a0f86a5ade8727855f677919abac82b3b1
This commit is contained in:
Evan Laird
2022-11-11 15:07:58 -05:00
parent e182b0d479
commit 27ff98f799
9 changed files with 183 additions and 87 deletions

View File

@@ -32,8 +32,6 @@ import com.android.systemui.animation.Expandable
import com.android.systemui.broadcast.BroadcastDispatcher
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags
import com.android.systemui.globalactions.GlobalActionsDialogLite
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.qs.FgsManagerController
@@ -42,10 +40,9 @@ import com.android.systemui.qs.footer.data.model.UserSwitcherStatusModel
import com.android.systemui.qs.footer.data.repository.ForegroundServicesRepository
import com.android.systemui.qs.footer.data.repository.UserSwitcherRepository
import com.android.systemui.qs.footer.domain.model.SecurityButtonConfig
import com.android.systemui.qs.user.UserSwitchDialogController
import com.android.systemui.security.data.repository.SecurityRepository
import com.android.systemui.statusbar.policy.DeviceProvisionedController
import com.android.systemui.user.UserSwitcherActivity
import com.android.systemui.user.domain.interactor.UserInteractor
import javax.inject.Inject
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.flow.Flow
@@ -100,13 +97,12 @@ class FooterActionsInteractorImpl
@Inject
constructor(
private val activityStarter: ActivityStarter,
private val featureFlags: FeatureFlags,
private val metricsLogger: MetricsLogger,
private val uiEventLogger: UiEventLogger,
private val deviceProvisionedController: DeviceProvisionedController,
private val qsSecurityFooterUtils: QSSecurityFooterUtils,
private val fgsManagerController: FgsManagerController,
private val userSwitchDialogController: UserSwitchDialogController,
private val userInteractor: UserInteractor,
securityRepository: SecurityRepository,
foregroundServicesRepository: ForegroundServicesRepository,
userSwitcherRepository: UserSwitcherRepository,
@@ -182,22 +178,6 @@ constructor(
}
override fun showUserSwitcher(context: Context, expandable: Expandable) {
if (!featureFlags.isEnabled(Flags.FULL_SCREEN_USER_SWITCHER)) {
userSwitchDialogController.showDialog(context, expandable)
return
}
val intent =
Intent(context, UserSwitcherActivity::class.java).apply {
addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_NEW_TASK)
}
activityStarter.startActivity(
intent,
true /* dismissShade */,
expandable.activityLaunchController(),
true /* showOverlockscreenwhenlocked */,
UserHandle.SYSTEM,
)
userInteractor.showUserSwitcher(context, expandable)
}
}

View File

@@ -34,15 +34,19 @@ import android.util.Log
import com.android.internal.util.UserIcons
import com.android.systemui.R
import com.android.systemui.SystemUISecondaryUserService
import com.android.systemui.animation.Expandable
import com.android.systemui.broadcast.BroadcastDispatcher
import com.android.systemui.common.shared.model.Text
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.qs.user.UserSwitchDialogController
import com.android.systemui.telephony.domain.interactor.TelephonyInteractor
import com.android.systemui.user.UserSwitcherActivity
import com.android.systemui.user.data.model.UserSwitcherSettingsModel
import com.android.systemui.user.data.repository.UserRepository
import com.android.systemui.user.data.source.UserRecord
@@ -81,6 +85,7 @@ constructor(
private val repository: UserRepository,
private val activityStarter: ActivityStarter,
private val keyguardInteractor: KeyguardInteractor,
private val featureFlags: FeatureFlags,
private val manager: UserManager,
@Application private val applicationScope: CoroutineScope,
telephonyInteractor: TelephonyInteractor,
@@ -468,6 +473,26 @@ constructor(
}
}
fun showUserSwitcher(context: Context, expandable: Expandable) {
if (!featureFlags.isEnabled(Flags.FULL_SCREEN_USER_SWITCHER)) {
showDialog(ShowDialogRequestModel.ShowUserSwitcherDialog)
return
}
val intent =
Intent(context, UserSwitcherActivity::class.java).apply {
addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_NEW_TASK)
}
activityStarter.startActivity(
intent,
true /* dismissShade */,
expandable.activityLaunchController(),
true /* showOverlockscreenwhenlocked */,
UserHandle.SYSTEM,
)
}
private fun showDialog(request: ShowDialogRequestModel) {
_dialogShowRequests.value = request
}

View File

@@ -43,4 +43,7 @@ sealed class ShowDialogRequestModel(
val onExitGuestUser: (guestId: Int, targetId: Int, forceRemoveGuest: Boolean) -> Unit,
override val dialogShower: UserSwitchDialogController.DialogShower?,
) : ShowDialogRequestModel(dialogShower)
/** Show the user switcher dialog */
object ShowUserSwitcherDialog : ShowDialogRequestModel()
}

View File

@@ -0,0 +1,68 @@
package com.android.systemui.user.ui.dialog
import android.content.Context
import android.content.Intent
import android.provider.Settings
import android.view.LayoutInflater
import com.android.internal.logging.UiEventLogger
import com.android.systemui.R
import com.android.systemui.animation.DialogLaunchAnimator
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.plugins.FalsingManager
import com.android.systemui.qs.QSUserSwitcherEvent
import com.android.systemui.qs.tiles.UserDetailView
import com.android.systemui.statusbar.phone.SystemUIDialog
/**
* Extracted from the old UserSwitchDialogController. This is the dialog version of the full-screen
* user switcher. See config_enableFullscreenUserSwitcher
*/
class UserSwitchDialog(
context: Context,
adapter: UserDetailView.Adapter,
uiEventLogger: UiEventLogger,
falsingManager: FalsingManager,
activityStarter: ActivityStarter,
dialogLaunchAnimator: DialogLaunchAnimator,
) : SystemUIDialog(context) {
init {
setShowForAllUsers(true)
setCanceledOnTouchOutside(true)
setTitle(R.string.qs_user_switch_dialog_title)
setPositiveButton(R.string.quick_settings_done) { _, _ ->
uiEventLogger.log(QSUserSwitcherEvent.QS_USER_DETAIL_CLOSE)
}
setNeutralButton(
R.string.quick_settings_more_user_settings,
{ _, _ ->
if (!falsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) {
uiEventLogger.log(QSUserSwitcherEvent.QS_USER_MORE_SETTINGS)
val controller =
dialogLaunchAnimator.createActivityLaunchController(
getButton(BUTTON_NEUTRAL)
)
if (controller == null) {
dismiss()
}
activityStarter.postStartActivityDismissingKeyguard(
USER_SETTINGS_INTENT,
0,
controller
)
}
},
false /* dismissOnClick */
)
val gridFrame =
LayoutInflater.from(this.context).inflate(R.layout.qs_user_dialog_content, null)
setView(gridFrame)
adapter.linkToViewGroup(gridFrame.findViewById(R.id.grid))
}
companion object {
private val USER_SETTINGS_INTENT = Intent(Settings.ACTION_USER_SETTINGS)
}
}

View File

@@ -20,6 +20,7 @@ package com.android.systemui.user.ui.dialog
import android.app.Dialog
import android.content.Context
import com.android.internal.jank.InteractionJankMonitor
import com.android.internal.logging.UiEventLogger
import com.android.settingslib.users.UserCreatingDialog
import com.android.systemui.CoreStartable
import com.android.systemui.animation.DialogCuj
@@ -27,11 +28,14 @@ import com.android.systemui.animation.DialogLaunchAnimator
import com.android.systemui.broadcast.BroadcastSender
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.plugins.FalsingManager
import com.android.systemui.qs.tiles.UserDetailView
import com.android.systemui.user.domain.interactor.UserInteractor
import com.android.systemui.user.domain.model.ShowDialogRequestModel
import dagger.Lazy
import javax.inject.Inject
import javax.inject.Provider
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.launch
@@ -47,6 +51,9 @@ constructor(
private val broadcastSender: Lazy<BroadcastSender>,
private val dialogLaunchAnimator: Lazy<DialogLaunchAnimator>,
private val interactor: Lazy<UserInteractor>,
private val userDetailAdapterProvider: Provider<UserDetailView.Adapter>,
private val eventLogger: Lazy<UiEventLogger>,
private val activityStarter: Lazy<ActivityStarter>,
) : CoreStartable {
private var currentDialog: Dialog? = null
@@ -108,6 +115,21 @@ constructor(
INTERACTION_JANK_EXIT_GUEST_MODE_TAG,
),
)
is ShowDialogRequestModel.ShowUserSwitcherDialog ->
Pair(
UserSwitchDialog(
context = context.get(),
adapter = userDetailAdapterProvider.get(),
uiEventLogger = eventLogger.get(),
falsingManager = falsingManager.get(),
activityStarter = activityStarter.get(),
dialogLaunchAnimator = dialogLaunchAnimator.get(),
),
DialogCuj(
InteractionJankMonitor.CUJ_USER_DIALOG_OPEN,
INTERACTION_JANK_EXIT_GUEST_MODE_TAG,
),
)
}
currentDialog = dialog

View File

@@ -16,10 +16,8 @@
package com.android.systemui.qs.footer.domain.interactor
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.os.UserHandle
import android.provider.Settings
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
@@ -30,17 +28,13 @@ import com.android.internal.logging.testing.UiEventLoggerFake
import com.android.systemui.SysuiTestCase
import com.android.systemui.animation.ActivityLaunchAnimator
import com.android.systemui.animation.Expandable
import com.android.systemui.flags.FakeFeatureFlags
import com.android.systemui.flags.Flags
import com.android.systemui.globalactions.GlobalActionsDialogLite
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.qs.QSSecurityFooterUtils
import com.android.systemui.qs.footer.FooterActionsTestUtils
import com.android.systemui.qs.user.UserSwitchDialogController
import com.android.systemui.statusbar.policy.DeviceProvisionedController
import com.android.systemui.truth.correspondence.FakeUiEvent
import com.android.systemui.truth.correspondence.LogMaker
import com.android.systemui.user.UserSwitcherActivity
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.argumentCaptor
import com.android.systemui.util.mockito.eq
@@ -156,54 +150,4 @@ class FooterActionsInteractorTest : SysuiTestCase() {
// We only unlock the device.
verify(activityStarter).postQSRunnableDismissingKeyguard(any())
}
@Test
fun showUserSwitcher_fullScreenDisabled() {
val featureFlags = FakeFeatureFlags().apply { set(Flags.FULL_SCREEN_USER_SWITCHER, false) }
val userSwitchDialogController = mock<UserSwitchDialogController>()
val underTest =
utils.footerActionsInteractor(
featureFlags = featureFlags,
userSwitchDialogController = userSwitchDialogController,
)
val expandable = mock<Expandable>()
underTest.showUserSwitcher(context, expandable)
// Dialog is shown.
verify(userSwitchDialogController).showDialog(context, expandable)
}
@Test
fun showUserSwitcher_fullScreenEnabled() {
val featureFlags = FakeFeatureFlags().apply { set(Flags.FULL_SCREEN_USER_SWITCHER, true) }
val activityStarter = mock<ActivityStarter>()
val underTest =
utils.footerActionsInteractor(
featureFlags = featureFlags,
activityStarter = activityStarter,
)
// The clicked expandable.
val expandable = mock<Expandable>()
underTest.showUserSwitcher(context, expandable)
// Dialog is shown.
val intentCaptor = argumentCaptor<Intent>()
verify(activityStarter)
.startActivity(
intentCaptor.capture(),
/* dismissShade= */ eq(true),
/* ActivityLaunchAnimator.Controller= */ nullable(),
/* showOverLockscreenWhenLocked= */ eq(true),
eq(UserHandle.SYSTEM),
)
assertThat(intentCaptor.value.component)
.isEqualTo(
ComponentName(
context,
UserSwitcherActivity::class.java,
)
)
}
}

View File

@@ -19,6 +19,7 @@ package com.android.systemui.user.domain.interactor
import android.app.ActivityManager
import android.app.admin.DevicePolicyManager
import android.content.ComponentName
import android.content.Intent
import android.content.pm.UserInfo
import android.graphics.Bitmap
@@ -33,7 +34,10 @@ import com.android.systemui.GuestResetOrExitSessionReceiver
import com.android.systemui.GuestResumeSessionReceiver
import com.android.systemui.R
import com.android.systemui.SysuiTestCase
import com.android.systemui.animation.Expandable
import com.android.systemui.common.shared.model.Text
import com.android.systemui.flags.FakeFeatureFlags
import com.android.systemui.flags.Flags
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
import com.android.systemui.plugins.ActivityStarter
@@ -41,6 +45,7 @@ import com.android.systemui.qs.user.UserSwitchDialogController
import com.android.systemui.statusbar.policy.DeviceProvisionedController
import com.android.systemui.telephony.data.repository.FakeTelephonyRepository
import com.android.systemui.telephony.domain.interactor.TelephonyInteractor
import com.android.systemui.user.UserSwitcherActivity
import com.android.systemui.user.data.model.UserSwitcherSettingsModel
import com.android.systemui.user.data.repository.FakeUserRepository
import com.android.systemui.user.data.source.UserRecord
@@ -48,9 +53,11 @@ import com.android.systemui.user.domain.model.ShowDialogRequestModel
import com.android.systemui.user.shared.model.UserActionModel
import com.android.systemui.user.shared.model.UserModel
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.argumentCaptor
import com.android.systemui.util.mockito.eq
import com.android.systemui.util.mockito.kotlinArgumentCaptor
import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.nullable
import com.android.systemui.util.mockito.whenever
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.Dispatchers
@@ -90,6 +97,7 @@ class UserInteractorTest : SysuiTestCase() {
private lateinit var userRepository: FakeUserRepository
private lateinit var keyguardRepository: FakeKeyguardRepository
private lateinit var telephonyRepository: FakeTelephonyRepository
private lateinit var featureFlags: FakeFeatureFlags
@Before
fun setUp() {
@@ -104,6 +112,7 @@ class UserInteractorTest : SysuiTestCase() {
SUPERVISED_USER_CREATION_APP_PACKAGE,
)
featureFlags = FakeFeatureFlags()
userRepository = FakeUserRepository()
keyguardRepository = FakeKeyguardRepository()
telephonyRepository = FakeTelephonyRepository()
@@ -147,7 +156,8 @@ class UserInteractorTest : SysuiTestCase() {
uiEventLogger = uiEventLogger,
resumeSessionReceiver = resumeSessionReceiver,
resetOrExitSessionReceiver = resetOrExitSessionReceiver,
)
),
featureFlags = featureFlags,
)
}
@@ -715,6 +725,52 @@ class UserInteractorTest : SysuiTestCase() {
job.cancel()
}
@Test
fun `show user switcher - full screen disabled - shows dialog switcher`() =
runBlocking(IMMEDIATE) {
featureFlags.set(Flags.FULL_SCREEN_USER_SWITCHER, false)
var dialogRequest: ShowDialogRequestModel? = null
val expandable = mock<Expandable>()
underTest.showUserSwitcher(context, expandable)
val job = underTest.dialogShowRequests.onEach { dialogRequest = it }.launchIn(this)
// Dialog is shown.
assertThat(dialogRequest).isEqualTo(ShowDialogRequestModel.ShowUserSwitcherDialog)
underTest.onDialogShown()
assertThat(dialogRequest).isNull()
job.cancel()
}
@Test
fun `show user switcher - full screen enabled - launches activity`() {
featureFlags.set(Flags.FULL_SCREEN_USER_SWITCHER, true)
val expandable = mock<Expandable>()
underTest.showUserSwitcher(context, expandable)
// Dialog is shown.
val intentCaptor = argumentCaptor<Intent>()
verify(activityStarter)
.startActivity(
intentCaptor.capture(),
/* dismissShade= */ eq(true),
/* ActivityLaunchAnimator.Controller= */ nullable(),
/* showOverLockscreenWhenLocked= */ eq(true),
eq(UserHandle.SYSTEM),
)
assertThat(intentCaptor.value.component)
.isEqualTo(
ComponentName(
context,
UserSwitcherActivity::class.java,
)
)
}
private fun assertUsers(
models: List<UserModel>?,
count: Int,

View File

@@ -27,6 +27,7 @@ import com.android.systemui.GuestResetOrExitSessionReceiver
import com.android.systemui.GuestResumeSessionReceiver
import com.android.systemui.SysuiTestCase
import com.android.systemui.common.shared.model.Text
import com.android.systemui.flags.FakeFeatureFlags
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
import com.android.systemui.plugins.ActivityStarter
@@ -147,6 +148,7 @@ class UserSwitcherViewModelTest : SysuiTestCase() {
KeyguardInteractor(
repository = keyguardRepository,
),
featureFlags = FakeFeatureFlags(),
manager = manager,
applicationScope = injectedScope,
telephonyInteractor =

View File

@@ -28,8 +28,6 @@ import com.android.internal.logging.testing.UiEventLoggerFake
import com.android.systemui.broadcast.BroadcastDispatcher
import com.android.systemui.classifier.FalsingManagerFake
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.flags.FakeFeatureFlags
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.globalactions.GlobalActionsDialogLite
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.plugins.FalsingManager
@@ -43,7 +41,6 @@ import com.android.systemui.qs.footer.data.repository.UserSwitcherRepositoryImpl
import com.android.systemui.qs.footer.domain.interactor.FooterActionsInteractor
import com.android.systemui.qs.footer.domain.interactor.FooterActionsInteractorImpl
import com.android.systemui.qs.footer.ui.viewmodel.FooterActionsViewModel
import com.android.systemui.qs.user.UserSwitchDialogController
import com.android.systemui.security.data.repository.SecurityRepository
import com.android.systemui.security.data.repository.SecurityRepositoryImpl
import com.android.systemui.settings.FakeUserTracker
@@ -54,6 +51,7 @@ import com.android.systemui.statusbar.policy.FakeUserInfoController
import com.android.systemui.statusbar.policy.SecurityController
import com.android.systemui.statusbar.policy.UserInfoController
import com.android.systemui.statusbar.policy.UserSwitcherController
import com.android.systemui.user.domain.interactor.UserInteractor
import com.android.systemui.util.mockito.mock
import com.android.systemui.util.settings.FakeSettings
import com.android.systemui.util.settings.GlobalSettings
@@ -97,13 +95,12 @@ class FooterActionsTestUtils(
/** Create a [FooterActionsInteractor] to be used in tests. */
fun footerActionsInteractor(
activityStarter: ActivityStarter = mock(),
featureFlags: FeatureFlags = FakeFeatureFlags(),
metricsLogger: MetricsLogger = FakeMetricsLogger(),
uiEventLogger: UiEventLogger = UiEventLoggerFake(),
deviceProvisionedController: DeviceProvisionedController = mock(),
qsSecurityFooterUtils: QSSecurityFooterUtils = mock(),
fgsManagerController: FgsManagerController = mock(),
userSwitchDialogController: UserSwitchDialogController = mock(),
userInteractor: UserInteractor = mock(),
securityRepository: SecurityRepository = securityRepository(),
foregroundServicesRepository: ForegroundServicesRepository = foregroundServicesRepository(),
userSwitcherRepository: UserSwitcherRepository = userSwitcherRepository(),
@@ -112,13 +109,12 @@ class FooterActionsTestUtils(
): FooterActionsInteractor {
return FooterActionsInteractorImpl(
activityStarter,
featureFlags,
metricsLogger,
uiEventLogger,
deviceProvisionedController,
qsSecurityFooterUtils,
fgsManagerController,
userSwitchDialogController,
userInteractor,
securityRepository,
foregroundServicesRepository,
userSwitcherRepository,