blob: 3ec893af21bdd602d2590b6162b18d0f519766b1 [file] [log] [blame]
Alejandro Nijamkin0f02b082022-11-24 13:43:43 -08001/*
2 * Copyright (C) 2022 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *
16 */
17
Alejandro Nijamkinabda67b2022-11-30 14:34:56 -080018package com.android.customization.model.picker.quickaffordance.ui.viewmodel
Alejandro Nijamkin0f02b082022-11-24 13:43:43 -080019
Alejandro Nijamkinabda67b2022-11-30 14:34:56 -080020import android.content.Context
Alejandro Nijamkin0f02b082022-11-24 13:43:43 -080021import androidx.test.filters.SmallTest
22import androidx.test.platform.app.InstrumentationRegistry
Alejandro Nijamkinabda67b2022-11-30 14:34:56 -080023import com.android.customization.picker.quickaffordance.data.repository.KeyguardQuickAffordancePickerRepository
24import com.android.customization.picker.quickaffordance.domain.interactor.KeyguardQuickAffordancePickerInteractor
Alejandro Nijamkinc27b1d32022-12-21 15:27:35 -080025import com.android.customization.picker.quickaffordance.domain.interactor.KeyguardQuickAffordanceSnapshotRestorer
Alejandro Nijamkinabda67b2022-11-30 14:34:56 -080026import com.android.customization.picker.quickaffordance.ui.viewmodel.KeyguardQuickAffordancePickerViewModel
27import com.android.customization.picker.quickaffordance.ui.viewmodel.KeyguardQuickAffordanceSlotViewModel
28import com.android.customization.picker.quickaffordance.ui.viewmodel.KeyguardQuickAffordanceSummaryViewModel
29import com.android.customization.picker.quickaffordance.ui.viewmodel.KeyguardQuickAffordanceViewModel
Alejandro Nijamkin0f02b082022-11-24 13:43:43 -080030import com.android.systemui.shared.keyguard.shared.model.KeyguardQuickAffordanceSlots
31import com.android.systemui.shared.quickaffordance.data.content.FakeKeyguardQuickAffordanceProviderClient
Alejandro Nijamkinabda67b2022-11-30 14:34:56 -080032import com.android.systemui.shared.quickaffordance.data.content.KeyguardQuickAffordanceProviderClient
Alejandro Nijamkinc27b1d32022-12-21 15:27:35 -080033import com.android.wallpaper.picker.undo.data.repository.UndoRepository
34import com.android.wallpaper.picker.undo.domain.interactor.UndoInteractor
35import com.android.wallpaper.testing.FAKE_RESTORERS
36import com.android.wallpaper.testing.collectLastValue
Alejandro Nijamkin0f02b082022-11-24 13:43:43 -080037import com.google.common.truth.Truth.assertThat
38import com.google.common.truth.Truth.assertWithMessage
39import kotlinx.coroutines.Dispatchers
40import kotlinx.coroutines.ExperimentalCoroutinesApi
Alejandro Nijamkinc27b1d32022-12-21 15:27:35 -080041import kotlinx.coroutines.runBlocking
42import kotlinx.coroutines.test.StandardTestDispatcher
Alejandro Nijamkin0f02b082022-11-24 13:43:43 -080043import kotlinx.coroutines.test.TestScope
Alejandro Nijamkin0f02b082022-11-24 13:43:43 -080044import kotlinx.coroutines.test.resetMain
45import kotlinx.coroutines.test.runTest
46import kotlinx.coroutines.test.setMain
47import org.junit.After
48import org.junit.Before
49import org.junit.Test
50import org.junit.runner.RunWith
51import org.junit.runners.JUnit4
52
53@OptIn(ExperimentalCoroutinesApi::class)
54@SmallTest
55@RunWith(JUnit4::class)
56class KeyguardQuickAffordancePickerViewModelTest {
57
58 private lateinit var underTest: KeyguardQuickAffordancePickerViewModel
59
Alejandro Nijamkinabda67b2022-11-30 14:34:56 -080060 private lateinit var context: Context
Alejandro Nijamkin0f02b082022-11-24 13:43:43 -080061 private lateinit var testScope: TestScope
62 private lateinit var client: FakeKeyguardQuickAffordanceProviderClient
Alejandro Nijamkinc27b1d32022-12-21 15:27:35 -080063 private lateinit var quickAffordanceInteractor: KeyguardQuickAffordancePickerInteractor
Alejandro Nijamkin0f02b082022-11-24 13:43:43 -080064
65 @Before
66 fun setUp() {
Alejandro Nijamkinabda67b2022-11-30 14:34:56 -080067 context = InstrumentationRegistry.getInstrumentation().targetContext
Alejandro Nijamkinc27b1d32022-12-21 15:27:35 -080068 val testDispatcher = StandardTestDispatcher()
69 testScope = TestScope(testDispatcher)
70 Dispatchers.setMain(testDispatcher)
Alejandro Nijamkin0f02b082022-11-24 13:43:43 -080071 client = FakeKeyguardQuickAffordanceProviderClient()
72
Alejandro Nijamkinc27b1d32022-12-21 15:27:35 -080073 quickAffordanceInteractor =
74 KeyguardQuickAffordancePickerInteractor(
75 repository =
76 KeyguardQuickAffordancePickerRepository(
77 client = client,
78 backgroundDispatcher = testDispatcher,
79 ),
80 client = client,
81 snapshotRestorer = {
82 KeyguardQuickAffordanceSnapshotRestorer(
83 interactor = quickAffordanceInteractor,
84 client = client,
85 )
86 .apply { runBlocking { setUpSnapshotRestorer {} } }
87 },
88 )
89 val undoInteractor =
90 UndoInteractor(
91 scope = testScope.backgroundScope,
92 repository = UndoRepository(),
93 restorerByOwnerId = FAKE_RESTORERS,
94 )
Alejandro Nijamkin0f02b082022-11-24 13:43:43 -080095 underTest =
96 KeyguardQuickAffordancePickerViewModel.Factory(
Alejandro Nijamkinabda67b2022-11-30 14:34:56 -080097 context = context,
Alejandro Nijamkinc27b1d32022-12-21 15:27:35 -080098 quickAffordanceInteractor = quickAffordanceInteractor,
99 undoInteractor = undoInteractor,
Alejandro Nijamkin0f02b082022-11-24 13:43:43 -0800100 )
101 .create(KeyguardQuickAffordancePickerViewModel::class.java)
102 }
103
104 @After
105 fun tearDown() {
106 Dispatchers.resetMain()
107 }
108
109 @Test
110 fun `Select an affordance for each side`() =
111 testScope.runTest {
Alejandro Nijamkinc27b1d32022-12-21 15:27:35 -0800112 val slots = collectLastValue(underTest.slots)
113 val quickAffordances = collectLastValue(underTest.quickAffordances)
Alejandro Nijamkin0f02b082022-11-24 13:43:43 -0800114
115 // Initially, the first slot is selected with the "none" affordance selected.
116 assertPickerUiState(
Alejandro Nijamkinc27b1d32022-12-21 15:27:35 -0800117 slots = slots(),
118 affordances = quickAffordances(),
Alejandro Nijamkin0f02b082022-11-24 13:43:43 -0800119 selectedSlotText = "Left button",
120 selectedAffordanceText = "None",
121 )
122 assertPreviewUiState(
Alejandro Nijamkinc27b1d32022-12-21 15:27:35 -0800123 slots = slots(),
Alejandro Nijamkin0f02b082022-11-24 13:43:43 -0800124 expectedAffordanceNameBySlotId =
125 mapOf(
126 KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START to null,
127 KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_END to null,
128 ),
129 )
130
131 // Select "affordance 1" for the first slot.
Alejandro Nijamkinc27b1d32022-12-21 15:27:35 -0800132 quickAffordances()?.get(1)?.onClicked?.invoke()
Alejandro Nijamkin0f02b082022-11-24 13:43:43 -0800133 assertPickerUiState(
Alejandro Nijamkinc27b1d32022-12-21 15:27:35 -0800134 slots = slots(),
135 affordances = quickAffordances(),
Alejandro Nijamkin0f02b082022-11-24 13:43:43 -0800136 selectedSlotText = "Left button",
137 selectedAffordanceText = FakeKeyguardQuickAffordanceProviderClient.AFFORDANCE_1,
138 )
139 assertPreviewUiState(
Alejandro Nijamkinc27b1d32022-12-21 15:27:35 -0800140 slots = slots(),
Alejandro Nijamkin0f02b082022-11-24 13:43:43 -0800141 expectedAffordanceNameBySlotId =
142 mapOf(
143 KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START to
144 FakeKeyguardQuickAffordanceProviderClient.AFFORDANCE_1,
145 KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_END to null,
146 ),
147 )
148
149 // Select an affordance for the second slot.
150 // First, switch to the second slot:
Alejandro Nijamkinc27b1d32022-12-21 15:27:35 -0800151 slots()?.get(KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_END)?.onClicked?.invoke()
Alejandro Nijamkin0f02b082022-11-24 13:43:43 -0800152 // Second, select the "affordance 3" affordance:
Alejandro Nijamkinc27b1d32022-12-21 15:27:35 -0800153 quickAffordances()?.get(3)?.onClicked?.invoke()
Alejandro Nijamkin0f02b082022-11-24 13:43:43 -0800154 assertPickerUiState(
Alejandro Nijamkinc27b1d32022-12-21 15:27:35 -0800155 slots = slots(),
156 affordances = quickAffordances(),
Alejandro Nijamkin0f02b082022-11-24 13:43:43 -0800157 selectedSlotText = "Right button",
158 selectedAffordanceText = FakeKeyguardQuickAffordanceProviderClient.AFFORDANCE_3,
159 )
160 assertPreviewUiState(
Alejandro Nijamkinc27b1d32022-12-21 15:27:35 -0800161 slots = slots(),
Alejandro Nijamkin0f02b082022-11-24 13:43:43 -0800162 expectedAffordanceNameBySlotId =
163 mapOf(
164 KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START to
165 FakeKeyguardQuickAffordanceProviderClient.AFFORDANCE_1,
166 KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_END to
167 FakeKeyguardQuickAffordanceProviderClient.AFFORDANCE_3,
168 ),
169 )
170
171 // Select a different affordance for the second slot.
Alejandro Nijamkinc27b1d32022-12-21 15:27:35 -0800172 quickAffordances()?.get(2)?.onClicked?.invoke()
Alejandro Nijamkin0f02b082022-11-24 13:43:43 -0800173 assertPickerUiState(
Alejandro Nijamkinc27b1d32022-12-21 15:27:35 -0800174 slots = slots(),
175 affordances = quickAffordances(),
Alejandro Nijamkin0f02b082022-11-24 13:43:43 -0800176 selectedSlotText = "Right button",
177 selectedAffordanceText = FakeKeyguardQuickAffordanceProviderClient.AFFORDANCE_2,
178 )
179 assertPreviewUiState(
Alejandro Nijamkinc27b1d32022-12-21 15:27:35 -0800180 slots = slots(),
Alejandro Nijamkin0f02b082022-11-24 13:43:43 -0800181 expectedAffordanceNameBySlotId =
182 mapOf(
183 KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START to
184 FakeKeyguardQuickAffordanceProviderClient.AFFORDANCE_1,
185 KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_END to
186 FakeKeyguardQuickAffordanceProviderClient.AFFORDANCE_2,
187 ),
188 )
Alejandro Nijamkin0f02b082022-11-24 13:43:43 -0800189 }
190
191 @Test
192 fun `Unselect - AKA selecting the none affordance - on one side`() =
193 testScope.runTest {
Alejandro Nijamkinc27b1d32022-12-21 15:27:35 -0800194 val slots = collectLastValue(underTest.slots)
195 val quickAffordances = collectLastValue(underTest.quickAffordances)
Alejandro Nijamkin0f02b082022-11-24 13:43:43 -0800196
197 // Select "affordance 1" for the first slot.
Alejandro Nijamkinc27b1d32022-12-21 15:27:35 -0800198 quickAffordances()?.get(1)?.onClicked?.invoke()
Alejandro Nijamkin0f02b082022-11-24 13:43:43 -0800199 // Select an affordance for the second slot.
200 // First, switch to the second slot:
Alejandro Nijamkinc27b1d32022-12-21 15:27:35 -0800201 slots()?.get(KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_END)?.onClicked?.invoke()
Alejandro Nijamkin0f02b082022-11-24 13:43:43 -0800202 // Second, select the "affordance 3" affordance:
Alejandro Nijamkinc27b1d32022-12-21 15:27:35 -0800203 quickAffordances()?.get(3)?.onClicked?.invoke()
Alejandro Nijamkin0f02b082022-11-24 13:43:43 -0800204
205 // Switch back to the first slot:
Alejandro Nijamkinc27b1d32022-12-21 15:27:35 -0800206 slots()?.get(KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START)?.onClicked?.invoke()
Alejandro Nijamkin0f02b082022-11-24 13:43:43 -0800207 // Select the "none" affordance, which is always in position 0:
Alejandro Nijamkinc27b1d32022-12-21 15:27:35 -0800208 quickAffordances()?.get(0)?.onClicked?.invoke()
Alejandro Nijamkin0f02b082022-11-24 13:43:43 -0800209
210 assertPickerUiState(
Alejandro Nijamkinc27b1d32022-12-21 15:27:35 -0800211 slots = slots(),
212 affordances = quickAffordances(),
Alejandro Nijamkin0f02b082022-11-24 13:43:43 -0800213 selectedSlotText = "Left button",
214 selectedAffordanceText = "None",
215 )
216 assertPreviewUiState(
Alejandro Nijamkinc27b1d32022-12-21 15:27:35 -0800217 slots = slots(),
Alejandro Nijamkin0f02b082022-11-24 13:43:43 -0800218 expectedAffordanceNameBySlotId =
219 mapOf(
220 KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START to null,
221 KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_END to
222 FakeKeyguardQuickAffordanceProviderClient.AFFORDANCE_3,
223 ),
224 )
Alejandro Nijamkin0f02b082022-11-24 13:43:43 -0800225 }
226
227 @Test
228 fun `Show enablement dialog when selecting a disabled affordance`() =
229 testScope.runTest {
Alejandro Nijamkinc27b1d32022-12-21 15:27:35 -0800230 val slots = collectLastValue(underTest.slots)
231 val quickAffordances = collectLastValue(underTest.quickAffordances)
232 val dialog = collectLastValue(underTest.dialog)
Alejandro Nijamkin0f02b082022-11-24 13:43:43 -0800233
Alejandro Nijamkin0f02b082022-11-24 13:43:43 -0800234 val enablementInstructions = listOf("header", "enablementInstructions")
235 val enablementActionText = "enablementActionText"
236 val packageName = "packageName"
237 val action = "action"
238 val enablementActionComponentName = "$packageName/$action"
239 // Lets add a disabled affordance to the picker:
240 val affordanceIndex =
241 client.addAffordance(
Alejandro Nijamkinabda67b2022-11-30 14:34:56 -0800242 KeyguardQuickAffordanceProviderClient.Affordance(
243 id = "disabled",
244 name = "disabled",
245 iconResourceId = 0,
246 isEnabled = false,
247 enablementInstructions = enablementInstructions,
248 enablementActionText = enablementActionText,
249 enablementActionComponentName = enablementActionComponentName,
250 )
Alejandro Nijamkin0f02b082022-11-24 13:43:43 -0800251 )
252
253 // Lets try to select that disabled affordance:
Alejandro Nijamkinc27b1d32022-12-21 15:27:35 -0800254 quickAffordances()?.get(affordanceIndex + 1)?.onClicked?.invoke()
Alejandro Nijamkin0f02b082022-11-24 13:43:43 -0800255
256 // We expect there to be a dialog that should be shown:
Alejandro Nijamkinc27b1d32022-12-21 15:27:35 -0800257 assertThat(dialog()?.instructionHeader).isEqualTo(enablementInstructions[0])
258 assertThat(dialog()?.instructions)
Alejandro Nijamkin0f02b082022-11-24 13:43:43 -0800259 .isEqualTo(enablementInstructions.subList(1, enablementInstructions.size))
Alejandro Nijamkinc27b1d32022-12-21 15:27:35 -0800260 assertThat(dialog()?.actionText).isEqualTo(enablementActionText)
261 assertThat(dialog()?.intent?.`package`).isEqualTo(packageName)
262 assertThat(dialog()?.intent?.action).isEqualTo(action)
Alejandro Nijamkin0f02b082022-11-24 13:43:43 -0800263
264 // Once we report that the dialog has been dismissed by the user, we expect there to be
265 // no
266 // dialog to be shown:
267 underTest.onDialogDismissed()
Alejandro Nijamkinc27b1d32022-12-21 15:27:35 -0800268 assertThat(dialog()).isNull()
Alejandro Nijamkin0f02b082022-11-24 13:43:43 -0800269 }
270
Alejandro Nijamkinabda67b2022-11-30 14:34:56 -0800271 @Test
272 fun `summary - affordance selected in both bottom-start and bottom-end`() =
273 testScope.runTest {
Alejandro Nijamkinc27b1d32022-12-21 15:27:35 -0800274 val slots = collectLastValue(underTest.slots)
275 val quickAffordances = collectLastValue(underTest.quickAffordances)
276 val summary = collectLastValue(underTest.summary)
Alejandro Nijamkinabda67b2022-11-30 14:34:56 -0800277
278 // Select "affordance 1" for the first slot.
Alejandro Nijamkinc27b1d32022-12-21 15:27:35 -0800279 quickAffordances()?.get(1)?.onClicked?.invoke()
Alejandro Nijamkinabda67b2022-11-30 14:34:56 -0800280 // Select an affordance for the second slot.
281 // First, switch to the second slot:
Alejandro Nijamkinc27b1d32022-12-21 15:27:35 -0800282 slots()?.get(KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_END)?.onClicked?.invoke()
Alejandro Nijamkinabda67b2022-11-30 14:34:56 -0800283 // Second, select the "affordance 3" affordance:
Alejandro Nijamkinc27b1d32022-12-21 15:27:35 -0800284 quickAffordances()?.get(3)?.onClicked?.invoke()
Alejandro Nijamkinabda67b2022-11-30 14:34:56 -0800285
Alejandro Nijamkinc27b1d32022-12-21 15:27:35 -0800286 assertThat(summary())
Alejandro Nijamkinabda67b2022-11-30 14:34:56 -0800287 .isEqualTo(
288 KeyguardQuickAffordanceSummaryViewModel(
289 description =
290 "${FakeKeyguardQuickAffordanceProviderClient.AFFORDANCE_1}," +
291 " ${FakeKeyguardQuickAffordanceProviderClient.AFFORDANCE_3}",
292 icon1 = FakeKeyguardQuickAffordanceProviderClient.ICON_1,
293 icon2 = FakeKeyguardQuickAffordanceProviderClient.ICON_3,
Alejandro Nijamkinabda67b2022-11-30 14:34:56 -0800294 )
295 )
Alejandro Nijamkinabda67b2022-11-30 14:34:56 -0800296 }
297
298 @Test
299 fun `summary - affordance selected only on bottom-start`() =
300 testScope.runTest {
Alejandro Nijamkinc27b1d32022-12-21 15:27:35 -0800301 val slots = collectLastValue(underTest.slots)
302 val quickAffordances = collectLastValue(underTest.quickAffordances)
303 val summary = collectLastValue(underTest.summary)
Alejandro Nijamkinabda67b2022-11-30 14:34:56 -0800304
305 // Select "affordance 1" for the first slot.
Alejandro Nijamkinc27b1d32022-12-21 15:27:35 -0800306 quickAffordances()?.get(1)?.onClicked?.invoke()
Alejandro Nijamkinabda67b2022-11-30 14:34:56 -0800307
Alejandro Nijamkinc27b1d32022-12-21 15:27:35 -0800308 assertThat(summary())
Alejandro Nijamkinabda67b2022-11-30 14:34:56 -0800309 .isEqualTo(
310 KeyguardQuickAffordanceSummaryViewModel(
311 description = FakeKeyguardQuickAffordanceProviderClient.AFFORDANCE_1,
312 icon1 = FakeKeyguardQuickAffordanceProviderClient.ICON_1,
313 icon2 = null,
Alejandro Nijamkinabda67b2022-11-30 14:34:56 -0800314 )
315 )
Alejandro Nijamkinabda67b2022-11-30 14:34:56 -0800316 }
317
318 @Test
319 fun `summary - affordance selected only on bottom-end`() =
320 testScope.runTest {
Alejandro Nijamkinc27b1d32022-12-21 15:27:35 -0800321 val slots = collectLastValue(underTest.slots)
322 val quickAffordances = collectLastValue(underTest.quickAffordances)
323 val summary = collectLastValue(underTest.summary)
Alejandro Nijamkinabda67b2022-11-30 14:34:56 -0800324
325 // Select an affordance for the second slot.
326 // First, switch to the second slot:
Alejandro Nijamkinc27b1d32022-12-21 15:27:35 -0800327 slots()?.get(KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_END)?.onClicked?.invoke()
Alejandro Nijamkinabda67b2022-11-30 14:34:56 -0800328 // Second, select the "affordance 3" affordance:
Alejandro Nijamkinc27b1d32022-12-21 15:27:35 -0800329 quickAffordances()?.get(3)?.onClicked?.invoke()
Alejandro Nijamkinabda67b2022-11-30 14:34:56 -0800330
Alejandro Nijamkinc27b1d32022-12-21 15:27:35 -0800331 assertThat(summary())
Alejandro Nijamkinabda67b2022-11-30 14:34:56 -0800332 .isEqualTo(
333 KeyguardQuickAffordanceSummaryViewModel(
334 description = FakeKeyguardQuickAffordanceProviderClient.AFFORDANCE_3,
335 icon1 = null,
336 icon2 = FakeKeyguardQuickAffordanceProviderClient.ICON_3,
Alejandro Nijamkinabda67b2022-11-30 14:34:56 -0800337 )
338 )
Alejandro Nijamkinabda67b2022-11-30 14:34:56 -0800339 }
340
341 @Test
342 fun `summary - no affordances selected`() =
343 testScope.runTest {
Alejandro Nijamkinc27b1d32022-12-21 15:27:35 -0800344 val slots = collectLastValue(underTest.slots)
345 val quickAffordances = collectLastValue(underTest.quickAffordances)
346 val summary = collectLastValue(underTest.summary)
Alejandro Nijamkinabda67b2022-11-30 14:34:56 -0800347
Alejandro Nijamkinc27b1d32022-12-21 15:27:35 -0800348 assertThat(summary()?.description).isEqualTo("None")
349 assertThat(summary()?.icon1).isNotNull()
350 assertThat(summary()?.icon2).isNull()
Alejandro Nijamkinabda67b2022-11-30 14:34:56 -0800351 }
352
Alejandro Nijamkin0f02b082022-11-24 13:43:43 -0800353 /**
354 * Asserts the entire picker UI state is what is expected. This includes the slot tabs and the
355 * affordance list.
356 *
357 * @param slots The observed slot view-models, keyed by slot ID
358 * @param affordances The observed affordances
359 * @param selectedSlotText The text of the slot that's expected to be selected
360 * @param selectedAffordanceText The text of the affordance that's expected to be selected
361 */
362 private fun assertPickerUiState(
Alejandro Nijamkinc27b1d32022-12-21 15:27:35 -0800363 slots: Map<String, KeyguardQuickAffordanceSlotViewModel>?,
364 affordances: List<KeyguardQuickAffordanceViewModel>?,
Alejandro Nijamkin0f02b082022-11-24 13:43:43 -0800365 selectedSlotText: String,
366 selectedAffordanceText: String,
367 ) {
368 assertSlotTabUiState(
369 slots = slots,
370 slotId = KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START,
371 isSelected = "Left button" == selectedSlotText,
372 )
373 assertSlotTabUiState(
374 slots = slots,
375 slotId = KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_END,
376 isSelected = "Right button" == selectedSlotText,
377 )
378
379 var foundSelectedAffordance = false
Alejandro Nijamkinc27b1d32022-12-21 15:27:35 -0800380 assertThat(affordances).isNotNull()
381 affordances?.forEach { affordance ->
Alejandro Nijamkin0f02b082022-11-24 13:43:43 -0800382 val nameMatchesSelectedName = affordance.contentDescription == selectedAffordanceText
383 assertWithMessage(
384 "Expected affordance with name \"${affordance.contentDescription}\" to have" +
385 " isSelected=$nameMatchesSelectedName but it was ${affordance.isSelected}"
386 )
387 .that(affordance.isSelected)
388 .isEqualTo(nameMatchesSelectedName)
389 foundSelectedAffordance = foundSelectedAffordance || nameMatchesSelectedName
390 }
391 assertWithMessage("No affordance is selected!").that(foundSelectedAffordance).isTrue()
392 }
393
394 /**
395 * Asserts that a slot tab has the correct UI state.
396 *
397 * @param slots The observed slot view-models, keyed by slot ID
398 * @param slotId the ID of the slot to assert
399 * @param isSelected Whether that slot should be selected
400 */
401 private fun assertSlotTabUiState(
Alejandro Nijamkinc27b1d32022-12-21 15:27:35 -0800402 slots: Map<String, KeyguardQuickAffordanceSlotViewModel>?,
Alejandro Nijamkin0f02b082022-11-24 13:43:43 -0800403 slotId: String,
404 isSelected: Boolean,
405 ) {
Alejandro Nijamkinc27b1d32022-12-21 15:27:35 -0800406 val viewModel = slots?.get(slotId) ?: error("No slot with ID \"$slotId\"!")
Alejandro Nijamkin0f02b082022-11-24 13:43:43 -0800407 assertThat(viewModel.isSelected).isEqualTo(isSelected)
408 }
409
410 /**
411 * Asserts the UI state of the preview.
412 *
413 * @param slots The observed slot view-models, keyed by slot ID
414 * @param expectedAffordanceNameBySlotId The expected name of the selected affordance for each
Alejandro Nijamkinc27b1d32022-12-21 15:27:35 -0800415 * slot ID or `null` if it's expected for there to be no affordance for that slot in the
416 * preview
Alejandro Nijamkin0f02b082022-11-24 13:43:43 -0800417 */
418 private fun assertPreviewUiState(
Alejandro Nijamkinc27b1d32022-12-21 15:27:35 -0800419 slots: Map<String, KeyguardQuickAffordanceSlotViewModel>?,
Alejandro Nijamkin0f02b082022-11-24 13:43:43 -0800420 expectedAffordanceNameBySlotId: Map<String, String?>,
421 ) {
Alejandro Nijamkinc27b1d32022-12-21 15:27:35 -0800422 assertThat(slots).isNotNull()
423 slots?.forEach { (slotId, slotViewModel) ->
Alejandro Nijamkin0f02b082022-11-24 13:43:43 -0800424 val expectedAffordanceName = expectedAffordanceNameBySlotId[slotId]
425 val actualAffordanceName =
426 slotViewModel.selectedQuickAffordances.firstOrNull()?.contentDescription
427 assertWithMessage(
428 "At slotId=\"$slotId\", expected affordance=\"$expectedAffordanceName\" but" +
429 " was \"$actualAffordanceName\"!"
430 )
431 .that(actualAffordanceName)
432 .isEqualTo(expectedAffordanceName)
433 }
434 }
435}