Quick affordance repository.

This CL introduces KeyguardQuickAffordanceRepository which combines
the known built-in configs and the current selections from KeyguardQuickAffordanceSelectionManager to produce the current set of
available affordances and the current selected affordances for each
slot.

KeyguardQuickAffordanceSelectionManager is just an in-memory cache at
the moment as we will flesh it out in upcoming CLs such that it actually
uses a persistence layer.

Note that the repository is meant for use for both displaying the
affordances on the lock screen and for serving content provider queries
coming from the wallpaper picker, which is why it's got both a flow and
a "get" function as opposed to a single StateFlow.

Bug: 254858696,254853190
Test: unit tests included. Tested with followup CL to make sure that
quick affordances are still showing up on the lock screen.

Change-Id: I6947e1f729c2aa6470ba21582d664ca5b3e3af70
This commit is contained in:
Alejandro Nijamkin
2022-10-26 18:01:32 -07:00
parent eaf2dc0792
commit 36b511f1b6
19 changed files with 640 additions and 44 deletions

View File

@@ -0,0 +1,27 @@
/*
* Copyright (C) 2022 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.shared.keyguard.shared.model
/**
* Collection of all supported "slots", placements where keyguard quick affordances can appear on
* the lock screen.
*/
object KeyguardQuickAffordanceSlots {
const val SLOT_ID_BOTTOM_START = "bottom_start"
const val SLOT_ID_BOTTOM_END = "bottom_end"
}

View File

