Loading packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/data/repository/KeyboardRepositoryTest.kt +67 −91 Original line number Diff line number Diff line Loading @@ -17,11 +17,13 @@ package com.android.systemui.keyboard.data.repository import android.hardware.input.InputManager import android.hardware.input.FakeInputManager import android.hardware.input.InputManager.InputDeviceListener import android.hardware.input.InputManager.KeyboardBacklightListener import android.hardware.input.KeyboardBacklightState import android.hardware.input.fakeInputManager import android.testing.TestableLooper import android.view.InputDevice import android.view.InputDevice.SOURCE_KEYBOARD import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase Loading @@ -30,10 +32,7 @@ import com.android.systemui.coroutines.collectLastValue import com.android.systemui.coroutines.collectValues import com.android.systemui.inputdevice.data.repository.InputDeviceRepository 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 import com.android.systemui.util.mockito.whenever import com.android.systemui.testKosmos import com.android.systemui.utils.os.FakeHandler import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.CoroutineDispatcher Loading @@ -50,9 +49,10 @@ import org.junit.Test import org.junit.runner.RunWith import org.mockito.ArgumentCaptor import org.mockito.Captor import org.mockito.Mock import org.mockito.Mockito.verify import org.mockito.MockitoAnnotations import org.mockito.kotlin.any import org.mockito.kotlin.anyOrNull @OptIn(ExperimentalCoroutinesApi::class) @SmallTest Loading @@ -60,10 +60,9 @@ import org.mockito.MockitoAnnotations @RunWith(AndroidJUnit4::class) class KeyboardRepositoryTest : SysuiTestCase() { @Captor private lateinit var deviceListenerCaptor: ArgumentCaptor<InputManager.InputDeviceListener> @Captor private lateinit var deviceListenerCaptor: ArgumentCaptor<InputDeviceListener> @Captor private lateinit var backlightListenerCaptor: ArgumentCaptor<KeyboardBacklightListener> @Mock private lateinit var inputManager: InputManager private lateinit var fakeInputManager: FakeInputManager private lateinit var underTest: KeyboardRepository private lateinit var dispatcher: CoroutineDispatcher Loading @@ -73,16 +72,14 @@ class KeyboardRepositoryTest : SysuiTestCase() { @Before fun setUp() { MockitoAnnotations.initMocks(this) whenever(inputManager.inputDeviceIds).thenReturn(intArrayOf()) whenever(inputManager.getInputDevice(any())).then { invocation -> val id = invocation.arguments.first() INPUT_DEVICES_MAP[id] } fakeInputManager = testKosmos().fakeInputManager dispatcher = StandardTestDispatcher() testScope = TestScope(dispatcher) val handler = FakeHandler(TestableLooper.get(this).looper) inputDeviceRepo = InputDeviceRepository(handler, testScope.backgroundScope, inputManager) underTest = KeyboardRepositoryImpl(dispatcher, inputManager, inputDeviceRepo) inputDeviceRepo = InputDeviceRepository(handler, testScope.backgroundScope, fakeInputManager.inputManager) underTest = KeyboardRepositoryImpl(dispatcher, fakeInputManager.inputManager, inputDeviceRepo) } @Test Loading @@ -95,7 +92,7 @@ class KeyboardRepositoryTest : SysuiTestCase() { @Test fun emitsConnected_ifKeyboardAlreadyConnectedAtTheStart() = testScope.runTest { whenever(inputManager.inputDeviceIds).thenReturn(intArrayOf(PHYSICAL_FULL_KEYBOARD_ID)) fakeInputManager.addPhysicalKeyboard(PHYSICAL_FULL_KEYBOARD_ID) val initialValue = underTest.isAnyKeyboardConnected.first() assertThat(initialValue).isTrue() } Loading @@ -103,74 +100,77 @@ class KeyboardRepositoryTest : SysuiTestCase() { @Test fun emitsConnected_whenNewPhysicalKeyboardConnects() = testScope.runTest { val deviceListener = captureDeviceListener() captureDeviceListener() val isKeyboardConnected by collectLastValue(underTest.isAnyKeyboardConnected) deviceListener.onInputDeviceAdded(PHYSICAL_FULL_KEYBOARD_ID) fakeInputManager.addPhysicalKeyboard(PHYSICAL_FULL_KEYBOARD_ID) assertThat(isKeyboardConnected).isTrue() } @Test fun emitsDisconnected_whenDeviceWithIdDoesNotExist() = fun emitsDisconnected_whenDeviceNotFound() = testScope.runTest { val deviceListener = captureDeviceListener() captureDeviceListener() val isKeyboardConnected by collectLastValue(underTest.isAnyKeyboardConnected) deviceListener.onInputDeviceAdded(NULL_DEVICE_ID) fakeInputManager.addDevice(NULL_DEVICE_ID, SOURCE_KEYBOARD, isNotFound = true) assertThat(isKeyboardConnected).isFalse() } @Test fun emitsDisconnected_whenKeyboardDisconnects() = testScope.runTest { val deviceListener = captureDeviceListener() captureDeviceListener() val isKeyboardConnected by collectLastValue(underTest.isAnyKeyboardConnected) deviceListener.onInputDeviceAdded(PHYSICAL_FULL_KEYBOARD_ID) fakeInputManager.addPhysicalKeyboard(PHYSICAL_FULL_KEYBOARD_ID) assertThat(isKeyboardConnected).isTrue() deviceListener.onInputDeviceRemoved(PHYSICAL_FULL_KEYBOARD_ID) fakeInputManager.removeDevice(PHYSICAL_FULL_KEYBOARD_ID) assertThat(isKeyboardConnected).isFalse() } private suspend fun captureDeviceListener(): InputManager.InputDeviceListener { private suspend fun captureDeviceListener() { underTest.isAnyKeyboardConnected.first() verify(inputManager).registerInputDeviceListener(deviceListenerCaptor.capture(), nullable()) return deviceListenerCaptor.value verify(fakeInputManager.inputManager) .registerInputDeviceListener(deviceListenerCaptor.capture(), anyOrNull()) fakeInputManager.registerInputDeviceListener(deviceListenerCaptor.value) } @Test fun emitsDisconnected_whenVirtualOrNotFullKeyboardConnects() = testScope.runTest { val deviceListener = captureDeviceListener() captureDeviceListener() val isKeyboardConnected by collectLastValue(underTest.isAnyKeyboardConnected) deviceListener.onInputDeviceAdded(PHYSICAL_NOT_FULL_KEYBOARD_ID) fakeInputManager.addPhysicalKeyboard( PHYSICAL_NOT_FULL_KEYBOARD_ID, isFullKeyboard = false ) assertThat(isKeyboardConnected).isFalse() deviceListener.onInputDeviceAdded(VIRTUAL_FULL_KEYBOARD_ID) fakeInputManager.addDevice(VIRTUAL_FULL_KEYBOARD_ID, SOURCE_KEYBOARD) assertThat(isKeyboardConnected).isFalse() } @Test fun emitsDisconnected_whenKeyboardDisconnectsAndWasAlreadyConnectedAtTheStart() = testScope.runTest { val deviceListener = captureDeviceListener() captureDeviceListener() val isKeyboardConnected by collectLastValue(underTest.isAnyKeyboardConnected) deviceListener.onInputDeviceRemoved(PHYSICAL_FULL_KEYBOARD_ID) fakeInputManager.removeDevice(PHYSICAL_FULL_KEYBOARD_ID) assertThat(isKeyboardConnected).isFalse() } @Test fun emitsConnected_whenAnotherDeviceDisconnects() = testScope.runTest { val deviceListener = captureDeviceListener() captureDeviceListener() val isKeyboardConnected by collectLastValue(underTest.isAnyKeyboardConnected) deviceListener.onInputDeviceAdded(PHYSICAL_FULL_KEYBOARD_ID) deviceListener.onInputDeviceRemoved(VIRTUAL_FULL_KEYBOARD_ID) fakeInputManager.addPhysicalKeyboard(PHYSICAL_FULL_KEYBOARD_ID) fakeInputManager.removeDevice(VIRTUAL_FULL_KEYBOARD_ID) assertThat(isKeyboardConnected).isTrue() } Loading @@ -178,12 +178,12 @@ class KeyboardRepositoryTest : SysuiTestCase() { @Test fun emitsConnected_whenOnePhysicalKeyboardDisconnectsButAnotherRemainsConnected() = testScope.runTest { val deviceListener = captureDeviceListener() captureDeviceListener() val isKeyboardConnected by collectLastValue(underTest.isAnyKeyboardConnected) deviceListener.onInputDeviceAdded(PHYSICAL_FULL_KEYBOARD_ID) deviceListener.onInputDeviceAdded(ANOTHER_PHYSICAL_FULL_KEYBOARD_ID) deviceListener.onInputDeviceRemoved(ANOTHER_PHYSICAL_FULL_KEYBOARD_ID) fakeInputManager.addPhysicalKeyboard(PHYSICAL_FULL_KEYBOARD_ID) fakeInputManager.addPhysicalKeyboard(ANOTHER_PHYSICAL_FULL_KEYBOARD_ID) fakeInputManager.removeDevice(ANOTHER_PHYSICAL_FULL_KEYBOARD_ID) assertThat(isKeyboardConnected).isTrue() } Loading @@ -195,7 +195,7 @@ class KeyboardRepositoryTest : SysuiTestCase() { // subscribed to and listener is actually registered in inputManager val backlight by collectLastValueImmediately(underTest.backlight) verify(inputManager) verify(fakeInputManager.inputManager) .registerKeyboardBacklightListener(any(), backlightListenerCaptor.capture()) backlightListenerCaptor.value.onBacklightChanged(current = 1, max = 5) Loading @@ -217,7 +217,7 @@ class KeyboardRepositoryTest : SysuiTestCase() { fun keyboardBacklightValuesNotPassed_fromBacklightListener_whenNotTriggeredByKeyPress() { testScope.runTest { val backlight by collectLastValueImmediately(underTest.backlight) verify(inputManager) verify(fakeInputManager.inputManager) .registerKeyboardBacklightListener(any(), backlightListenerCaptor.capture()) backlightListenerCaptor.value.onBacklightChanged( Loading @@ -233,7 +233,7 @@ class KeyboardRepositoryTest : SysuiTestCase() { fun passesKeyboardBacklightValues_fromBacklightListener_whenTriggeredByKeyPress() { testScope.runTest { val backlight by collectLastValueImmediately(underTest.backlight) verify(inputManager) verify(fakeInputManager.inputManager) .registerKeyboardBacklightListener(any(), backlightListenerCaptor.capture()) backlightListenerCaptor.value.onBacklightChanged( Loading @@ -248,14 +248,11 @@ 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 ) ) fakeInputManager.addPhysicalKeyboard(PHYSICAL_FULL_KEYBOARD_ID) fakeInputManager.addPhysicalKeyboard(ANOTHER_PHYSICAL_FULL_KEYBOARD_ID) // not a physical keyboard - that's why result is 2 fakeInputManager.addDevice(VIRTUAL_FULL_KEYBOARD_ID, SOURCE_KEYBOARD) val keyboards by collectValues(underTest.newlyConnectedKeyboard) assertThat(keyboards).hasSize(2) Loading @@ -265,9 +262,9 @@ class KeyboardRepositoryTest : SysuiTestCase() { @Test fun passesNewlyConnectedKeyboard() { testScope.runTest { val deviceListener = captureDeviceListener() captureDeviceListener() deviceListener.onInputDeviceAdded(PHYSICAL_FULL_KEYBOARD_ID) fakeInputManager.addPhysicalKeyboard(PHYSICAL_FULL_KEYBOARD_ID, VENDOR_ID, PRODUCT_ID) assertThat(underTest.newlyConnectedKeyboard.first()) .isEqualTo(Keyboard(VENDOR_ID, PRODUCT_ID)) Loading @@ -277,13 +274,12 @@ class KeyboardRepositoryTest : SysuiTestCase() { @Test fun emitsOnlyNewlyConnectedKeyboards() { testScope.runTest { whenever(inputManager.inputDeviceIds).thenReturn(intArrayOf(PHYSICAL_FULL_KEYBOARD_ID)) fakeInputManager.addPhysicalKeyboard(PHYSICAL_FULL_KEYBOARD_ID) underTest.newlyConnectedKeyboard.first() verify(inputManager) .registerInputDeviceListener(deviceListenerCaptor.capture(), nullable()) val deviceListener = deviceListenerCaptor.value deviceListener.onInputDeviceAdded(ANOTHER_PHYSICAL_FULL_KEYBOARD_ID) captureDeviceListener() fakeInputManager.addPhysicalKeyboard(ANOTHER_PHYSICAL_FULL_KEYBOARD_ID) val keyboards by collectValues(underTest.newlyConnectedKeyboard) assertThat(keyboards).hasSize(1) Loading @@ -293,14 +289,11 @@ class KeyboardRepositoryTest : SysuiTestCase() { @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 ) ) fakeInputManager.addPhysicalKeyboard(PHYSICAL_FULL_KEYBOARD_ID) fakeInputManager.addPhysicalKeyboard(ANOTHER_PHYSICAL_FULL_KEYBOARD_ID) // not a physical keyboard - that's why result is 2 fakeInputManager.addDevice(VIRTUAL_FULL_KEYBOARD_ID, SOURCE_KEYBOARD) collectLastValueImmediately(underTest.isAnyKeyboardConnected) // let's pretend second flow is subscribed after some delay Loading @@ -314,12 +307,12 @@ class KeyboardRepositoryTest : SysuiTestCase() { @Test fun emitsKeyboardWhenItWasReconnected() { testScope.runTest { val deviceListener = captureDeviceListener() 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) fakeInputManager.addPhysicalKeyboard(PHYSICAL_FULL_KEYBOARD_ID) fakeInputManager.removeDevice(PHYSICAL_FULL_KEYBOARD_ID) fakeInputManager.addPhysicalKeyboard(PHYSICAL_FULL_KEYBOARD_ID) assertThat(keyboards).hasSize(2) } Loading @@ -339,30 +332,13 @@ class KeyboardRepositoryTest : SysuiTestCase() { private companion object { private const val PHYSICAL_FULL_KEYBOARD_ID = 1 private const val VIRTUAL_FULL_KEYBOARD_ID = 2 private const val VIRTUAL_FULL_KEYBOARD_ID = -2 // Virtual keyboards has id with minus value private const val PHYSICAL_NOT_FULL_KEYBOARD_ID = 3 private const val ANOTHER_PHYSICAL_FULL_KEYBOARD_ID = 4 private const val NULL_DEVICE_ID = 5 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), VIRTUAL_FULL_KEYBOARD_ID to inputDevice(virtual = true, fullKeyboard = true), PHYSICAL_NOT_FULL_KEYBOARD_ID to inputDevice(virtual = false, fullKeyboard = false), ANOTHER_PHYSICAL_FULL_KEYBOARD_ID to inputDevice(virtual = false, fullKeyboard = true) ) private fun inputDevice(virtual: Boolean, fullKeyboard: Boolean): InputDevice = 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) } } private class TestBacklightState( Loading packages/SystemUI/tests/utils/src/android/hardware/input/FakeInputManager.kt +33 −9 Original line number Diff line number Diff line Loading @@ -84,7 +84,7 @@ class FakeInputManager { if (devices.containsKey(deviceId)) { return } addPhysicalKeyboard(deviceId, enabled) addPhysicalKeyboard(deviceId, enabled = enabled) } fun registerInputDeviceListener(listener: InputDeviceListener) { Loading @@ -92,9 +92,15 @@ class FakeInputManager { inputDeviceListener = listener } fun addPhysicalKeyboard(id: Int, enabled: Boolean = true) { fun addPhysicalKeyboard( id: Int, vendorId: Int = 0, productId: Int = 0, isFullKeyboard: Boolean = true, enabled: Boolean = true ) { check(id > 0) { "Physical keyboard ids have to be > 0" } addKeyboard(id, enabled) addKeyboard(id, vendorId, productId, isFullKeyboard, enabled) } fun removeKeysFromKeyboard(deviceId: Int, vararg keyCodes: Int) { Loading @@ -102,20 +108,38 @@ class FakeInputManager { supportedKeyCodesByDeviceId[deviceId]!!.removeAll(keyCodes.asList()) } private fun addKeyboard(id: Int, enabled: Boolean = true) { devices[id] = private fun addKeyboard( id: Int, vendorId: Int = 0, productId: Int = 0, isFullKeyboard: Boolean = true, enabled: Boolean = true ) { val keyboardType = if (isFullKeyboard) InputDevice.KEYBOARD_TYPE_ALPHABETIC else InputDevice.KEYBOARD_TYPE_NON_ALPHABETIC // VendorId and productId are set to 0 if not specified, which is the same as the default // values used in InputDevice.Builder val builder = InputDevice.Builder() .setId(id) .setKeyboardType(InputDevice.KEYBOARD_TYPE_ALPHABETIC) .setVendorId(vendorId) .setProductId(productId) .setKeyboardType(keyboardType) .setSources(InputDevice.SOURCE_KEYBOARD) .setEnabled(enabled) .setKeyCharacterMap(keyCharacterMap) .build() devices[id] = builder.build() inputDeviceListener?.onInputDeviceAdded(id) supportedKeyCodesByDeviceId[id] = allKeyCodes.toMutableSet() } fun addDevice(id: Int, sources: Int) { fun addDevice(id: Int, sources: Int, isNotFound: Boolean = false) { // there's not way of differentiate device connection vs registry in current implementation. // If the device isNotFound, it means that we connect an unregistered device. if (!isNotFound) { devices[id] = InputDevice.Builder().setId(id).setSources(sources).build() } inputDeviceListener?.onInputDeviceAdded(id) } Loading Loading
packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/data/repository/KeyboardRepositoryTest.kt +67 −91 Original line number Diff line number Diff line Loading @@ -17,11 +17,13 @@ package com.android.systemui.keyboard.data.repository import android.hardware.input.InputManager import android.hardware.input.FakeInputManager import android.hardware.input.InputManager.InputDeviceListener import android.hardware.input.InputManager.KeyboardBacklightListener import android.hardware.input.KeyboardBacklightState import android.hardware.input.fakeInputManager import android.testing.TestableLooper import android.view.InputDevice import android.view.InputDevice.SOURCE_KEYBOARD import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase Loading @@ -30,10 +32,7 @@ import com.android.systemui.coroutines.collectLastValue import com.android.systemui.coroutines.collectValues import com.android.systemui.inputdevice.data.repository.InputDeviceRepository 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 import com.android.systemui.util.mockito.whenever import com.android.systemui.testKosmos import com.android.systemui.utils.os.FakeHandler import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.CoroutineDispatcher Loading @@ -50,9 +49,10 @@ import org.junit.Test import org.junit.runner.RunWith import org.mockito.ArgumentCaptor import org.mockito.Captor import org.mockito.Mock import org.mockito.Mockito.verify import org.mockito.MockitoAnnotations import org.mockito.kotlin.any import org.mockito.kotlin.anyOrNull @OptIn(ExperimentalCoroutinesApi::class) @SmallTest Loading @@ -60,10 +60,9 @@ import org.mockito.MockitoAnnotations @RunWith(AndroidJUnit4::class) class KeyboardRepositoryTest : SysuiTestCase() { @Captor private lateinit var deviceListenerCaptor: ArgumentCaptor<InputManager.InputDeviceListener> @Captor private lateinit var deviceListenerCaptor: ArgumentCaptor<InputDeviceListener> @Captor private lateinit var backlightListenerCaptor: ArgumentCaptor<KeyboardBacklightListener> @Mock private lateinit var inputManager: InputManager private lateinit var fakeInputManager: FakeInputManager private lateinit var underTest: KeyboardRepository private lateinit var dispatcher: CoroutineDispatcher Loading @@ -73,16 +72,14 @@ class KeyboardRepositoryTest : SysuiTestCase() { @Before fun setUp() { MockitoAnnotations.initMocks(this) whenever(inputManager.inputDeviceIds).thenReturn(intArrayOf()) whenever(inputManager.getInputDevice(any())).then { invocation -> val id = invocation.arguments.first() INPUT_DEVICES_MAP[id] } fakeInputManager = testKosmos().fakeInputManager dispatcher = StandardTestDispatcher() testScope = TestScope(dispatcher) val handler = FakeHandler(TestableLooper.get(this).looper) inputDeviceRepo = InputDeviceRepository(handler, testScope.backgroundScope, inputManager) underTest = KeyboardRepositoryImpl(dispatcher, inputManager, inputDeviceRepo) inputDeviceRepo = InputDeviceRepository(handler, testScope.backgroundScope, fakeInputManager.inputManager) underTest = KeyboardRepositoryImpl(dispatcher, fakeInputManager.inputManager, inputDeviceRepo) } @Test Loading @@ -95,7 +92,7 @@ class KeyboardRepositoryTest : SysuiTestCase() { @Test fun emitsConnected_ifKeyboardAlreadyConnectedAtTheStart() = testScope.runTest { whenever(inputManager.inputDeviceIds).thenReturn(intArrayOf(PHYSICAL_FULL_KEYBOARD_ID)) fakeInputManager.addPhysicalKeyboard(PHYSICAL_FULL_KEYBOARD_ID) val initialValue = underTest.isAnyKeyboardConnected.first() assertThat(initialValue).isTrue() } Loading @@ -103,74 +100,77 @@ class KeyboardRepositoryTest : SysuiTestCase() { @Test fun emitsConnected_whenNewPhysicalKeyboardConnects() = testScope.runTest { val deviceListener = captureDeviceListener() captureDeviceListener() val isKeyboardConnected by collectLastValue(underTest.isAnyKeyboardConnected) deviceListener.onInputDeviceAdded(PHYSICAL_FULL_KEYBOARD_ID) fakeInputManager.addPhysicalKeyboard(PHYSICAL_FULL_KEYBOARD_ID) assertThat(isKeyboardConnected).isTrue() } @Test fun emitsDisconnected_whenDeviceWithIdDoesNotExist() = fun emitsDisconnected_whenDeviceNotFound() = testScope.runTest { val deviceListener = captureDeviceListener() captureDeviceListener() val isKeyboardConnected by collectLastValue(underTest.isAnyKeyboardConnected) deviceListener.onInputDeviceAdded(NULL_DEVICE_ID) fakeInputManager.addDevice(NULL_DEVICE_ID, SOURCE_KEYBOARD, isNotFound = true) assertThat(isKeyboardConnected).isFalse() } @Test fun emitsDisconnected_whenKeyboardDisconnects() = testScope.runTest { val deviceListener = captureDeviceListener() captureDeviceListener() val isKeyboardConnected by collectLastValue(underTest.isAnyKeyboardConnected) deviceListener.onInputDeviceAdded(PHYSICAL_FULL_KEYBOARD_ID) fakeInputManager.addPhysicalKeyboard(PHYSICAL_FULL_KEYBOARD_ID) assertThat(isKeyboardConnected).isTrue() deviceListener.onInputDeviceRemoved(PHYSICAL_FULL_KEYBOARD_ID) fakeInputManager.removeDevice(PHYSICAL_FULL_KEYBOARD_ID) assertThat(isKeyboardConnected).isFalse() } private suspend fun captureDeviceListener(): InputManager.InputDeviceListener { private suspend fun captureDeviceListener() { underTest.isAnyKeyboardConnected.first() verify(inputManager).registerInputDeviceListener(deviceListenerCaptor.capture(), nullable()) return deviceListenerCaptor.value verify(fakeInputManager.inputManager) .registerInputDeviceListener(deviceListenerCaptor.capture(), anyOrNull()) fakeInputManager.registerInputDeviceListener(deviceListenerCaptor.value) } @Test fun emitsDisconnected_whenVirtualOrNotFullKeyboardConnects() = testScope.runTest { val deviceListener = captureDeviceListener() captureDeviceListener() val isKeyboardConnected by collectLastValue(underTest.isAnyKeyboardConnected) deviceListener.onInputDeviceAdded(PHYSICAL_NOT_FULL_KEYBOARD_ID) fakeInputManager.addPhysicalKeyboard( PHYSICAL_NOT_FULL_KEYBOARD_ID, isFullKeyboard = false ) assertThat(isKeyboardConnected).isFalse() deviceListener.onInputDeviceAdded(VIRTUAL_FULL_KEYBOARD_ID) fakeInputManager.addDevice(VIRTUAL_FULL_KEYBOARD_ID, SOURCE_KEYBOARD) assertThat(isKeyboardConnected).isFalse() } @Test fun emitsDisconnected_whenKeyboardDisconnectsAndWasAlreadyConnectedAtTheStart() = testScope.runTest { val deviceListener = captureDeviceListener() captureDeviceListener() val isKeyboardConnected by collectLastValue(underTest.isAnyKeyboardConnected) deviceListener.onInputDeviceRemoved(PHYSICAL_FULL_KEYBOARD_ID) fakeInputManager.removeDevice(PHYSICAL_FULL_KEYBOARD_ID) assertThat(isKeyboardConnected).isFalse() } @Test fun emitsConnected_whenAnotherDeviceDisconnects() = testScope.runTest { val deviceListener = captureDeviceListener() captureDeviceListener() val isKeyboardConnected by collectLastValue(underTest.isAnyKeyboardConnected) deviceListener.onInputDeviceAdded(PHYSICAL_FULL_KEYBOARD_ID) deviceListener.onInputDeviceRemoved(VIRTUAL_FULL_KEYBOARD_ID) fakeInputManager.addPhysicalKeyboard(PHYSICAL_FULL_KEYBOARD_ID) fakeInputManager.removeDevice(VIRTUAL_FULL_KEYBOARD_ID) assertThat(isKeyboardConnected).isTrue() } Loading @@ -178,12 +178,12 @@ class KeyboardRepositoryTest : SysuiTestCase() { @Test fun emitsConnected_whenOnePhysicalKeyboardDisconnectsButAnotherRemainsConnected() = testScope.runTest { val deviceListener = captureDeviceListener() captureDeviceListener() val isKeyboardConnected by collectLastValue(underTest.isAnyKeyboardConnected) deviceListener.onInputDeviceAdded(PHYSICAL_FULL_KEYBOARD_ID) deviceListener.onInputDeviceAdded(ANOTHER_PHYSICAL_FULL_KEYBOARD_ID) deviceListener.onInputDeviceRemoved(ANOTHER_PHYSICAL_FULL_KEYBOARD_ID) fakeInputManager.addPhysicalKeyboard(PHYSICAL_FULL_KEYBOARD_ID) fakeInputManager.addPhysicalKeyboard(ANOTHER_PHYSICAL_FULL_KEYBOARD_ID) fakeInputManager.removeDevice(ANOTHER_PHYSICAL_FULL_KEYBOARD_ID) assertThat(isKeyboardConnected).isTrue() } Loading @@ -195,7 +195,7 @@ class KeyboardRepositoryTest : SysuiTestCase() { // subscribed to and listener is actually registered in inputManager val backlight by collectLastValueImmediately(underTest.backlight) verify(inputManager) verify(fakeInputManager.inputManager) .registerKeyboardBacklightListener(any(), backlightListenerCaptor.capture()) backlightListenerCaptor.value.onBacklightChanged(current = 1, max = 5) Loading @@ -217,7 +217,7 @@ class KeyboardRepositoryTest : SysuiTestCase() { fun keyboardBacklightValuesNotPassed_fromBacklightListener_whenNotTriggeredByKeyPress() { testScope.runTest { val backlight by collectLastValueImmediately(underTest.backlight) verify(inputManager) verify(fakeInputManager.inputManager) .registerKeyboardBacklightListener(any(), backlightListenerCaptor.capture()) backlightListenerCaptor.value.onBacklightChanged( Loading @@ -233,7 +233,7 @@ class KeyboardRepositoryTest : SysuiTestCase() { fun passesKeyboardBacklightValues_fromBacklightListener_whenTriggeredByKeyPress() { testScope.runTest { val backlight by collectLastValueImmediately(underTest.backlight) verify(inputManager) verify(fakeInputManager.inputManager) .registerKeyboardBacklightListener(any(), backlightListenerCaptor.capture()) backlightListenerCaptor.value.onBacklightChanged( Loading @@ -248,14 +248,11 @@ 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 ) ) fakeInputManager.addPhysicalKeyboard(PHYSICAL_FULL_KEYBOARD_ID) fakeInputManager.addPhysicalKeyboard(ANOTHER_PHYSICAL_FULL_KEYBOARD_ID) // not a physical keyboard - that's why result is 2 fakeInputManager.addDevice(VIRTUAL_FULL_KEYBOARD_ID, SOURCE_KEYBOARD) val keyboards by collectValues(underTest.newlyConnectedKeyboard) assertThat(keyboards).hasSize(2) Loading @@ -265,9 +262,9 @@ class KeyboardRepositoryTest : SysuiTestCase() { @Test fun passesNewlyConnectedKeyboard() { testScope.runTest { val deviceListener = captureDeviceListener() captureDeviceListener() deviceListener.onInputDeviceAdded(PHYSICAL_FULL_KEYBOARD_ID) fakeInputManager.addPhysicalKeyboard(PHYSICAL_FULL_KEYBOARD_ID, VENDOR_ID, PRODUCT_ID) assertThat(underTest.newlyConnectedKeyboard.first()) .isEqualTo(Keyboard(VENDOR_ID, PRODUCT_ID)) Loading @@ -277,13 +274,12 @@ class KeyboardRepositoryTest : SysuiTestCase() { @Test fun emitsOnlyNewlyConnectedKeyboards() { testScope.runTest { whenever(inputManager.inputDeviceIds).thenReturn(intArrayOf(PHYSICAL_FULL_KEYBOARD_ID)) fakeInputManager.addPhysicalKeyboard(PHYSICAL_FULL_KEYBOARD_ID) underTest.newlyConnectedKeyboard.first() verify(inputManager) .registerInputDeviceListener(deviceListenerCaptor.capture(), nullable()) val deviceListener = deviceListenerCaptor.value deviceListener.onInputDeviceAdded(ANOTHER_PHYSICAL_FULL_KEYBOARD_ID) captureDeviceListener() fakeInputManager.addPhysicalKeyboard(ANOTHER_PHYSICAL_FULL_KEYBOARD_ID) val keyboards by collectValues(underTest.newlyConnectedKeyboard) assertThat(keyboards).hasSize(1) Loading @@ -293,14 +289,11 @@ class KeyboardRepositoryTest : SysuiTestCase() { @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 ) ) fakeInputManager.addPhysicalKeyboard(PHYSICAL_FULL_KEYBOARD_ID) fakeInputManager.addPhysicalKeyboard(ANOTHER_PHYSICAL_FULL_KEYBOARD_ID) // not a physical keyboard - that's why result is 2 fakeInputManager.addDevice(VIRTUAL_FULL_KEYBOARD_ID, SOURCE_KEYBOARD) collectLastValueImmediately(underTest.isAnyKeyboardConnected) // let's pretend second flow is subscribed after some delay Loading @@ -314,12 +307,12 @@ class KeyboardRepositoryTest : SysuiTestCase() { @Test fun emitsKeyboardWhenItWasReconnected() { testScope.runTest { val deviceListener = captureDeviceListener() 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) fakeInputManager.addPhysicalKeyboard(PHYSICAL_FULL_KEYBOARD_ID) fakeInputManager.removeDevice(PHYSICAL_FULL_KEYBOARD_ID) fakeInputManager.addPhysicalKeyboard(PHYSICAL_FULL_KEYBOARD_ID) assertThat(keyboards).hasSize(2) } Loading @@ -339,30 +332,13 @@ class KeyboardRepositoryTest : SysuiTestCase() { private companion object { private const val PHYSICAL_FULL_KEYBOARD_ID = 1 private const val VIRTUAL_FULL_KEYBOARD_ID = 2 private const val VIRTUAL_FULL_KEYBOARD_ID = -2 // Virtual keyboards has id with minus value private const val PHYSICAL_NOT_FULL_KEYBOARD_ID = 3 private const val ANOTHER_PHYSICAL_FULL_KEYBOARD_ID = 4 private const val NULL_DEVICE_ID = 5 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), VIRTUAL_FULL_KEYBOARD_ID to inputDevice(virtual = true, fullKeyboard = true), PHYSICAL_NOT_FULL_KEYBOARD_ID to inputDevice(virtual = false, fullKeyboard = false), ANOTHER_PHYSICAL_FULL_KEYBOARD_ID to inputDevice(virtual = false, fullKeyboard = true) ) private fun inputDevice(virtual: Boolean, fullKeyboard: Boolean): InputDevice = 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) } } private class TestBacklightState( Loading
packages/SystemUI/tests/utils/src/android/hardware/input/FakeInputManager.kt +33 −9 Original line number Diff line number Diff line Loading @@ -84,7 +84,7 @@ class FakeInputManager { if (devices.containsKey(deviceId)) { return } addPhysicalKeyboard(deviceId, enabled) addPhysicalKeyboard(deviceId, enabled = enabled) } fun registerInputDeviceListener(listener: InputDeviceListener) { Loading @@ -92,9 +92,15 @@ class FakeInputManager { inputDeviceListener = listener } fun addPhysicalKeyboard(id: Int, enabled: Boolean = true) { fun addPhysicalKeyboard( id: Int, vendorId: Int = 0, productId: Int = 0, isFullKeyboard: Boolean = true, enabled: Boolean = true ) { check(id > 0) { "Physical keyboard ids have to be > 0" } addKeyboard(id, enabled) addKeyboard(id, vendorId, productId, isFullKeyboard, enabled) } fun removeKeysFromKeyboard(deviceId: Int, vararg keyCodes: Int) { Loading @@ -102,20 +108,38 @@ class FakeInputManager { supportedKeyCodesByDeviceId[deviceId]!!.removeAll(keyCodes.asList()) } private fun addKeyboard(id: Int, enabled: Boolean = true) { devices[id] = private fun addKeyboard( id: Int, vendorId: Int = 0, productId: Int = 0, isFullKeyboard: Boolean = true, enabled: Boolean = true ) { val keyboardType = if (isFullKeyboard) InputDevice.KEYBOARD_TYPE_ALPHABETIC else InputDevice.KEYBOARD_TYPE_NON_ALPHABETIC // VendorId and productId are set to 0 if not specified, which is the same as the default // values used in InputDevice.Builder val builder = InputDevice.Builder() .setId(id) .setKeyboardType(InputDevice.KEYBOARD_TYPE_ALPHABETIC) .setVendorId(vendorId) .setProductId(productId) .setKeyboardType(keyboardType) .setSources(InputDevice.SOURCE_KEYBOARD) .setEnabled(enabled) .setKeyCharacterMap(keyCharacterMap) .build() devices[id] = builder.build() inputDeviceListener?.onInputDeviceAdded(id) supportedKeyCodesByDeviceId[id] = allKeyCodes.toMutableSet() } fun addDevice(id: Int, sources: Int) { fun addDevice(id: Int, sources: Int, isNotFound: Boolean = false) { // there's not way of differentiate device connection vs registry in current implementation. // If the device isNotFound, it means that we connect an unregistered device. if (!isNotFound) { devices[id] = InputDevice.Builder().setId(id).setSources(sources).build() } inputDeviceListener?.onInputDeviceAdded(id) } Loading