Adding newlyConnectedKeyboard flow to KeyboardRepository
newlyConnectedKeyboard emits new physical Keyboards that are connected to the device. Other changes: 1. Because keyboardConnected starts to be confusing now, I renamed it to isAnyKeyboardConnected. 2. Extracting inputDeviceListener flow to separate shared flow so that both newlyConnectedKeyboard and isAnyKeyboardConnected can use it without each registering their own listener. 3. Commenting KeyboardRepository flows 4. Adding tests for newlyConnectedKeyboard Flag: KEYBOARD_EDUCATION Bug: 277192620 Test: KeyboardRepositoryTest Change-Id: I61044362a4e924d80546ae92300844280174db00
This commit is contained in:
@@ -21,6 +21,7 @@ import com.android.systemui.dagger.SysUISingleton
|
||||
import com.android.systemui.keyboard.data.repository.KeyboardRepository
|
||||
import com.android.systemui.keyboard.shared.model.BacklightModel
|
||||
import javax.inject.Inject
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.flatMapLatest
|
||||
import kotlinx.coroutines.flow.flowOf
|
||||
@@ -34,8 +35,9 @@ constructor(
|
||||
) {
|
||||
|
||||
/** Emits current backlight level as [BacklightModel] or null if keyboard is not connected */
|
||||
@ExperimentalCoroutinesApi
|
||||
val backlight: Flow<BacklightModel?> =
|
||||
keyboardRepository.keyboardConnected.flatMapLatest { connected ->
|
||||
keyboardRepository.isAnyKeyboardConnected.flatMapLatest { connected ->
|
||||
if (connected) keyboardRepository.backlight else flowOf(null)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2023 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.keyboard.data.model
|
||||
|
||||
data class Keyboard(val vendorId: Int, val productId: Int)
|
||||
@@ -25,22 +25,41 @@ import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCall
|
||||
import com.android.systemui.dagger.SysUISingleton
|
||||
import com.android.systemui.dagger.qualifiers.Application
|
||||
import com.android.systemui.dagger.qualifiers.Background
|
||||
import com.android.systemui.keyboard.data.model.Keyboard
|
||||
import com.android.systemui.keyboard.shared.model.BacklightModel
|
||||
import java.util.concurrent.Executor
|
||||
import javax.inject.Inject
|
||||
import kotlinx.coroutines.CoroutineDispatcher
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.FlowPreview
|
||||
import kotlinx.coroutines.channels.SendChannel
|
||||
import kotlinx.coroutines.channels.awaitClose
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.asFlow
|
||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
import kotlinx.coroutines.flow.emptyFlow
|
||||
import kotlinx.coroutines.flow.flatMapConcat
|
||||
import kotlinx.coroutines.flow.flowOf
|
||||
import kotlinx.coroutines.flow.flowOn
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.mapNotNull
|
||||
import kotlinx.coroutines.flow.shareIn
|
||||
|
||||
interface KeyboardRepository {
|
||||
val keyboardConnected: Flow<Boolean>
|
||||
/** Emits true if any physical keyboard is connected to the device, false otherwise. */
|
||||
val isAnyKeyboardConnected: Flow<Boolean>
|
||||
|
||||
/**
|
||||
* Emits [Keyboard] object whenever new physical keyboard connects. When SysUI (re)starts it
|
||||
* emits all currently connected keyboards
|
||||
*/
|
||||
val newlyConnectedKeyboard: Flow<Keyboard>
|
||||
|
||||
/**
|
||||
* Emits [BacklightModel] whenever user changes backlight level from keyboard press. Can only
|
||||
* happen when physical keyboard is connected
|
||||
*/
|
||||
val backlight: Flow<BacklightModel>
|
||||
}
|
||||
|
||||
@@ -53,33 +72,65 @@ constructor(
|
||||
private val inputManager: InputManager,
|
||||
) : KeyboardRepository {
|
||||
|
||||
private val connectedDeviceIds: Flow<Set<Int>> =
|
||||
private sealed interface DeviceChange
|
||||
private data class DeviceAdded(val deviceId: Int) : DeviceChange
|
||||
private object DeviceRemoved : DeviceChange
|
||||
private object FreshStart : DeviceChange
|
||||
|
||||
/**
|
||||
* Emits collection of all currently connected keyboards and what was the last [DeviceChange].
|
||||
* It emits collection so that every new subscriber to this SharedFlow can get latest state of
|
||||
* all keyboards. Otherwise we might get into situation where subscriber timing on
|
||||
* initialization matter and later subscriber will only get latest device and will miss all
|
||||
* previous devices.
|
||||
*/
|
||||
private val keyboardsChange: Flow<Pair<Collection<Int>, DeviceChange>> =
|
||||
conflatedCallbackFlow {
|
||||
var connectedKeyboards = inputManager.inputDeviceIds.toSet()
|
||||
var connectedDevices = inputManager.inputDeviceIds.toSet()
|
||||
val listener =
|
||||
object : InputManager.InputDeviceListener {
|
||||
override fun onInputDeviceAdded(deviceId: Int) {
|
||||
connectedKeyboards = connectedKeyboards + deviceId
|
||||
sendWithLogging(connectedKeyboards)
|
||||
connectedDevices = connectedDevices + deviceId
|
||||
sendWithLogging(connectedDevices to DeviceAdded(deviceId))
|
||||
}
|
||||
|
||||
override fun onInputDeviceChanged(deviceId: Int) = Unit
|
||||
|
||||
override fun onInputDeviceRemoved(deviceId: Int) {
|
||||
connectedKeyboards = connectedKeyboards - deviceId
|
||||
sendWithLogging(connectedKeyboards)
|
||||
connectedDevices = connectedDevices - deviceId
|
||||
sendWithLogging(connectedDevices to DeviceRemoved)
|
||||
}
|
||||
}
|
||||
sendWithLogging(connectedKeyboards)
|
||||
sendWithLogging(connectedDevices to FreshStart)
|
||||
inputManager.registerInputDeviceListener(listener, /* handler= */ null)
|
||||
awaitClose { inputManager.unregisterInputDeviceListener(listener) }
|
||||
}
|
||||
.map { (ids, change) -> ids.filter { id -> isPhysicalFullKeyboard(id) } to change }
|
||||
.shareIn(
|
||||
scope = applicationScope,
|
||||
started = SharingStarted.Lazily,
|
||||
replay = 1,
|
||||
)
|
||||
|
||||
@FlowPreview
|
||||
override val newlyConnectedKeyboard: Flow<Keyboard> =
|
||||
keyboardsChange
|
||||
.flatMapConcat { (devices, operation) ->
|
||||
when (operation) {
|
||||
FreshStart -> devices.asFlow()
|
||||
is DeviceAdded -> flowOf(operation.deviceId)
|
||||
is DeviceRemoved -> emptyFlow()
|
||||
}
|
||||
}
|
||||
.mapNotNull { deviceIdToKeyboard(it) }
|
||||
.flowOn(backgroundDispatcher)
|
||||
|
||||
override val isAnyKeyboardConnected: Flow<Boolean> =
|
||||
keyboardsChange
|
||||
.map { (devices, _) -> devices.isNotEmpty() }
|
||||
.distinctUntilChanged()
|
||||
.flowOn(backgroundDispatcher)
|
||||
|
||||
private val backlightStateListener: Flow<KeyboardBacklightState> = conflatedCallbackFlow {
|
||||
val listener = KeyboardBacklightListener { _, state, isTriggeredByKeyPress ->
|
||||
if (isTriggeredByKeyPress) {
|
||||
@@ -90,11 +141,10 @@ constructor(
|
||||
awaitClose { inputManager.unregisterKeyboardBacklightListener(listener) }
|
||||
}
|
||||
|
||||
override val keyboardConnected: Flow<Boolean> =
|
||||
connectedDeviceIds
|
||||
.map { it.any { deviceId -> isPhysicalFullKeyboard(deviceId) } }
|
||||
.distinctUntilChanged()
|
||||
.flowOn(backgroundDispatcher)
|
||||
private fun deviceIdToKeyboard(deviceId: Int): Keyboard? {
|
||||
val device = inputManager.getInputDevice(deviceId) ?: return null
|
||||
return Keyboard(device.vendorId, device.productId)
|
||||
}
|
||||
|
||||
override val backlight: Flow<BacklightModel> =
|
||||
backlightStateListener
|
||||
|
||||
@@ -47,14 +47,14 @@ class KeyboardBacklightInteractorTest : SysuiTestCase() {
|
||||
@Test
|
||||
fun emitsNull_whenKeyboardJustConnected() = runTest {
|
||||
val latest by collectLastValue(underTest.backlight)
|
||||
keyboardRepository.setKeyboardConnected(true)
|
||||
keyboardRepository.setIsAnyKeyboardConnected(true)
|
||||
|
||||
assertThat(latest).isNull()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun emitsBacklight_whenKeyboardConnectedAndBacklightChanged() = runTest {
|
||||
keyboardRepository.setKeyboardConnected(true)
|
||||
keyboardRepository.setIsAnyKeyboardConnected(true)
|
||||
keyboardRepository.setBacklight(BacklightModel(1, 5))
|
||||
|
||||
assertThat(underTest.backlight.first()).isEqualTo(BacklightModel(1, 5))
|
||||
@@ -63,10 +63,10 @@ class KeyboardBacklightInteractorTest : SysuiTestCase() {
|
||||
@Test
|
||||
fun emitsNull_afterKeyboardDisconnecting() = runTest {
|
||||
val latest by collectLastValue(underTest.backlight)
|
||||
keyboardRepository.setKeyboardConnected(true)
|
||||
keyboardRepository.setIsAnyKeyboardConnected(true)
|
||||
keyboardRepository.setBacklight(BacklightModel(1, 5))
|
||||
|
||||
keyboardRepository.setKeyboardConnected(false)
|
||||
keyboardRepository.setIsAnyKeyboardConnected(false)
|
||||
|
||||
assertThat(latest).isNull()
|
||||
}
|
||||
|
||||
@@ -58,7 +58,7 @@ class BacklightDialogViewModelTest : SysuiTestCase() {
|
||||
KeyboardBacklightInteractor(keyboardRepository),
|
||||
accessibilityManagerWrapper
|
||||
)
|
||||
keyboardRepository.setKeyboardConnected(true)
|
||||
keyboardRepository.setIsAnyKeyboardConnected(true)
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -81,7 +81,7 @@ class BacklightDialogViewModelTest : SysuiTestCase() {
|
||||
@Test
|
||||
fun emitsNull_after5secDelay_fromLastBacklightChange() = runTest {
|
||||
val latest by collectLastValue(underTest.dialogContent)
|
||||
keyboardRepository.setKeyboardConnected(true)
|
||||
keyboardRepository.setIsAnyKeyboardConnected(true)
|
||||
|
||||
keyboardRepository.setBacklight(BacklightModel(1, 5))
|
||||
assertThat(latest).isEqualTo(BacklightDialogContentViewModel(1, 5))
|
||||
|
||||
@@ -25,6 +25,8 @@ import androidx.test.filters.SmallTest
|
||||
import com.android.systemui.SysuiTestCase
|
||||
import com.android.systemui.coroutines.FlowValue
|
||||
import com.android.systemui.coroutines.collectLastValue
|
||||
import com.android.systemui.coroutines.collectValues
|
||||
import com.android.systemui.keyboard.data.model.Keyboard
|
||||
import com.android.systemui.util.mockito.any
|
||||
import com.android.systemui.util.mockito.mock
|
||||
import com.android.systemui.util.mockito.nullable
|
||||
@@ -36,6 +38,7 @@ import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.test.StandardTestDispatcher
|
||||
import kotlinx.coroutines.test.TestScope
|
||||
import kotlinx.coroutines.test.advanceTimeBy
|
||||
import kotlinx.coroutines.test.runCurrent
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.Before
|
||||
@@ -78,7 +81,7 @@ class KeyboardRepositoryTest : SysuiTestCase() {
|
||||
@Test
|
||||
fun emitsDisconnected_ifNothingIsConnected() =
|
||||
testScope.runTest {
|
||||
val initialState = underTest.keyboardConnected.first()
|
||||
val initialState = underTest.isAnyKeyboardConnected.first()
|
||||
assertThat(initialState).isFalse()
|
||||
}
|
||||
|
||||
@@ -86,7 +89,7 @@ class KeyboardRepositoryTest : SysuiTestCase() {
|
||||
fun emitsConnected_ifKeyboardAlreadyConnectedAtTheStart() =
|
||||
testScope.runTest {
|
||||
whenever(inputManager.inputDeviceIds).thenReturn(intArrayOf(PHYSICAL_FULL_KEYBOARD_ID))
|
||||
val initialValue = underTest.keyboardConnected.first()
|
||||
val initialValue = underTest.isAnyKeyboardConnected.first()
|
||||
assertThat(initialValue).isTrue()
|
||||
}
|
||||
|
||||
@@ -94,7 +97,7 @@ class KeyboardRepositoryTest : SysuiTestCase() {
|
||||
fun emitsConnected_whenNewPhysicalKeyboardConnects() =
|
||||
testScope.runTest {
|
||||
val deviceListener = captureDeviceListener()
|
||||
val isKeyboardConnected by collectLastValue(underTest.keyboardConnected)
|
||||
val isKeyboardConnected by collectLastValue(underTest.isAnyKeyboardConnected)
|
||||
|
||||
deviceListener.onInputDeviceAdded(PHYSICAL_FULL_KEYBOARD_ID)
|
||||
|
||||
@@ -105,7 +108,7 @@ class KeyboardRepositoryTest : SysuiTestCase() {
|
||||
fun emitsDisconnected_whenDeviceWithIdDoesNotExist() =
|
||||
testScope.runTest {
|
||||
val deviceListener = captureDeviceListener()
|
||||
val isKeyboardConnected by collectLastValue(underTest.keyboardConnected)
|
||||
val isKeyboardConnected by collectLastValue(underTest.isAnyKeyboardConnected)
|
||||
|
||||
deviceListener.onInputDeviceAdded(NULL_DEVICE_ID)
|
||||
assertThat(isKeyboardConnected).isFalse()
|
||||
@@ -115,7 +118,7 @@ class KeyboardRepositoryTest : SysuiTestCase() {
|
||||
fun emitsDisconnected_whenKeyboardDisconnects() =
|
||||
testScope.runTest {
|
||||
val deviceListener = captureDeviceListener()
|
||||
val isKeyboardConnected by collectLastValue(underTest.keyboardConnected)
|
||||
val isKeyboardConnected by collectLastValue(underTest.isAnyKeyboardConnected)
|
||||
|
||||
deviceListener.onInputDeviceAdded(PHYSICAL_FULL_KEYBOARD_ID)
|
||||
assertThat(isKeyboardConnected).isTrue()
|
||||
@@ -125,7 +128,7 @@ class KeyboardRepositoryTest : SysuiTestCase() {
|
||||
}
|
||||
|
||||
private suspend fun captureDeviceListener(): InputManager.InputDeviceListener {
|
||||
underTest.keyboardConnected.first()
|
||||
underTest.isAnyKeyboardConnected.first()
|
||||
verify(inputManager).registerInputDeviceListener(deviceListenerCaptor.capture(), nullable())
|
||||
return deviceListenerCaptor.value
|
||||
}
|
||||
@@ -134,7 +137,7 @@ class KeyboardRepositoryTest : SysuiTestCase() {
|
||||
fun emitsDisconnected_whenVirtualOrNotFullKeyboardConnects() =
|
||||
testScope.runTest {
|
||||
val deviceListener = captureDeviceListener()
|
||||
val isKeyboardConnected by collectLastValue(underTest.keyboardConnected)
|
||||
val isKeyboardConnected by collectLastValue(underTest.isAnyKeyboardConnected)
|
||||
|
||||
deviceListener.onInputDeviceAdded(PHYSICAL_NOT_FULL_KEYBOARD_ID)
|
||||
assertThat(isKeyboardConnected).isFalse()
|
||||
@@ -147,7 +150,7 @@ class KeyboardRepositoryTest : SysuiTestCase() {
|
||||
fun emitsDisconnected_whenKeyboardDisconnectsAndWasAlreadyConnectedAtTheStart() =
|
||||
testScope.runTest {
|
||||
val deviceListener = captureDeviceListener()
|
||||
val isKeyboardConnected by collectLastValue(underTest.keyboardConnected)
|
||||
val isKeyboardConnected by collectLastValue(underTest.isAnyKeyboardConnected)
|
||||
|
||||
deviceListener.onInputDeviceRemoved(PHYSICAL_FULL_KEYBOARD_ID)
|
||||
assertThat(isKeyboardConnected).isFalse()
|
||||
@@ -157,7 +160,7 @@ class KeyboardRepositoryTest : SysuiTestCase() {
|
||||
fun emitsConnected_whenAnotherDeviceDisconnects() =
|
||||
testScope.runTest {
|
||||
val deviceListener = captureDeviceListener()
|
||||
val isKeyboardConnected by collectLastValue(underTest.keyboardConnected)
|
||||
val isKeyboardConnected by collectLastValue(underTest.isAnyKeyboardConnected)
|
||||
|
||||
deviceListener.onInputDeviceAdded(PHYSICAL_FULL_KEYBOARD_ID)
|
||||
deviceListener.onInputDeviceRemoved(VIRTUAL_FULL_KEYBOARD_ID)
|
||||
@@ -169,7 +172,7 @@ class KeyboardRepositoryTest : SysuiTestCase() {
|
||||
fun emitsConnected_whenOnePhysicalKeyboardDisconnectsButAnotherRemainsConnected() =
|
||||
testScope.runTest {
|
||||
val deviceListener = captureDeviceListener()
|
||||
val isKeyboardConnected by collectLastValue(underTest.keyboardConnected)
|
||||
val isKeyboardConnected by collectLastValue(underTest.isAnyKeyboardConnected)
|
||||
|
||||
deviceListener.onInputDeviceAdded(PHYSICAL_FULL_KEYBOARD_ID)
|
||||
deviceListener.onInputDeviceAdded(ANOTHER_PHYSICAL_FULL_KEYBOARD_ID)
|
||||
@@ -205,7 +208,7 @@ class KeyboardRepositoryTest : SysuiTestCase() {
|
||||
|
||||
@Test
|
||||
fun keyboardBacklightValuesNotPassed_fromBacklightListener_whenNotTriggeredByKeyPress() {
|
||||
testScope.runTest() {
|
||||
testScope.runTest {
|
||||
val backlight by collectLastValueImmediately(underTest.backlight)
|
||||
verify(inputManager)
|
||||
.registerKeyboardBacklightListener(any(), backlightListenerCaptor.capture())
|
||||
@@ -221,7 +224,7 @@ class KeyboardRepositoryTest : SysuiTestCase() {
|
||||
|
||||
@Test
|
||||
fun passesKeyboardBacklightValues_fromBacklightListener_whenTriggeredByKeyPress() {
|
||||
testScope.runTest() {
|
||||
testScope.runTest {
|
||||
val backlight by collectLastValueImmediately(underTest.backlight)
|
||||
verify(inputManager)
|
||||
.registerKeyboardBacklightListener(any(), backlightListenerCaptor.capture())
|
||||
@@ -235,6 +238,86 @@ class KeyboardRepositoryTest : SysuiTestCase() {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun passessAllKeyboards_thatWereAlreadyConnectedOnInitialization() {
|
||||
testScope.runTest {
|
||||
whenever(inputManager.inputDeviceIds)
|
||||
.thenReturn(
|
||||
intArrayOf(
|
||||
PHYSICAL_FULL_KEYBOARD_ID,
|
||||
ANOTHER_PHYSICAL_FULL_KEYBOARD_ID,
|
||||
VIRTUAL_FULL_KEYBOARD_ID // not a physical keyboard - that's why result is 2
|
||||
)
|
||||
)
|
||||
val keyboards by collectValues(underTest.newlyConnectedKeyboard)
|
||||
|
||||
assertThat(keyboards).hasSize(2)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun passesNewlyConnectedKeyboard() {
|
||||
testScope.runTest {
|
||||
val deviceListener = captureDeviceListener()
|
||||
|
||||
deviceListener.onInputDeviceAdded(PHYSICAL_FULL_KEYBOARD_ID)
|
||||
|
||||
assertThat(underTest.newlyConnectedKeyboard.first())
|
||||
.isEqualTo(Keyboard(VENDOR_ID, PRODUCT_ID))
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun emitsOnlyNewlyConnectedKeyboards() {
|
||||
testScope.runTest {
|
||||
whenever(inputManager.inputDeviceIds).thenReturn(intArrayOf(PHYSICAL_FULL_KEYBOARD_ID))
|
||||
underTest.newlyConnectedKeyboard.first()
|
||||
verify(inputManager)
|
||||
.registerInputDeviceListener(deviceListenerCaptor.capture(), nullable())
|
||||
val deviceListener = deviceListenerCaptor.value
|
||||
|
||||
deviceListener.onInputDeviceAdded(ANOTHER_PHYSICAL_FULL_KEYBOARD_ID)
|
||||
val keyboards by collectValues(underTest.newlyConnectedKeyboard)
|
||||
|
||||
assertThat(keyboards).hasSize(1)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun stillEmitsNewKeyboardEvenIfFlowWasSubscribedAfterOtherFlows() {
|
||||
testScope.runTest {
|
||||
whenever(inputManager.inputDeviceIds)
|
||||
.thenReturn(
|
||||
intArrayOf(
|
||||
PHYSICAL_FULL_KEYBOARD_ID,
|
||||
ANOTHER_PHYSICAL_FULL_KEYBOARD_ID,
|
||||
VIRTUAL_FULL_KEYBOARD_ID // not a physical keyboard - that's why result is 2
|
||||
)
|
||||
)
|
||||
collectLastValueImmediately(underTest.isAnyKeyboardConnected)
|
||||
|
||||
// let's pretend second flow is subscribed after some delay
|
||||
advanceTimeBy(1000)
|
||||
val keyboards by collectValues(underTest.newlyConnectedKeyboard)
|
||||
|
||||
assertThat(keyboards).hasSize(2)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun emitsKeyboardWhenItWasReconnected() {
|
||||
testScope.runTest {
|
||||
val deviceListener = captureDeviceListener()
|
||||
val keyboards by collectValues(underTest.newlyConnectedKeyboard)
|
||||
|
||||
deviceListener.onInputDeviceAdded(PHYSICAL_FULL_KEYBOARD_ID)
|
||||
deviceListener.onInputDeviceRemoved(PHYSICAL_FULL_KEYBOARD_ID)
|
||||
deviceListener.onInputDeviceAdded(PHYSICAL_FULL_KEYBOARD_ID)
|
||||
|
||||
assertThat(keyboards).hasSize(2)
|
||||
}
|
||||
}
|
||||
|
||||
private fun KeyboardBacklightListener.onBacklightChanged(
|
||||
current: Int,
|
||||
max: Int,
|
||||
@@ -254,6 +337,9 @@ class KeyboardRepositoryTest : SysuiTestCase() {
|
||||
private const val ANOTHER_PHYSICAL_FULL_KEYBOARD_ID = 4
|
||||
private const val NULL_DEVICE_ID = 5
|
||||
|
||||
private const val VENDOR_ID = 99
|
||||
private const val PRODUCT_ID = 101
|
||||
|
||||
private val INPUT_DEVICES_MAP: Map<Int, InputDevice> =
|
||||
mapOf(
|
||||
PHYSICAL_FULL_KEYBOARD_ID to inputDevice(virtual = false, fullKeyboard = true),
|
||||
@@ -267,6 +353,8 @@ class KeyboardRepositoryTest : SysuiTestCase() {
|
||||
mock<InputDevice>().also {
|
||||
whenever(it.isVirtual).thenReturn(virtual)
|
||||
whenever(it.isFullKeyboard).thenReturn(fullKeyboard)
|
||||
whenever(it.vendorId).thenReturn(VENDOR_ID)
|
||||
whenever(it.productId).thenReturn(PRODUCT_ID)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
|
||||
package com.android.systemui.keyboard.data.repository
|
||||
|
||||
import com.android.systemui.keyboard.data.model.Keyboard
|
||||
import com.android.systemui.keyboard.shared.model.BacklightModel
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
@@ -24,18 +25,25 @@ import kotlinx.coroutines.flow.filterNotNull
|
||||
|
||||
class FakeKeyboardRepository : KeyboardRepository {
|
||||
|
||||
private val _keyboardConnected = MutableStateFlow(false)
|
||||
override val keyboardConnected: Flow<Boolean> = _keyboardConnected
|
||||
private val _isAnyKeyboardConnected = MutableStateFlow(false)
|
||||
override val isAnyKeyboardConnected: Flow<Boolean> = _isAnyKeyboardConnected
|
||||
|
||||
private val _backlightState: MutableStateFlow<BacklightModel?> = MutableStateFlow(null)
|
||||
// filtering to make sure backlight doesn't have default initial value
|
||||
override val backlight: Flow<BacklightModel> = _backlightState.filterNotNull()
|
||||
|
||||
private val _newlyConnectedKeyboard: MutableStateFlow<Keyboard?> = MutableStateFlow(null)
|
||||
override val newlyConnectedKeyboard: Flow<Keyboard> = _newlyConnectedKeyboard.filterNotNull()
|
||||
|
||||
fun setBacklight(state: BacklightModel) {
|
||||
_backlightState.value = state
|
||||
}
|
||||
|
||||
fun setKeyboardConnected(connected: Boolean) {
|
||||
_keyboardConnected.value = connected
|
||||
fun setIsAnyKeyboardConnected(connected: Boolean) {
|
||||
_isAnyKeyboardConnected.value = connected
|
||||
}
|
||||
|
||||
fun setNewlyConnectedKeyboard(keyboard: Keyboard) {
|
||||
_newlyConnectedKeyboard.value = keyboard
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user