@@ -42,6 +42,7 @@ import com.android.systemui.dump.DumpManager;
import com.android.systemui.keyguard.DismissCallbackRegistry;
import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
import com.android.systemui.keyguard.KeyguardViewMediator;
import com.android.systemui.keyguard.data.quickaffordance.KeyguardDataQuickAffordanceModule;
import com.android.systemui.keyguard.data.repository.KeyguardRepositoryModule;
import com.android.systemui.keyguard.domain.interactor.StartKeyguardTransitionModule;
import com.android.systemui.keyguard.domain.quickaffordance.KeyguardQuickAffordanceModule;
@@ -71,6 +72,7 @@ import dagger.Provides;
KeyguardUserSwitcherComponent.class},
includes = {
FalsingModule.class,
KeyguardDataQuickAffordanceModule.class,
KeyguardQuickAffordanceModule.class,
KeyguardRepositoryModule.class,
StartKeyguardTransitionModule.class,

View File

@@ -53,6 +53,10 @@ constructor(
override val key: String = BuiltInKeyguardQuickAffordanceKeys.HOME_CONTROLS
override val pickerName: String by lazy { context.getString(component.getTileTitleId()) }
override val pickerIconResourceId: Int by lazy { component.getTileImageId() }
override val lockScreenState: Flow<KeyguardQuickAffordanceConfig.LockScreenState> =
component.canShowWhileLockedSetting.flatMapLatest { canShowWhileLocked ->
if (canShowWhileLocked) {

View File

@@ -0,0 +1,39 @@
/*
* Copyright (C) 2022 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.keyguard.data.quickaffordance
import dagger.Module
import dagger.Provides
import dagger.multibindings.ElementsIntoSet
@Module
object KeyguardDataQuickAffordanceModule {
@Provides
@ElementsIntoSet
fun quickAffordanceConfigs(
home: HomeControlsKeyguardQuickAffordanceConfig,
quickAccessWallet: QuickAccessWalletKeyguardQuickAffordanceConfig,
qrCodeScanner: QrCodeScannerKeyguardQuickAffordanceConfig,
): Set<KeyguardQuickAffordanceConfig> {
return setOf(
home,
quickAccessWallet,
qrCodeScanner,
)
}
}

View File

@@ -29,6 +29,10 @@ interface KeyguardQuickAffordanceConfig {
/** Unique identifier for this quick affordance. It must be globally unique. */
val key: String
val pickerName: String
val pickerIconResourceId: Int
/**
* The ever-changing state of the affordance.
*

View File

@@ -0,0 +1,62 @@
/*
* Copyright (C) 2022 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.keyguard.data.quickaffordance
import com.android.systemui.dagger.SysUISingleton
import javax.inject.Inject
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
/**
* Manages and provides access to the current "selections" of keyguard quick affordances, answering
* the question "which affordances should the keyguard show?".
*/
@SysUISingleton
class KeyguardQuickAffordanceSelectionManager @Inject constructor() {
// TODO(b/254858695): implement a persistence layer (database).
private val _selections = MutableStateFlow<Map<String, List<String>>>(emptyMap())
/** IDs of affordances to show, indexed by slot ID, and sorted in descending priority order. */
val selections: Flow<Map<String, List<String>>> = _selections.asStateFlow()
/**
* Returns a snapshot of the IDs of affordances to show, indexed by slot ID, and sorted in
* descending priority order.
*/
suspend fun getSelections(): Map<String, List<String>> {
return _selections.value
}
/**
* Updates the IDs of affordances to show at the slot with the given ID. The order of affordance
* IDs should be descending priority order.
*/
suspend fun setSelections(
slotId: String,
affordanceIds: List<String>,
) {
// Must make a copy of the map and update it, otherwise, the MutableStateFlow won't emit
// when we set its value to the same instance of the original map, even if we change the
// map by updating the value of one of its keys.
val copy = _selections.value.toMutableMap()
copy[slotId] = affordanceIds
_selections.value = copy
}
}

View File

@@ -17,6 +17,7 @@
package com.android.systemui.keyguard.data.quickaffordance
import android.content.Context
import com.android.systemui.R
import com.android.systemui.animation.Expandable
import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging
@@ -24,6 +25,7 @@ import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCall
import com.android.systemui.common.shared.model.ContentDescription
import com.android.systemui.common.shared.model.Icon
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.qrcodescanner.controller.QRCodeScannerController
import javax.inject.Inject
import kotlinx.coroutines.channels.awaitClose
@@ -34,11 +36,16 @@ import kotlinx.coroutines.flow.Flow
class QrCodeScannerKeyguardQuickAffordanceConfig
@Inject
constructor(
@Application context: Context,
private val controller: QRCodeScannerController,
) : KeyguardQuickAffordanceConfig {
override val key: String = BuiltInKeyguardQuickAffordanceKeys.QR_CODE_SCANNER
override val pickerName = context.getString(R.string.qr_code_scanner_title)
override val pickerIconResourceId = R.drawable.ic_qr_code_scanner
override val lockScreenState: Flow<KeyguardQuickAffordanceConfig.LockScreenState> =
conflatedCallbackFlow {
val callback =

View File

@@ -17,6 +17,7 @@
package com.android.systemui.keyguard.data.quickaffordance
import android.content.Context
import android.graphics.drawable.Drawable
import android.service.quickaccesswallet.GetWalletCardsError
import android.service.quickaccesswallet.GetWalletCardsResponse
@@ -29,6 +30,7 @@ import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCall
import com.android.systemui.common.shared.model.ContentDescription
import com.android.systemui.common.shared.model.Icon
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.wallet.controller.QuickAccessWalletController
import javax.inject.Inject
@@ -40,12 +42,17 @@ import kotlinx.coroutines.flow.Flow
class QuickAccessWalletKeyguardQuickAffordanceConfig
@Inject
constructor(
@Application context: Context,
private val walletController: QuickAccessWalletController,
private val activityStarter: ActivityStarter,
) : KeyguardQuickAffordanceConfig {
override val key: String = BuiltInKeyguardQuickAffordanceKeys.QUICK_ACCESS_WALLET
override val pickerName = context.getString(R.string.accessibility_wallet_button)
override val pickerIconResourceId = R.drawable.ic_wallet_lockscreen
override val lockScreenState: Flow<KeyguardQuickAffordanceConfig.LockScreenState> =
conflatedCallbackFlow {
val callback =

View File

@@ -0,0 +1,128 @@
/*
* Copyright (C) 2022 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.keyguard.data.repository
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceConfig
import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceSelectionManager
import com.android.systemui.keyguard.shared.model.KeyguardQuickAffordancePickerRepresentation
import com.android.systemui.keyguard.shared.model.KeyguardSlotPickerRepresentation
import com.android.systemui.shared.keyguard.shared.model.KeyguardQuickAffordanceSlots
import javax.inject.Inject
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch
/** Abstracts access to application state related to keyguard quick affordances. */
@SysUISingleton
class KeyguardQuickAffordanceRepository
@Inject
constructor(
@Application private val scope: CoroutineScope,
@Background private val backgroundDispatcher: CoroutineDispatcher,
private val selectionManager: KeyguardQuickAffordanceSelectionManager,
private val configs: Set<@JvmSuppressWildcards KeyguardQuickAffordanceConfig>,
) {
/**
* List of [KeyguardQuickAffordanceConfig] instances of the affordances at the slot with the
* given ID. The configs are sorted in descending priority order.
*/
val selections: StateFlow<Map<String, List<KeyguardQuickAffordanceConfig>>> =
selectionManager.selections
.map { selectionsBySlotId ->
selectionsBySlotId.mapValues { (_, selections) ->
configs.filter { selections.contains(it.key) }
}
}
.stateIn(
scope = scope,
started = SharingStarted.Eagerly,
initialValue = emptyMap(),
)
/**
* Returns a snapshot of the [KeyguardQuickAffordanceConfig] instances of the affordances at the
* slot with the given ID. The configs are sorted in descending priority order.
*/
suspend fun getSelections(slotId: String): List<KeyguardQuickAffordanceConfig> {
val selections = selectionManager.getSelections().getOrDefault(slotId, emptyList())
return configs.filter { selections.contains(it.key) }
}
/**
* Returns a snapshot of the IDs of the selected affordances, indexed by slot ID. The configs
* are sorted in descending priority order.
*/
suspend fun getSelections(): Map<String, List<String>> {
return selectionManager.getSelections()
}
/**
* Updates the IDs of affordances to show at the slot with the given ID. The order of affordance
* IDs should be descending priority order.
*/
fun setSelections(
slotId: String,
affordanceIds: List<String>,
) {
scope.launch(backgroundDispatcher) {
selectionManager.setSelections(
slotId = slotId,
affordanceIds = affordanceIds,
)
}
}
/**
* Returns the list of representation objects for all known affordances, regardless of what is
* selected. This is useful for building experiences like the picker/selector or user settings
* so the user can see everything that can be selected in a menu.
*/
fun getAffordancePickerRepresentations(): List<KeyguardQuickAffordancePickerRepresentation> {
return configs.map { config ->
KeyguardQuickAffordancePickerRepresentation(
id = config.key,
name = config.pickerName,
iconResourceId = config.pickerIconResourceId,
)
}
}
/**
* Returns the list of representation objects for all available slots on the keyguard. This is
* useful for building experiences like the picker/selector or user settings so the user can see
* each slot and select which affordance(s) is/are installed in each slot on the keyguard.
*/
fun getSlotPickerRepresentations(): List<KeyguardSlotPickerRepresentation> {
// TODO(b/256195304): source these from a config XML file.
return listOf(
KeyguardSlotPickerRepresentation(
id = KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START,
),
KeyguardSlotPickerRepresentation(
id = KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_END,
),
)
}
}

View File

@@ -0,0 +1,30 @@
/*
* Copyright (C) 2022 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.keyguard.shared.model
import androidx.annotation.DrawableRes
/**
* Representation of a quick affordance for use to build "picker", "selector", or "settings"
* experiences.
*/
data class KeyguardQuickAffordancePickerRepresentation(
val id: String,
val name: String,
@DrawableRes val iconResourceId: Int,
)

View File

@@ -0,0 +1,28 @@
/*
* Copyright (C) 2022 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.keyguard.shared.model
/**
* Representation of a quick affordance slot (or position) for use to build "picker", "selector", or
* "settings" experiences.
*/
data class KeyguardSlotPickerRepresentation(
val id: String,
/** The maximum number of selected affordances that can be present on this slot. */
val maxSelectedAffordances: Int = 1,
)

View File

@@ -23,14 +23,11 @@ import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.yield
/**
* Fake implementation of a quick affordance data source.
*
* This class is abstract to force tests to provide extensions of it as the system that references
* these configs uses each implementation's class type to refer to them.
*/
abstract class FakeKeyguardQuickAffordanceConfig(
/** Fake implementation of a quick affordance data source. */
class FakeKeyguardQuickAffordanceConfig(
override val key: String,
override val pickerName: String = key,
override val pickerIconResourceId: Int = 0,
) : KeyguardQuickAffordanceConfig {
var onTriggeredResult: OnTriggeredResult = OnTriggeredResult.Handled

View File

@@ -0,0 +1,127 @@
/*
* Copyright (C) 2022 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.keyguard.data.quickaffordance
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.runBlocking
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
@SmallTest
@RunWith(JUnit4::class)
class KeyguardQuickAffordanceSelectionManagerTest : SysuiTestCase() {
private lateinit var underTest: KeyguardQuickAffordanceSelectionManager
@Before
fun setUp() {
underTest = KeyguardQuickAffordanceSelectionManager()
}
@Test
fun setSelections() =
runBlocking(IMMEDIATE) {
var affordanceIdsBySlotId: Map<String, List<String>>? = null
val job = underTest.selections.onEach { affordanceIdsBySlotId = it }.launchIn(this)
val slotId1 = "slot1"
val slotId2 = "slot2"
val affordanceId1 = "affordance1"
val affordanceId2 = "affordance2"
val affordanceId3 = "affordance3"
underTest.setSelections(
slotId = slotId1,
affordanceIds = listOf(affordanceId1),
)
assertSelections(
affordanceIdsBySlotId,
mapOf(
slotId1 to listOf(affordanceId1),
),
)
underTest.setSelections(
slotId = slotId2,
affordanceIds = listOf(affordanceId2),
)
assertSelections(
affordanceIdsBySlotId,
mapOf(
slotId1 to listOf(affordanceId1),
slotId2 to listOf(affordanceId2),
)
)
underTest.setSelections(
slotId = slotId1,
affordanceIds = listOf(affordanceId1, affordanceId3),
)
assertSelections(
affordanceIdsBySlotId,
mapOf(
slotId1 to listOf(affordanceId1, affordanceId3),
slotId2 to listOf(affordanceId2),
)
)
underTest.setSelections(
slotId = slotId1,
affordanceIds = listOf(affordanceId3),
)
assertSelections(
affordanceIdsBySlotId,
mapOf(
slotId1 to listOf(affordanceId3),
slotId2 to listOf(affordanceId2),
)
)
underTest.setSelections(
slotId = slotId2,
affordanceIds = listOf(),
)
assertSelections(
affordanceIdsBySlotId,
mapOf(
slotId1 to listOf(affordanceId3),
slotId2 to listOf(),
)
)
job.cancel()
}
private suspend fun assertSelections(
observed: Map<String, List<String>>?,
expected: Map<String, List<String>>,
) {
assertThat(underTest.getSelections()).isEqualTo(expected)
assertThat(observed).isEqualTo(expected)
}
companion object {
private val IMMEDIATE = Dispatchers.Main.immediate
}
}

View File

@@ -50,7 +50,7 @@ class QrCodeScannerKeyguardQuickAffordanceConfigTest : SysuiTestCase() {
MockitoAnnotations.initMocks(this)
whenever(controller.intent).thenReturn(INTENT_1)
underTest = QrCodeScannerKeyguardQuickAffordanceConfig(controller)
underTest = QrCodeScannerKeyguardQuickAffordanceConfig(mock(), controller)
}
@Test

View File

@@ -59,6 +59,7 @@ class QuickAccessWalletKeyguardQuickAffordanceConfigTest : SysuiTestCase() {
underTest =
QuickAccessWalletKeyguardQuickAffordanceConfig(
mock(),
walletController,
activityStarter,
)

View File

@@ -0,0 +1,152 @@
/*
* Copyright (C) 2022 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.keyguard.data.repository
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.keyguard.data.quickaffordance.FakeKeyguardQuickAffordanceConfig
import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceConfig
import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceSelectionManager
import com.android.systemui.keyguard.shared.model.KeyguardQuickAffordancePickerRepresentation
import com.android.systemui.keyguard.shared.model.KeyguardSlotPickerRepresentation
import com.android.systemui.shared.keyguard.shared.model.KeyguardQuickAffordanceSlots
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.runBlocking
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
@RunWith(JUnit4::class)
class KeyguardQuickAffordanceRepositoryTest : SysuiTestCase() {
private lateinit var underTest: KeyguardQuickAffordanceRepository
private lateinit var config1: FakeKeyguardQuickAffordanceConfig
private lateinit var config2: FakeKeyguardQuickAffordanceConfig
@Before
fun setUp() {
config1 = FakeKeyguardQuickAffordanceConfig("built_in:1")
config2 = FakeKeyguardQuickAffordanceConfig("built_in:2")
underTest =
KeyguardQuickAffordanceRepository(
scope = CoroutineScope(IMMEDIATE),
backgroundDispatcher = IMMEDIATE,
selectionManager = KeyguardQuickAffordanceSelectionManager(),
configs = setOf(config1, config2),
)
}
@Test
fun setSelections() =
runBlocking(IMMEDIATE) {
var configsBySlotId: Map<String, List<KeyguardQuickAffordanceConfig>>? = null
val job = underTest.selections.onEach { configsBySlotId = it }.launchIn(this)
val slotId1 = "slot1"
val slotId2 = "slot2"
underTest.setSelections(slotId1, listOf(config1.key))
assertSelections(
configsBySlotId,
mapOf(
slotId1 to listOf(config1),
),
)
underTest.setSelections(slotId2, listOf(config2.key))
assertSelections(
configsBySlotId,
mapOf(
slotId1 to listOf(config1),
slotId2 to listOf(config2),
),
)
underTest.setSelections(slotId1, emptyList())
underTest.setSelections(slotId2, listOf(config1.key))
assertSelections(
configsBySlotId,
mapOf(
slotId1 to emptyList(),
slotId2 to listOf(config1),
),
)
job.cancel()
}
@Test
fun getAffordancePickerRepresentations() {
assertThat(underTest.getAffordancePickerRepresentations())
.isEqualTo(
listOf(
KeyguardQuickAffordancePickerRepresentation(
id = config1.key,
name = config1.pickerName,
iconResourceId = config1.pickerIconResourceId,
),
KeyguardQuickAffordancePickerRepresentation(
id = config2.key,
name = config2.pickerName,
iconResourceId = config2.pickerIconResourceId,
),
)
)
}
@Test
fun getSlotPickerRepresentations() {
assertThat(underTest.getSlotPickerRepresentations())
.isEqualTo(
listOf(
KeyguardSlotPickerRepresentation(
id = KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START,
maxSelectedAffordances = 1,
),
KeyguardSlotPickerRepresentation(
id = KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_END,
maxSelectedAffordances = 1,
),
)
)
}
private suspend fun assertSelections(
observed: Map<String, List<KeyguardQuickAffordanceConfig>>?,
expected: Map<String, List<KeyguardQuickAffordanceConfig>>,
) {
assertThat(observed).isEqualTo(expected)
assertThat(underTest.getSelections())
.isEqualTo(expected.mapValues { (_, configs) -> configs.map { it.key } })
expected.forEach { (slotId, configs) ->
assertThat(underTest.getSelections(slotId)).isEqualTo(configs)
}
}
companion object {
private val IMMEDIATE = Dispatchers.Main.immediate
}
}

View File

@@ -213,10 +213,7 @@ class KeyguardQuickAffordanceInteractorParameterizedTest : SysuiTestCase() {
whenever(expandable.activityLaunchController()).thenReturn(animationController)
homeControls =
object :
FakeKeyguardQuickAffordanceConfig(
BuiltInKeyguardQuickAffordanceKeys.HOME_CONTROLS
) {}
FakeKeyguardQuickAffordanceConfig(BuiltInKeyguardQuickAffordanceKeys.HOME_CONTROLS)
underTest =
KeyguardQuickAffordanceInteractor(
keyguardInteractor = KeyguardInteractor(repository = FakeKeyguardRepository()),
@@ -229,14 +226,12 @@ class KeyguardQuickAffordanceInteractorParameterizedTest : SysuiTestCase() {
),
KeyguardQuickAffordancePosition.BOTTOM_END to
listOf(
object :
FakeKeyguardQuickAffordanceConfig(
BuiltInKeyguardQuickAffordanceKeys.QUICK_ACCESS_WALLET
) {},
object :
FakeKeyguardQuickAffordanceConfig(
BuiltInKeyguardQuickAffordanceKeys.QR_CODE_SCANNER
) {},
FakeKeyguardQuickAffordanceConfig(
BuiltInKeyguardQuickAffordanceKeys.QUICK_ACCESS_WALLET
),
FakeKeyguardQuickAffordanceConfig(
BuiltInKeyguardQuickAffordanceKeys.QR_CODE_SCANNER
),
),
),
),

View File

@@ -71,20 +71,13 @@ class KeyguardQuickAffordanceInteractorTest : SysuiTestCase() {
repository.setKeyguardShowing(true)
homeControls =
object :
FakeKeyguardQuickAffordanceConfig(
BuiltInKeyguardQuickAffordanceKeys.HOME_CONTROLS
) {}
FakeKeyguardQuickAffordanceConfig(BuiltInKeyguardQuickAffordanceKeys.HOME_CONTROLS)
quickAccessWallet =
object :
FakeKeyguardQuickAffordanceConfig(
BuiltInKeyguardQuickAffordanceKeys.QUICK_ACCESS_WALLET
) {}
FakeKeyguardQuickAffordanceConfig(
BuiltInKeyguardQuickAffordanceKeys.QUICK_ACCESS_WALLET
)
qrCodeScanner =
object :
FakeKeyguardQuickAffordanceConfig(
BuiltInKeyguardQuickAffordanceKeys.QR_CODE_SCANNER
) {}
FakeKeyguardQuickAffordanceConfig(BuiltInKeyguardQuickAffordanceKeys.QR_CODE_SCANNER)
underTest =
KeyguardQuickAffordanceInteractor(

View File

@@ -82,20 +82,13 @@ class KeyguardBottomAreaViewModelTest : SysuiTestCase() {
.thenReturn(RETURNED_BURN_IN_OFFSET)
homeControlsQuickAffordanceConfig =
object :
FakeKeyguardQuickAffordanceConfig(
BuiltInKeyguardQuickAffordanceKeys.HOME_CONTROLS
) {}
FakeKeyguardQuickAffordanceConfig(BuiltInKeyguardQuickAffordanceKeys.HOME_CONTROLS)
quickAccessWalletAffordanceConfig =
object :
FakeKeyguardQuickAffordanceConfig(
BuiltInKeyguardQuickAffordanceKeys.QUICK_ACCESS_WALLET
) {}
FakeKeyguardQuickAffordanceConfig(
BuiltInKeyguardQuickAffordanceKeys.QUICK_ACCESS_WALLET
)
qrCodeScannerAffordanceConfig =
object :
FakeKeyguardQuickAffordanceConfig(
BuiltInKeyguardQuickAffordanceKeys.QR_CODE_SCANNER
) {}
FakeKeyguardQuickAffordanceConfig(BuiltInKeyguardQuickAffordanceKeys.QR_CODE_SCANNER)
registry =
FakeKeyguardQuickAffordanceRegistry(
mapOf(