Merge "Respects device policy to disble quick affordances" into tm-qpr-dev

This commit is contained in:
Ale Nijamkin
2023-02-17 00:30:27 +00:00
committed by Android (Google) Code Review
7 changed files with 186 additions and 58 deletions

View File

@@ -52,6 +52,11 @@ A picker experience may:
* Unselect an already-selected quick affordance from a slot * Unselect an already-selected quick affordance from a slot
* Unselect all already-selected quick affordances from a slot * Unselect all already-selected quick affordances from a slot
## Device Policy
Returning `DevicePolicyManager.KEYGUARD_DISABLE_FEATURES_ALL` or
`DevicePolicyManager.KEYGUARD_DISABLE_SHORTCUTS_ALL` from
`DevicePolicyManager#getKeyguardDisabledFeatures` will disable the keyguard quick affordance feature on the device.
## Testing ## Testing
* Add a unit test for your implementation of `KeyguardQuickAffordanceConfig` * Add a unit test for your implementation of `KeyguardQuickAffordanceConfig`
* Manually verify that your implementation works in multi-user environments from both the main user and a secondary user * Manually verify that your implementation works in multi-user environments from both the main user and a secondary user

View File

@@ -131,7 +131,7 @@ class CustomizationProvider :
throw UnsupportedOperationException() throw UnsupportedOperationException()
} }
return insertSelection(values) return runBlocking { insertSelection(values) }
} }
override fun query( override fun query(
@@ -171,7 +171,7 @@ class CustomizationProvider :
throw UnsupportedOperationException() throw UnsupportedOperationException()
} }
return deleteSelection(uri, selectionArgs) return runBlocking { deleteSelection(uri, selectionArgs) }
} }
override fun call(method: String, arg: String?, extras: Bundle?): Bundle? { override fun call(method: String, arg: String?, extras: Bundle?): Bundle? {
@@ -189,7 +189,7 @@ class CustomizationProvider :
} }
} }
private fun insertSelection(values: ContentValues?): Uri? { private suspend fun insertSelection(values: ContentValues?): Uri? {
if (values == null) { if (values == null) {
throw IllegalArgumentException("Cannot insert selection, no values passed in!") throw IllegalArgumentException("Cannot insert selection, no values passed in!")
} }
@@ -311,7 +311,7 @@ class CustomizationProvider :
} }
} }
private fun querySlots(): Cursor { private suspend fun querySlots(): Cursor {
return MatrixCursor( return MatrixCursor(
arrayOf( arrayOf(
Contract.LockScreenQuickAffordances.SlotTable.Columns.ID, Contract.LockScreenQuickAffordances.SlotTable.Columns.ID,
@@ -330,7 +330,7 @@ class CustomizationProvider :
} }
} }
private fun queryFlags(): Cursor { private suspend fun queryFlags(): Cursor {
return MatrixCursor( return MatrixCursor(
arrayOf( arrayOf(
Contract.FlagsTable.Columns.NAME, Contract.FlagsTable.Columns.NAME,
@@ -353,7 +353,7 @@ class CustomizationProvider :
} }
} }
private fun deleteSelection( private suspend fun deleteSelection(
uri: Uri, uri: Uri,
selectionArgs: Array<out String>?, selectionArgs: Array<out String>?,
): Int { ): Int {

View File

@@ -18,12 +18,14 @@
package com.android.systemui.keyguard.domain.interactor package com.android.systemui.keyguard.domain.interactor
import android.app.AlertDialog import android.app.AlertDialog
import android.app.admin.DevicePolicyManager
import android.content.Intent import android.content.Intent
import android.util.Log import android.util.Log
import com.android.internal.widget.LockPatternUtils import com.android.internal.widget.LockPatternUtils
import com.android.systemui.animation.DialogLaunchAnimator import com.android.systemui.animation.DialogLaunchAnimator
import com.android.systemui.animation.Expandable import com.android.systemui.animation.Expandable
import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.flags.FeatureFlags import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags import com.android.systemui.flags.Flags
import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceConfig import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceConfig
@@ -41,13 +43,17 @@ import com.android.systemui.statusbar.phone.SystemUIDialog
import com.android.systemui.statusbar.policy.KeyguardStateController import com.android.systemui.statusbar.policy.KeyguardStateController
import dagger.Lazy import dagger.Lazy
import javax.inject.Inject import javax.inject.Inject
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onStart import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.withContext
@OptIn(ExperimentalCoroutinesApi::class)
@SysUISingleton @SysUISingleton
class KeyguardQuickAffordanceInteractor class KeyguardQuickAffordanceInteractor
@Inject @Inject
@@ -61,6 +67,8 @@ constructor(
private val featureFlags: FeatureFlags, private val featureFlags: FeatureFlags,
private val repository: Lazy<KeyguardQuickAffordanceRepository>, private val repository: Lazy<KeyguardQuickAffordanceRepository>,
private val launchAnimator: DialogLaunchAnimator, private val launchAnimator: DialogLaunchAnimator,
private val devicePolicyManager: DevicePolicyManager,
@Background private val backgroundDispatcher: CoroutineDispatcher,
) { ) {
private val isUsingRepository: Boolean private val isUsingRepository: Boolean
get() = featureFlags.isEnabled(Flags.CUSTOMIZABLE_LOCK_SCREEN_QUICK_AFFORDANCES) get() = featureFlags.isEnabled(Flags.CUSTOMIZABLE_LOCK_SCREEN_QUICK_AFFORDANCES)
@@ -74,9 +82,13 @@ constructor(
get() = featureFlags.isEnabled(Flags.CUSTOMIZABLE_LOCK_SCREEN_QUICK_AFFORDANCES) get() = featureFlags.isEnabled(Flags.CUSTOMIZABLE_LOCK_SCREEN_QUICK_AFFORDANCES)
/** Returns an observable for the quick affordance at the given position. */ /** Returns an observable for the quick affordance at the given position. */
fun quickAffordance( suspend fun quickAffordance(
position: KeyguardQuickAffordancePosition position: KeyguardQuickAffordancePosition
): Flow<KeyguardQuickAffordanceModel> { ): Flow<KeyguardQuickAffordanceModel> {
if (isFeatureDisabledByDevicePolicy()) {
return flowOf(KeyguardQuickAffordanceModel.Hidden)
}
return combine( return combine(
quickAffordanceAlwaysVisible(position), quickAffordanceAlwaysVisible(position),
keyguardInteractor.isDozing, keyguardInteractor.isDozing,
@@ -148,13 +160,20 @@ constructor(
* *
* @return `true` if the affordance was selected successfully; `false` otherwise. * @return `true` if the affordance was selected successfully; `false` otherwise.
*/ */
fun select(slotId: String, affordanceId: String): Boolean { suspend fun select(slotId: String, affordanceId: String): Boolean {
check(isUsingRepository) check(isUsingRepository)
if (isFeatureDisabledByDevicePolicy()) {
return false
}
val slots = repository.get().getSlotPickerRepresentations() val slots = repository.get().getSlotPickerRepresentations()
val slot = slots.find { it.id == slotId } ?: return false val slot = slots.find { it.id == slotId } ?: return false
val selections = val selections =
repository.get().getCurrentSelections().getOrDefault(slotId, emptyList()).toMutableList() repository
.get()
.getCurrentSelections()
.getOrDefault(slotId, emptyList())
.toMutableList()
val alreadySelected = selections.remove(affordanceId) val alreadySelected = selections.remove(affordanceId)
if (!alreadySelected) { if (!alreadySelected) {
while (selections.size > 0 && selections.size >= slot.maxSelectedAffordances) { while (selections.size > 0 && selections.size >= slot.maxSelectedAffordances) {
@@ -183,8 +202,11 @@ constructor(
* @return `true` if the affordance was successfully removed; `false` otherwise (for example, if * @return `true` if the affordance was successfully removed; `false` otherwise (for example, if
* the affordance was not on the slot to begin with). * the affordance was not on the slot to begin with).
*/ */
fun unselect(slotId: String, affordanceId: String?): Boolean { suspend fun unselect(slotId: String, affordanceId: String?): Boolean {
check(isUsingRepository) check(isUsingRepository)
if (isFeatureDisabledByDevicePolicy()) {
return false
}
val slots = repository.get().getSlotPickerRepresentations() val slots = repository.get().getSlotPickerRepresentations()
if (slots.find { it.id == slotId } == null) { if (slots.find { it.id == slotId } == null) {
@@ -203,7 +225,11 @@ constructor(
} }
val selections = val selections =
repository.get().getCurrentSelections().getOrDefault(slotId, emptyList()).toMutableList() repository
.get()
.getCurrentSelections()
.getOrDefault(slotId, emptyList())
.toMutableList()
return if (selections.remove(affordanceId)) { return if (selections.remove(affordanceId)) {
repository repository
.get() .get()
@@ -219,6 +245,10 @@ constructor(
/** Returns affordance IDs indexed by slot ID, for all known slots. */ /** Returns affordance IDs indexed by slot ID, for all known slots. */
suspend fun getSelections(): Map<String, List<KeyguardQuickAffordancePickerRepresentation>> { suspend fun getSelections(): Map<String, List<KeyguardQuickAffordancePickerRepresentation>> {
if (isFeatureDisabledByDevicePolicy()) {
return emptyMap()
}
val slots = repository.get().getSlotPickerRepresentations() val slots = repository.get().getSlotPickerRepresentations()
val selections = repository.get().getCurrentSelections() val selections = repository.get().getCurrentSelections()
val affordanceById = val affordanceById =
@@ -343,13 +373,17 @@ constructor(
return repository.get().getAffordancePickerRepresentations() return repository.get().getAffordancePickerRepresentations()
} }
fun getSlotPickerRepresentations(): List<KeyguardSlotPickerRepresentation> { suspend fun getSlotPickerRepresentations(): List<KeyguardSlotPickerRepresentation> {
check(isUsingRepository) check(isUsingRepository)
if (isFeatureDisabledByDevicePolicy()) {
return emptyList()
}
return repository.get().getSlotPickerRepresentations() return repository.get().getSlotPickerRepresentations()
} }
fun getPickerFlags(): List<KeyguardPickerFlag> { suspend fun getPickerFlags(): List<KeyguardPickerFlag> {
return listOf( return listOf(
KeyguardPickerFlag( KeyguardPickerFlag(
name = Contract.FlagsTable.FLAG_NAME_REVAMPED_WALLPAPER_UI, name = Contract.FlagsTable.FLAG_NAME_REVAMPED_WALLPAPER_UI,
@@ -357,7 +391,9 @@ constructor(
), ),
KeyguardPickerFlag( KeyguardPickerFlag(
name = Contract.FlagsTable.FLAG_NAME_CUSTOM_LOCK_SCREEN_QUICK_AFFORDANCES_ENABLED, name = Contract.FlagsTable.FLAG_NAME_CUSTOM_LOCK_SCREEN_QUICK_AFFORDANCES_ENABLED,
value = featureFlags.isEnabled(Flags.CUSTOMIZABLE_LOCK_SCREEN_QUICK_AFFORDANCES), value =
!isFeatureDisabledByDevicePolicy() &&
featureFlags.isEnabled(Flags.CUSTOMIZABLE_LOCK_SCREEN_QUICK_AFFORDANCES),
), ),
KeyguardPickerFlag( KeyguardPickerFlag(
name = Contract.FlagsTable.FLAG_NAME_CUSTOM_CLOCKS_ENABLED, name = Contract.FlagsTable.FLAG_NAME_CUSTOM_CLOCKS_ENABLED,
@@ -374,6 +410,16 @@ constructor(
) )
} }
private suspend fun isFeatureDisabledByDevicePolicy(): Boolean {
val flags =
withContext(backgroundDispatcher) {
devicePolicyManager.getKeyguardDisabledFeatures(null, userTracker.userId)
}
val flagsToCheck = DevicePolicyManager.KEYGUARD_DISABLE_FEATURES_ALL
// TODO(b/268218507): "or" with DevicePolicyManager.KEYGUARD_DISABLE_SHORTCUTS_ALL
return flagsToCheck and flags != 0
}
companion object { companion object {
private const val TAG = "KeyguardQuickAffordanceInteractor" private const val TAG = "KeyguardQuickAffordanceInteractor"
private const val DELIMITER = "::" private const val DELIMITER = "::"

View File

@@ -17,6 +17,7 @@
package com.android.systemui.keyguard package com.android.systemui.keyguard
import android.app.admin.DevicePolicyManager
import android.content.ContentValues import android.content.ContentValues
import android.content.pm.PackageManager import android.content.pm.PackageManager
import android.content.pm.ProviderInfo import android.content.pm.ProviderInfo
@@ -90,6 +91,7 @@ class CustomizationProviderTest : SysuiTestCase() {
@Mock private lateinit var previewSurfacePackage: SurfaceControlViewHost.SurfacePackage @Mock private lateinit var previewSurfacePackage: SurfaceControlViewHost.SurfacePackage
@Mock private lateinit var launchAnimator: DialogLaunchAnimator @Mock private lateinit var launchAnimator: DialogLaunchAnimator
@Mock private lateinit var commandQueue: CommandQueue @Mock private lateinit var commandQueue: CommandQueue
@Mock private lateinit var devicePolicyManager: DevicePolicyManager
private lateinit var underTest: CustomizationProvider private lateinit var underTest: CustomizationProvider
private lateinit var testScope: TestScope private lateinit var testScope: TestScope
@@ -183,6 +185,8 @@ class CustomizationProviderTest : SysuiTestCase() {
featureFlags = featureFlags, featureFlags = featureFlags,
repository = { quickAffordanceRepository }, repository = { quickAffordanceRepository },
launchAnimator = launchAnimator, launchAnimator = launchAnimator,
devicePolicyManager = devicePolicyManager,
backgroundDispatcher = testDispatcher,
) )
underTest.previewManager = underTest.previewManager =
KeyguardRemotePreviewManager( KeyguardRemotePreviewManager(

View File

@@ -17,6 +17,7 @@
package com.android.systemui.keyguard.domain.interactor package com.android.systemui.keyguard.domain.interactor
import android.app.admin.DevicePolicyManager
import android.content.Intent import android.content.Intent
import android.os.UserHandle import android.os.UserHandle
import androidx.test.filters.SmallTest import androidx.test.filters.SmallTest
@@ -54,7 +55,10 @@ import com.android.systemui.util.mockito.whenever
import com.android.systemui.util.settings.FakeSettings import com.android.systemui.util.settings.FakeSettings
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.test.runBlockingTest import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.StandardTestDispatcher
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runTest
import org.junit.Before import org.junit.Before
import org.junit.Test import org.junit.Test
import org.junit.runner.RunWith import org.junit.runner.RunWith
@@ -70,6 +74,7 @@ import org.mockito.Mockito.verify
import org.mockito.Mockito.verifyZeroInteractions import org.mockito.Mockito.verifyZeroInteractions
import org.mockito.MockitoAnnotations import org.mockito.MockitoAnnotations
@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest @SmallTest
@RunWith(Parameterized::class) @RunWith(Parameterized::class)
class KeyguardQuickAffordanceInteractorParameterizedTest : SysuiTestCase() { class KeyguardQuickAffordanceInteractorParameterizedTest : SysuiTestCase() {
@@ -219,8 +224,10 @@ class KeyguardQuickAffordanceInteractorParameterizedTest : SysuiTestCase() {
@Mock private lateinit var expandable: Expandable @Mock private lateinit var expandable: Expandable
@Mock private lateinit var launchAnimator: DialogLaunchAnimator @Mock private lateinit var launchAnimator: DialogLaunchAnimator
@Mock private lateinit var commandQueue: CommandQueue @Mock private lateinit var commandQueue: CommandQueue
@Mock private lateinit var devicePolicyManager: DevicePolicyManager
private lateinit var underTest: KeyguardQuickAffordanceInteractor private lateinit var underTest: KeyguardQuickAffordanceInteractor
private lateinit var testScope: TestScope
@JvmField @Parameter(0) var needStrongAuthAfterBoot: Boolean = false @JvmField @Parameter(0) var needStrongAuthAfterBoot: Boolean = false
@JvmField @Parameter(1) var canShowWhileLocked: Boolean = false @JvmField @Parameter(1) var canShowWhileLocked: Boolean = false
@@ -292,6 +299,8 @@ class KeyguardQuickAffordanceInteractorParameterizedTest : SysuiTestCase() {
set(Flags.CUSTOMIZABLE_LOCK_SCREEN_QUICK_AFFORDANCES, false) set(Flags.CUSTOMIZABLE_LOCK_SCREEN_QUICK_AFFORDANCES, false)
set(Flags.FACE_AUTH_REFACTOR, true) set(Flags.FACE_AUTH_REFACTOR, true)
} }
val testDispatcher = StandardTestDispatcher()
testScope = TestScope(testDispatcher)
underTest = underTest =
KeyguardQuickAffordanceInteractor( KeyguardQuickAffordanceInteractor(
keyguardInteractor = keyguardInteractor =
@@ -322,58 +331,61 @@ class KeyguardQuickAffordanceInteractorParameterizedTest : SysuiTestCase() {
featureFlags = featureFlags, featureFlags = featureFlags,
repository = { quickAffordanceRepository }, repository = { quickAffordanceRepository },
launchAnimator = launchAnimator, launchAnimator = launchAnimator,
devicePolicyManager = devicePolicyManager,
backgroundDispatcher = testDispatcher,
) )
} }
@Test @Test
fun onQuickAffordanceTriggered() = runBlockingTest { fun onQuickAffordanceTriggered() =
setUpMocks( testScope.runTest {
needStrongAuthAfterBoot = needStrongAuthAfterBoot, setUpMocks(
keyguardIsUnlocked = keyguardIsUnlocked, needStrongAuthAfterBoot = needStrongAuthAfterBoot,
) keyguardIsUnlocked = keyguardIsUnlocked,
)
homeControls.setState(
lockScreenState =
KeyguardQuickAffordanceConfig.LockScreenState.Visible(
icon = DRAWABLE,
)
)
homeControls.onTriggeredResult =
if (startActivity) {
KeyguardQuickAffordanceConfig.OnTriggeredResult.StartActivity(
intent = INTENT,
canShowWhileLocked = canShowWhileLocked,
)
} else {
KeyguardQuickAffordanceConfig.OnTriggeredResult.Handled
}
underTest.onQuickAffordanceTriggered(
configKey = BuiltInKeyguardQuickAffordanceKeys.HOME_CONTROLS,
expandable = expandable,
)
homeControls.setState(
lockScreenState =
KeyguardQuickAffordanceConfig.LockScreenState.Visible(
icon = DRAWABLE,
)
)
homeControls.onTriggeredResult =
if (startActivity) { if (startActivity) {
KeyguardQuickAffordanceConfig.OnTriggeredResult.StartActivity( if (needsToUnlockFirst) {
intent = INTENT, verify(activityStarter)
canShowWhileLocked = canShowWhileLocked, .postStartActivityDismissingKeyguard(
) any(),
/* delay= */ eq(0),
same(animationController),
)
} else {
verify(activityStarter)
.startActivity(
any(),
/* dismissShade= */ eq(true),
same(animationController),
/* showOverLockscreenWhenLocked= */ eq(true),
)
}
} else { } else {
KeyguardQuickAffordanceConfig.OnTriggeredResult.Handled verifyZeroInteractions(activityStarter)
} }
underTest.onQuickAffordanceTriggered(
configKey = BuiltInKeyguardQuickAffordanceKeys.HOME_CONTROLS,
expandable = expandable,
)
if (startActivity) {
if (needsToUnlockFirst) {
verify(activityStarter)
.postStartActivityDismissingKeyguard(
any(),
/* delay= */ eq(0),
same(animationController),
)
} else {
verify(activityStarter)
.startActivity(
any(),
/* dismissShade= */ eq(true),
same(animationController),
/* showOverLockscreenWhenLocked= */ eq(true),
)
}
} else {
verifyZeroInteractions(activityStarter)
} }
}
private fun setUpMocks( private fun setUpMocks(
needStrongAuthAfterBoot: Boolean = true, needStrongAuthAfterBoot: Boolean = true,

View File

@@ -17,6 +17,7 @@
package com.android.systemui.keyguard.domain.interactor package com.android.systemui.keyguard.domain.interactor
import android.app.admin.DevicePolicyManager
import android.os.UserHandle import android.os.UserHandle
import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest import androidx.test.filters.SmallTest
@@ -78,6 +79,7 @@ class KeyguardQuickAffordanceInteractorTest : SysuiTestCase() {
@Mock private lateinit var activityStarter: ActivityStarter @Mock private lateinit var activityStarter: ActivityStarter
@Mock private lateinit var launchAnimator: DialogLaunchAnimator @Mock private lateinit var launchAnimator: DialogLaunchAnimator
@Mock private lateinit var commandQueue: CommandQueue @Mock private lateinit var commandQueue: CommandQueue
@Mock private lateinit var devicePolicyManager: DevicePolicyManager
private lateinit var underTest: KeyguardQuickAffordanceInteractor private lateinit var underTest: KeyguardQuickAffordanceInteractor
@@ -184,6 +186,8 @@ class KeyguardQuickAffordanceInteractorTest : SysuiTestCase() {
featureFlags = featureFlags, featureFlags = featureFlags,
repository = { quickAffordanceRepository }, repository = { quickAffordanceRepository },
launchAnimator = launchAnimator, launchAnimator = launchAnimator,
devicePolicyManager = devicePolicyManager,
backgroundDispatcher = testDispatcher,
) )
} }
@@ -238,6 +242,25 @@ class KeyguardQuickAffordanceInteractorTest : SysuiTestCase() {
assertThat(visibleModel.activationState).isEqualTo(ActivationState.NotSupported) assertThat(visibleModel.activationState).isEqualTo(ActivationState.NotSupported)
} }
@Test
fun `quickAffordance - bottom end affordance is hidden when disabled by device policy`() =
testScope.runTest {
whenever(devicePolicyManager.getKeyguardDisabledFeatures(null, userTracker.userId))
.thenReturn(DevicePolicyManager.KEYGUARD_DISABLE_FEATURES_ALL)
quickAccessWallet.setState(
KeyguardQuickAffordanceConfig.LockScreenState.Visible(
icon = ICON,
)
)
val collectedValue by
collectLastValue(
underTest.quickAffordance(KeyguardQuickAffordancePosition.BOTTOM_END)
)
assertThat(collectedValue).isInstanceOf(KeyguardQuickAffordanceModel.Hidden::class.java)
}
@Test @Test
fun `quickAffordance - bottom start affordance hidden while dozing`() = fun `quickAffordance - bottom start affordance hidden while dozing`() =
testScope.runTest { testScope.runTest {

View File

@@ -16,6 +16,7 @@
package com.android.systemui.keyguard.ui.viewmodel package com.android.systemui.keyguard.ui.viewmodel
import android.app.admin.DevicePolicyManager
import android.content.Intent import android.content.Intent
import android.os.UserHandle import android.os.UserHandle
import androidx.test.filters.SmallTest import androidx.test.filters.SmallTest
@@ -87,6 +88,7 @@ class KeyguardBottomAreaViewModelTest : SysuiTestCase() {
@Mock private lateinit var activityStarter: ActivityStarter @Mock private lateinit var activityStarter: ActivityStarter
@Mock private lateinit var launchAnimator: DialogLaunchAnimator @Mock private lateinit var launchAnimator: DialogLaunchAnimator
@Mock private lateinit var commandQueue: CommandQueue @Mock private lateinit var commandQueue: CommandQueue
@Mock private lateinit var devicePolicyManager: DevicePolicyManager
private lateinit var underTest: KeyguardBottomAreaViewModel private lateinit var underTest: KeyguardBottomAreaViewModel
@@ -140,6 +142,7 @@ class KeyguardBottomAreaViewModelTest : SysuiTestCase() {
bouncerRepository = FakeKeyguardBouncerRepository(), bouncerRepository = FakeKeyguardBouncerRepository(),
) )
whenever(userTracker.userHandle).thenReturn(mock()) whenever(userTracker.userHandle).thenReturn(mock())
whenever(userTracker.userId).thenReturn(10)
whenever(lockPatternUtils.getStrongAuthForUser(anyInt())) whenever(lockPatternUtils.getStrongAuthForUser(anyInt()))
.thenReturn(LockPatternUtils.StrongAuthTracker.STRONG_AUTH_NOT_REQUIRED) .thenReturn(LockPatternUtils.StrongAuthTracker.STRONG_AUTH_NOT_REQUIRED)
val testDispatcher = StandardTestDispatcher() val testDispatcher = StandardTestDispatcher()
@@ -205,6 +208,8 @@ class KeyguardBottomAreaViewModelTest : SysuiTestCase() {
featureFlags = featureFlags, featureFlags = featureFlags,
repository = { quickAffordanceRepository }, repository = { quickAffordanceRepository },
launchAnimator = launchAnimator, launchAnimator = launchAnimator,
devicePolicyManager = devicePolicyManager,
backgroundDispatcher = testDispatcher,
), ),
bottomAreaInteractor = KeyguardBottomAreaInteractor(repository = repository), bottomAreaInteractor = KeyguardBottomAreaInteractor(repository = repository),
burnInHelperWrapper = burnInHelperWrapper, burnInHelperWrapper = burnInHelperWrapper,
@@ -239,6 +244,39 @@ class KeyguardBottomAreaViewModelTest : SysuiTestCase() {
) )
} }
@Test
fun `startButton - hidden when device policy disables all keyguard features`() =
testScope.runTest {
whenever(devicePolicyManager.getKeyguardDisabledFeatures(null, userTracker.userId))
.thenReturn(DevicePolicyManager.KEYGUARD_DISABLE_FEATURES_ALL)
repository.setKeyguardShowing(true)
val latest by collectLastValue(underTest.startButton)
val testConfig =
TestConfig(
isVisible = true,
isClickable = true,
isActivated = true,
icon = mock(),
canShowWhileLocked = false,
intent = Intent("action"),
)
val configKey =
setUpQuickAffordanceModel(
position = KeyguardQuickAffordancePosition.BOTTOM_START,
testConfig = testConfig,
)
assertQuickAffordanceViewModel(
viewModel = latest,
testConfig =
TestConfig(
isVisible = false,
),
configKey = configKey,
)
}
@Test @Test
fun `startButton - in preview mode - visible even when keyguard not showing`() = fun `startButton - in preview mode - visible even when keyguard not showing`() =
testScope.runTest { testScope.runTest {