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:
@@ -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"
|
||||
}
|
||||
@@ -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,
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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,
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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 =
|
||||
|
||||
@@ -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 =
|
||||
|
||||
@@ -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,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -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,
|
||||
)
|
||||
@@ -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,
|
||||
)
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -50,7 +50,7 @@ class QrCodeScannerKeyguardQuickAffordanceConfigTest : SysuiTestCase() {
|
||||
MockitoAnnotations.initMocks(this)
|
||||
whenever(controller.intent).thenReturn(INTENT_1)
|
||||
|
||||
underTest = QrCodeScannerKeyguardQuickAffordanceConfig(controller)
|
||||
underTest = QrCodeScannerKeyguardQuickAffordanceConfig(mock(), controller)
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -59,6 +59,7 @@ class QuickAccessWalletKeyguardQuickAffordanceConfigTest : SysuiTestCase() {
|
||||
|
||||
underTest =
|
||||
QuickAccessWalletKeyguardQuickAffordanceConfig(
|
||||
mock(),
|
||||
walletController,
|
||||
activityStarter,
|
||||
)
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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(
|
||||
|
||||
Reference in New Issue
Block a user