Loading packages/SystemUI/src/com/android/systemui/keyboard/stickykeys/StickyKeysLogger.kt +10 −1 Original line number Original line Diff line number Diff line Loading @@ -43,4 +43,13 @@ class StickyKeysLogger @Inject constructor(@KeyboardLog private val buffer: LogB { "new sticky keys state received: $str1" } { "new sticky keys state received: $str1" } ) ) } } fun logNewSettingValue(enabled: Boolean) { buffer.log( TAG, LogLevel.INFO, { bool1 = enabled }, { "sticky key setting changed, new state: ${if (bool1) "enabled" else "disabled"}" } ) } } } packages/SystemUI/src/com/android/systemui/keyboard/stickykeys/data/repository/StickyKeysRepository.kt +34 −4 Original line number Original line Diff line number Diff line Loading @@ -19,8 +19,10 @@ package com.android.systemui.keyboard.stickykeys.data.repository import android.hardware.input.InputManager import android.hardware.input.InputManager import android.hardware.input.InputManager.StickyModifierStateListener import android.hardware.input.InputManager.StickyModifierStateListener import android.hardware.input.StickyModifierState import android.hardware.input.StickyModifierState import android.provider.Settings import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.keyboard.stickykeys.StickyKeysLogger import com.android.systemui.keyboard.stickykeys.StickyKeysLogger import com.android.systemui.keyboard.stickykeys.shared.model.Locked import com.android.systemui.keyboard.stickykeys.shared.model.Locked Loading @@ -30,14 +32,19 @@ import com.android.systemui.keyboard.stickykeys.shared.model.ModifierKey.ALT_GR import com.android.systemui.keyboard.stickykeys.shared.model.ModifierKey.CTRL import com.android.systemui.keyboard.stickykeys.shared.model.ModifierKey.CTRL import com.android.systemui.keyboard.stickykeys.shared.model.ModifierKey.META import com.android.systemui.keyboard.stickykeys.shared.model.ModifierKey.META import com.android.systemui.keyboard.stickykeys.shared.model.ModifierKey.SHIFT import com.android.systemui.keyboard.stickykeys.shared.model.ModifierKey.SHIFT import com.android.systemui.user.data.repository.UserRepository import com.android.systemui.util.settings.SecureSettings import com.android.systemui.util.settings.SettingsProxyExt.observerFlow import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.onStart import javax.inject.Inject import javax.inject.Inject interface StickyKeysRepository { interface StickyKeysRepository { Loading @@ -45,11 +52,15 @@ interface StickyKeysRepository { val settingEnabled: Flow<Boolean> val settingEnabled: Flow<Boolean> } } @SysUISingleton @OptIn(ExperimentalCoroutinesApi::class) class StickyKeysRepositoryImpl class StickyKeysRepositoryImpl @Inject @Inject constructor( constructor( private val inputManager: InputManager, private val inputManager: InputManager, @Background private val backgroundDispatcher: CoroutineDispatcher, @Background private val backgroundDispatcher: CoroutineDispatcher, private val secureSettings: SecureSettings, userRepository: UserRepository, private val stickyKeysLogger: StickyKeysLogger, private val stickyKeysLogger: StickyKeysLogger, ) : StickyKeysRepository { ) : StickyKeysRepository { Loading @@ -66,8 +77,26 @@ constructor( .onEach { stickyKeysLogger.logNewStickyKeysReceived(it) } .onEach { stickyKeysLogger.logNewStickyKeysReceived(it) } .flowOn(backgroundDispatcher) .flowOn(backgroundDispatcher) // TODO(b/319837892): Implement reading actual setting override val settingEnabled: Flow<Boolean> = override val settingEnabled: StateFlow<Boolean> = MutableStateFlow(true) userRepository.selectedUserInfo .flatMapLatest { stickyKeySettingObserver(it.id) } .flowOn(backgroundDispatcher) private fun stickyKeySettingObserver(userId: Int): Flow<Boolean> { return secureSettings .observerFlow(userId, SETTING_KEY) .onStart { emit(Unit) } .map { isSettingEnabledForCurrentUser(userId) } .distinctUntilChanged() .onEach { stickyKeysLogger.logNewSettingValue(it) } } private fun isSettingEnabledForCurrentUser(userId: Int) = secureSettings.getIntForUser( /* name= */ SETTING_KEY, /* default= */ 0, /* userHandle= */ userId ) != 0 private fun toStickyKeysMap(state: StickyModifierState): LinkedHashMap<ModifierKey, Locked> { private fun toStickyKeysMap(state: StickyModifierState): LinkedHashMap<ModifierKey, Locked> { val keys = linkedMapOf<ModifierKey, Locked>() val keys = linkedMapOf<ModifierKey, Locked>() Loading @@ -88,5 +117,6 @@ constructor( companion object { companion object { const val TAG = "StickyKeysRepositoryImpl" const val TAG = "StickyKeysRepositoryImpl" const val SETTING_KEY = Settings.Secure.ACCESSIBILITY_STICKY_KEYS } } } } packages/SystemUI/tests/src/com/android/systemui/keyboard/stickykeys/data/repository/StickyKeysRepositoryImplTest.kt 0 → 100644 +98 −0 Original line number Original line Diff line number Diff line package com.android.systemui.keyboard.stickykeys.data.repository import android.content.pm.UserInfo import android.hardware.input.InputManager import android.provider.Settings.Secure.ACCESSIBILITY_STICKY_KEYS import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.coroutines.collectLastValue import com.android.systemui.coroutines.collectValues import com.android.systemui.keyboard.stickykeys.StickyKeysLogger import com.android.systemui.kosmos.Kosmos import com.android.systemui.user.data.repository.fakeUserRepository import com.android.systemui.util.mockito.mock import com.android.systemui.util.settings.FakeSettings import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.StandardTestDispatcher import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.runCurrent import kotlinx.coroutines.test.runTest 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 StickyKeysRepositoryImplTest : SysuiTestCase() { private val dispatcher = StandardTestDispatcher() private val testScope = TestScope(dispatcher) private val secureSettings = FakeSettings() private val userRepository = Kosmos().fakeUserRepository private lateinit var stickyKeysRepository: StickyKeysRepositoryImpl @Before fun setup() { stickyKeysRepository = StickyKeysRepositoryImpl( mock<InputManager>(), dispatcher, secureSettings, userRepository, mock<StickyKeysLogger>() ) userRepository.setUserInfos(USER_INFOS) setStickyKeySettingForUser(enabled = true, userInfo = SETTING_ENABLED_USER) setStickyKeySettingForUser(enabled = false, userInfo = SETTING_DISABLED_USER) } @Test fun settingEnabledEmitsValueForCurrentUser() { testScope.runTest { userRepository.setSelectedUserInfo(SETTING_ENABLED_USER) val enabled by collectLastValue(stickyKeysRepository.settingEnabled) assertThat(enabled).isTrue() } } @Test fun settingEnabledEmitsNewValueWhenSettingChanges() { testScope.runTest { userRepository.setSelectedUserInfo(SETTING_ENABLED_USER) val enabled by collectValues(stickyKeysRepository.settingEnabled) runCurrent() setStickyKeySettingForUser(enabled = false, userInfo = SETTING_ENABLED_USER) assertThat(enabled).containsExactly(true, false).inOrder() } } @Test fun settingEnabledEmitsValueForNewUserWhenUserChanges() { testScope.runTest { userRepository.setSelectedUserInfo(SETTING_ENABLED_USER) val enabled by collectLastValue(stickyKeysRepository.settingEnabled) runCurrent() userRepository.setSelectedUserInfo(SETTING_DISABLED_USER) assertThat(enabled).isFalse() } } private fun setStickyKeySettingForUser(enabled: Boolean, userInfo: UserInfo) { val newValue = if (enabled) "1" else "0" secureSettings.putStringForUser(ACCESSIBILITY_STICKY_KEYS, newValue, userInfo.id) } private companion object { val SETTING_ENABLED_USER = UserInfo(/* id= */ 0, "user1", /* flags= */ 0) val SETTING_DISABLED_USER = UserInfo(/* id= */ 1, "user2", /* flags= */ 0) val USER_INFOS = listOf(SETTING_ENABLED_USER, SETTING_DISABLED_USER) } } No newline at end of file packages/SystemUI/tests/src/com/android/systemui/keyboard/stickykeys/ui/viewmodel/StickyKeysIndicatorViewModelTest.kt +52 −7 Original line number Original line Diff line number Diff line Loading @@ -18,6 +18,7 @@ package com.android.systemui.keyboard.stickykeys.ui.viewmodel import android.hardware.input.InputManager import android.hardware.input.InputManager import android.hardware.input.StickyModifierState import android.hardware.input.StickyModifierState import android.provider.Settings.Secure.ACCESSIBILITY_STICKY_KEYS import androidx.test.filters.SmallTest import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.SysuiTestCase import com.android.systemui.coroutines.collectLastValue import com.android.systemui.coroutines.collectLastValue Loading @@ -31,8 +32,11 @@ import com.android.systemui.keyboard.stickykeys.shared.model.ModifierKey.ALT_GR import com.android.systemui.keyboard.stickykeys.shared.model.ModifierKey.CTRL import com.android.systemui.keyboard.stickykeys.shared.model.ModifierKey.CTRL import com.android.systemui.keyboard.stickykeys.shared.model.ModifierKey.META import com.android.systemui.keyboard.stickykeys.shared.model.ModifierKey.META import com.android.systemui.keyboard.stickykeys.shared.model.ModifierKey.SHIFT import com.android.systemui.keyboard.stickykeys.shared.model.ModifierKey.SHIFT import com.android.systemui.kosmos.Kosmos import com.android.systemui.user.data.repository.fakeUserRepository import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.mock import com.android.systemui.util.mockito.mock import com.android.systemui.util.settings.FakeSettings import com.google.common.truth.Truth.assertThat import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.StandardTestDispatcher import kotlinx.coroutines.test.StandardTestDispatcher Loading @@ -57,6 +61,8 @@ class StickyKeysIndicatorViewModelTest : SysuiTestCase() { private lateinit var viewModel: StickyKeysIndicatorViewModel private lateinit var viewModel: StickyKeysIndicatorViewModel private val inputManager = mock<InputManager>() private val inputManager = mock<InputManager>() private val keyboardRepository = FakeKeyboardRepository() private val keyboardRepository = FakeKeyboardRepository() private val secureSettings = FakeSettings() private val userRepository = Kosmos().fakeUserRepository private val captor = private val captor = ArgumentCaptor.forClass(InputManager.StickyModifierStateListener::class.java) ArgumentCaptor.forClass(InputManager.StickyModifierStateListener::class.java) Loading @@ -65,8 +71,11 @@ class StickyKeysIndicatorViewModelTest : SysuiTestCase() { val stickyKeysRepository = StickyKeysRepositoryImpl( val stickyKeysRepository = StickyKeysRepositoryImpl( inputManager, inputManager, dispatcher, dispatcher, secureSettings, userRepository, mock<StickyKeysLogger>() mock<StickyKeysLogger>() ) ) setStickyKeySetting(enabled = false) viewModel = viewModel = StickyKeysIndicatorViewModel( StickyKeysIndicatorViewModel( stickyKeysRepository = stickyKeysRepository, stickyKeysRepository = stickyKeysRepository, Loading @@ -76,13 +85,24 @@ class StickyKeysIndicatorViewModelTest : SysuiTestCase() { } } @Test @Test fun startsListeningToStickyKeysOnlyWhenKeyboardIsConnected() { fun doesntListenToStickyKeysOnlyWhenKeyboardIsConnected() { testScope.runTest { testScope.runTest { collectLastValue(viewModel.indicatorContent) collectLastValue(viewModel.indicatorContent) keyboardRepository.setIsAnyKeyboardConnected(true) runCurrent() runCurrent() verifyZeroInteractions(inputManager) verifyZeroInteractions(inputManager) } } @Test fun startsListeningToStickyKeysOnlyWhenKeyboardIsConnectedAndSettingIsOn() { testScope.runTest { collectLastValue(viewModel.indicatorContent) keyboardRepository.setIsAnyKeyboardConnected(true) keyboardRepository.setIsAnyKeyboardConnected(true) setStickyKeySetting(enabled = true) runCurrent() runCurrent() verify(inputManager) verify(inputManager) Loading @@ -93,11 +113,31 @@ class StickyKeysIndicatorViewModelTest : SysuiTestCase() { } } } } private fun setStickyKeySetting(enabled: Boolean) { val newValue = if (enabled) "1" else "0" val defaultUser = userRepository.getSelectedUserInfo().id secureSettings.putStringForUser(ACCESSIBILITY_STICKY_KEYS, newValue, defaultUser) } @Test fun stopsListeningToStickyKeysWhenStickyKeySettingsIsTurnedOff() { testScope.runTest { collectLastValue(viewModel.indicatorContent) setStickyKeysActive() runCurrent() setStickyKeySetting(enabled = false) runCurrent() verify(inputManager).unregisterStickyModifierStateListener(any()) } } @Test @Test fun stopsListeningToStickyKeysWhenKeyboardDisconnects() { fun stopsListeningToStickyKeysWhenKeyboardDisconnects() { testScope.runTest { testScope.runTest { collectLastValue(viewModel.indicatorContent) collectLastValue(viewModel.indicatorContent) keyboardRepository.setIsAnyKeyboardConnected(true) setStickyKeysActive() runCurrent() runCurrent() keyboardRepository.setIsAnyKeyboardConnected(false) keyboardRepository.setIsAnyKeyboardConnected(false) Loading @@ -111,7 +151,7 @@ class StickyKeysIndicatorViewModelTest : SysuiTestCase() { fun emitsStickyKeysListWhenStickyKeyIsPressed() { fun emitsStickyKeysListWhenStickyKeyIsPressed() { testScope.runTest { testScope.runTest { val stickyKeys by collectLastValue(viewModel.indicatorContent) val stickyKeys by collectLastValue(viewModel.indicatorContent) keyboardRepository.setIsAnyKeyboardConnected(true) setStickyKeysActive() setStickyKeys(mapOf(ALT to false)) setStickyKeys(mapOf(ALT to false)) Loading @@ -123,7 +163,7 @@ class StickyKeysIndicatorViewModelTest : SysuiTestCase() { fun emitsEmptyListWhenNoStickyKeysAreActive() { fun emitsEmptyListWhenNoStickyKeysAreActive() { testScope.runTest { testScope.runTest { val stickyKeys by collectLastValue(viewModel.indicatorContent) val stickyKeys by collectLastValue(viewModel.indicatorContent) keyboardRepository.setIsAnyKeyboardConnected(true) setStickyKeysActive() setStickyKeys(emptyMap()) setStickyKeys(emptyMap()) Loading @@ -135,7 +175,7 @@ class StickyKeysIndicatorViewModelTest : SysuiTestCase() { fun passesAllStickyKeysToDialog() { fun passesAllStickyKeysToDialog() { testScope.runTest { testScope.runTest { val stickyKeys by collectLastValue(viewModel.indicatorContent) val stickyKeys by collectLastValue(viewModel.indicatorContent) keyboardRepository.setIsAnyKeyboardConnected(true) setStickyKeysActive() setStickyKeys(mapOf( setStickyKeys(mapOf( ALT to false, ALT to false, Loading @@ -154,7 +194,7 @@ class StickyKeysIndicatorViewModelTest : SysuiTestCase() { fun showsOnlyLockedStateIfKeyIsStickyAndLocked() { fun showsOnlyLockedStateIfKeyIsStickyAndLocked() { testScope.runTest { testScope.runTest { val stickyKeys by collectLastValue(viewModel.indicatorContent) val stickyKeys by collectLastValue(viewModel.indicatorContent) keyboardRepository.setIsAnyKeyboardConnected(true) setStickyKeysActive() setStickyKeys(mapOf( setStickyKeys(mapOf( ALT to false, ALT to false, Loading @@ -168,7 +208,7 @@ class StickyKeysIndicatorViewModelTest : SysuiTestCase() { fun doesNotChangeOrderOfKeysIfTheyBecomeLocked() { fun doesNotChangeOrderOfKeysIfTheyBecomeLocked() { testScope.runTest { testScope.runTest { val stickyKeys by collectLastValue(viewModel.indicatorContent) val stickyKeys by collectLastValue(viewModel.indicatorContent) keyboardRepository.setIsAnyKeyboardConnected(true) setStickyKeysActive() setStickyKeys(mapOf( setStickyKeys(mapOf( META to false, META to false, Loading @@ -186,6 +226,11 @@ class StickyKeysIndicatorViewModelTest : SysuiTestCase() { } } } } private fun setStickyKeysActive() { keyboardRepository.setIsAnyKeyboardConnected(true) setStickyKeySetting(enabled = true) } private fun TestScope.setStickyKeys(keys: Map<ModifierKey, Boolean>) { private fun TestScope.setStickyKeys(keys: Map<ModifierKey, Boolean>) { runCurrent() runCurrent() verify(inputManager).registerStickyModifierStateListener(any(), captor.capture()) verify(inputManager).registerStickyModifierStateListener(any(), captor.capture()) Loading Loading
packages/SystemUI/src/com/android/systemui/keyboard/stickykeys/StickyKeysLogger.kt +10 −1 Original line number Original line Diff line number Diff line Loading @@ -43,4 +43,13 @@ class StickyKeysLogger @Inject constructor(@KeyboardLog private val buffer: LogB { "new sticky keys state received: $str1" } { "new sticky keys state received: $str1" } ) ) } } fun logNewSettingValue(enabled: Boolean) { buffer.log( TAG, LogLevel.INFO, { bool1 = enabled }, { "sticky key setting changed, new state: ${if (bool1) "enabled" else "disabled"}" } ) } } }
packages/SystemUI/src/com/android/systemui/keyboard/stickykeys/data/repository/StickyKeysRepository.kt +34 −4 Original line number Original line Diff line number Diff line Loading @@ -19,8 +19,10 @@ package com.android.systemui.keyboard.stickykeys.data.repository import android.hardware.input.InputManager import android.hardware.input.InputManager import android.hardware.input.InputManager.StickyModifierStateListener import android.hardware.input.InputManager.StickyModifierStateListener import android.hardware.input.StickyModifierState import android.hardware.input.StickyModifierState import android.provider.Settings import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.keyboard.stickykeys.StickyKeysLogger import com.android.systemui.keyboard.stickykeys.StickyKeysLogger import com.android.systemui.keyboard.stickykeys.shared.model.Locked import com.android.systemui.keyboard.stickykeys.shared.model.Locked Loading @@ -30,14 +32,19 @@ import com.android.systemui.keyboard.stickykeys.shared.model.ModifierKey.ALT_GR import com.android.systemui.keyboard.stickykeys.shared.model.ModifierKey.CTRL import com.android.systemui.keyboard.stickykeys.shared.model.ModifierKey.CTRL import com.android.systemui.keyboard.stickykeys.shared.model.ModifierKey.META import com.android.systemui.keyboard.stickykeys.shared.model.ModifierKey.META import com.android.systemui.keyboard.stickykeys.shared.model.ModifierKey.SHIFT import com.android.systemui.keyboard.stickykeys.shared.model.ModifierKey.SHIFT import com.android.systemui.user.data.repository.UserRepository import com.android.systemui.util.settings.SecureSettings import com.android.systemui.util.settings.SettingsProxyExt.observerFlow import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.onStart import javax.inject.Inject import javax.inject.Inject interface StickyKeysRepository { interface StickyKeysRepository { Loading @@ -45,11 +52,15 @@ interface StickyKeysRepository { val settingEnabled: Flow<Boolean> val settingEnabled: Flow<Boolean> } } @SysUISingleton @OptIn(ExperimentalCoroutinesApi::class) class StickyKeysRepositoryImpl class StickyKeysRepositoryImpl @Inject @Inject constructor( constructor( private val inputManager: InputManager, private val inputManager: InputManager, @Background private val backgroundDispatcher: CoroutineDispatcher, @Background private val backgroundDispatcher: CoroutineDispatcher, private val secureSettings: SecureSettings, userRepository: UserRepository, private val stickyKeysLogger: StickyKeysLogger, private val stickyKeysLogger: StickyKeysLogger, ) : StickyKeysRepository { ) : StickyKeysRepository { Loading @@ -66,8 +77,26 @@ constructor( .onEach { stickyKeysLogger.logNewStickyKeysReceived(it) } .onEach { stickyKeysLogger.logNewStickyKeysReceived(it) } .flowOn(backgroundDispatcher) .flowOn(backgroundDispatcher) // TODO(b/319837892): Implement reading actual setting override val settingEnabled: Flow<Boolean> = override val settingEnabled: StateFlow<Boolean> = MutableStateFlow(true) userRepository.selectedUserInfo .flatMapLatest { stickyKeySettingObserver(it.id) } .flowOn(backgroundDispatcher) private fun stickyKeySettingObserver(userId: Int): Flow<Boolean> { return secureSettings .observerFlow(userId, SETTING_KEY) .onStart { emit(Unit) } .map { isSettingEnabledForCurrentUser(userId) } .distinctUntilChanged() .onEach { stickyKeysLogger.logNewSettingValue(it) } } private fun isSettingEnabledForCurrentUser(userId: Int) = secureSettings.getIntForUser( /* name= */ SETTING_KEY, /* default= */ 0, /* userHandle= */ userId ) != 0 private fun toStickyKeysMap(state: StickyModifierState): LinkedHashMap<ModifierKey, Locked> { private fun toStickyKeysMap(state: StickyModifierState): LinkedHashMap<ModifierKey, Locked> { val keys = linkedMapOf<ModifierKey, Locked>() val keys = linkedMapOf<ModifierKey, Locked>() Loading @@ -88,5 +117,6 @@ constructor( companion object { companion object { const val TAG = "StickyKeysRepositoryImpl" const val TAG = "StickyKeysRepositoryImpl" const val SETTING_KEY = Settings.Secure.ACCESSIBILITY_STICKY_KEYS } } } }
packages/SystemUI/tests/src/com/android/systemui/keyboard/stickykeys/data/repository/StickyKeysRepositoryImplTest.kt 0 → 100644 +98 −0 Original line number Original line Diff line number Diff line package com.android.systemui.keyboard.stickykeys.data.repository import android.content.pm.UserInfo import android.hardware.input.InputManager import android.provider.Settings.Secure.ACCESSIBILITY_STICKY_KEYS import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.coroutines.collectLastValue import com.android.systemui.coroutines.collectValues import com.android.systemui.keyboard.stickykeys.StickyKeysLogger import com.android.systemui.kosmos.Kosmos import com.android.systemui.user.data.repository.fakeUserRepository import com.android.systemui.util.mockito.mock import com.android.systemui.util.settings.FakeSettings import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.StandardTestDispatcher import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.runCurrent import kotlinx.coroutines.test.runTest 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 StickyKeysRepositoryImplTest : SysuiTestCase() { private val dispatcher = StandardTestDispatcher() private val testScope = TestScope(dispatcher) private val secureSettings = FakeSettings() private val userRepository = Kosmos().fakeUserRepository private lateinit var stickyKeysRepository: StickyKeysRepositoryImpl @Before fun setup() { stickyKeysRepository = StickyKeysRepositoryImpl( mock<InputManager>(), dispatcher, secureSettings, userRepository, mock<StickyKeysLogger>() ) userRepository.setUserInfos(USER_INFOS) setStickyKeySettingForUser(enabled = true, userInfo = SETTING_ENABLED_USER) setStickyKeySettingForUser(enabled = false, userInfo = SETTING_DISABLED_USER) } @Test fun settingEnabledEmitsValueForCurrentUser() { testScope.runTest { userRepository.setSelectedUserInfo(SETTING_ENABLED_USER) val enabled by collectLastValue(stickyKeysRepository.settingEnabled) assertThat(enabled).isTrue() } } @Test fun settingEnabledEmitsNewValueWhenSettingChanges() { testScope.runTest { userRepository.setSelectedUserInfo(SETTING_ENABLED_USER) val enabled by collectValues(stickyKeysRepository.settingEnabled) runCurrent() setStickyKeySettingForUser(enabled = false, userInfo = SETTING_ENABLED_USER) assertThat(enabled).containsExactly(true, false).inOrder() } } @Test fun settingEnabledEmitsValueForNewUserWhenUserChanges() { testScope.runTest { userRepository.setSelectedUserInfo(SETTING_ENABLED_USER) val enabled by collectLastValue(stickyKeysRepository.settingEnabled) runCurrent() userRepository.setSelectedUserInfo(SETTING_DISABLED_USER) assertThat(enabled).isFalse() } } private fun setStickyKeySettingForUser(enabled: Boolean, userInfo: UserInfo) { val newValue = if (enabled) "1" else "0" secureSettings.putStringForUser(ACCESSIBILITY_STICKY_KEYS, newValue, userInfo.id) } private companion object { val SETTING_ENABLED_USER = UserInfo(/* id= */ 0, "user1", /* flags= */ 0) val SETTING_DISABLED_USER = UserInfo(/* id= */ 1, "user2", /* flags= */ 0) val USER_INFOS = listOf(SETTING_ENABLED_USER, SETTING_DISABLED_USER) } } No newline at end of file
packages/SystemUI/tests/src/com/android/systemui/keyboard/stickykeys/ui/viewmodel/StickyKeysIndicatorViewModelTest.kt +52 −7 Original line number Original line Diff line number Diff line Loading @@ -18,6 +18,7 @@ package com.android.systemui.keyboard.stickykeys.ui.viewmodel import android.hardware.input.InputManager import android.hardware.input.InputManager import android.hardware.input.StickyModifierState import android.hardware.input.StickyModifierState import android.provider.Settings.Secure.ACCESSIBILITY_STICKY_KEYS import androidx.test.filters.SmallTest import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.SysuiTestCase import com.android.systemui.coroutines.collectLastValue import com.android.systemui.coroutines.collectLastValue Loading @@ -31,8 +32,11 @@ import com.android.systemui.keyboard.stickykeys.shared.model.ModifierKey.ALT_GR import com.android.systemui.keyboard.stickykeys.shared.model.ModifierKey.CTRL import com.android.systemui.keyboard.stickykeys.shared.model.ModifierKey.CTRL import com.android.systemui.keyboard.stickykeys.shared.model.ModifierKey.META import com.android.systemui.keyboard.stickykeys.shared.model.ModifierKey.META import com.android.systemui.keyboard.stickykeys.shared.model.ModifierKey.SHIFT import com.android.systemui.keyboard.stickykeys.shared.model.ModifierKey.SHIFT import com.android.systemui.kosmos.Kosmos import com.android.systemui.user.data.repository.fakeUserRepository import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.mock import com.android.systemui.util.mockito.mock import com.android.systemui.util.settings.FakeSettings import com.google.common.truth.Truth.assertThat import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.StandardTestDispatcher import kotlinx.coroutines.test.StandardTestDispatcher Loading @@ -57,6 +61,8 @@ class StickyKeysIndicatorViewModelTest : SysuiTestCase() { private lateinit var viewModel: StickyKeysIndicatorViewModel private lateinit var viewModel: StickyKeysIndicatorViewModel private val inputManager = mock<InputManager>() private val inputManager = mock<InputManager>() private val keyboardRepository = FakeKeyboardRepository() private val keyboardRepository = FakeKeyboardRepository() private val secureSettings = FakeSettings() private val userRepository = Kosmos().fakeUserRepository private val captor = private val captor = ArgumentCaptor.forClass(InputManager.StickyModifierStateListener::class.java) ArgumentCaptor.forClass(InputManager.StickyModifierStateListener::class.java) Loading @@ -65,8 +71,11 @@ class StickyKeysIndicatorViewModelTest : SysuiTestCase() { val stickyKeysRepository = StickyKeysRepositoryImpl( val stickyKeysRepository = StickyKeysRepositoryImpl( inputManager, inputManager, dispatcher, dispatcher, secureSettings, userRepository, mock<StickyKeysLogger>() mock<StickyKeysLogger>() ) ) setStickyKeySetting(enabled = false) viewModel = viewModel = StickyKeysIndicatorViewModel( StickyKeysIndicatorViewModel( stickyKeysRepository = stickyKeysRepository, stickyKeysRepository = stickyKeysRepository, Loading @@ -76,13 +85,24 @@ class StickyKeysIndicatorViewModelTest : SysuiTestCase() { } } @Test @Test fun startsListeningToStickyKeysOnlyWhenKeyboardIsConnected() { fun doesntListenToStickyKeysOnlyWhenKeyboardIsConnected() { testScope.runTest { testScope.runTest { collectLastValue(viewModel.indicatorContent) collectLastValue(viewModel.indicatorContent) keyboardRepository.setIsAnyKeyboardConnected(true) runCurrent() runCurrent() verifyZeroInteractions(inputManager) verifyZeroInteractions(inputManager) } } @Test fun startsListeningToStickyKeysOnlyWhenKeyboardIsConnectedAndSettingIsOn() { testScope.runTest { collectLastValue(viewModel.indicatorContent) keyboardRepository.setIsAnyKeyboardConnected(true) keyboardRepository.setIsAnyKeyboardConnected(true) setStickyKeySetting(enabled = true) runCurrent() runCurrent() verify(inputManager) verify(inputManager) Loading @@ -93,11 +113,31 @@ class StickyKeysIndicatorViewModelTest : SysuiTestCase() { } } } } private fun setStickyKeySetting(enabled: Boolean) { val newValue = if (enabled) "1" else "0" val defaultUser = userRepository.getSelectedUserInfo().id secureSettings.putStringForUser(ACCESSIBILITY_STICKY_KEYS, newValue, defaultUser) } @Test fun stopsListeningToStickyKeysWhenStickyKeySettingsIsTurnedOff() { testScope.runTest { collectLastValue(viewModel.indicatorContent) setStickyKeysActive() runCurrent() setStickyKeySetting(enabled = false) runCurrent() verify(inputManager).unregisterStickyModifierStateListener(any()) } } @Test @Test fun stopsListeningToStickyKeysWhenKeyboardDisconnects() { fun stopsListeningToStickyKeysWhenKeyboardDisconnects() { testScope.runTest { testScope.runTest { collectLastValue(viewModel.indicatorContent) collectLastValue(viewModel.indicatorContent) keyboardRepository.setIsAnyKeyboardConnected(true) setStickyKeysActive() runCurrent() runCurrent() keyboardRepository.setIsAnyKeyboardConnected(false) keyboardRepository.setIsAnyKeyboardConnected(false) Loading @@ -111,7 +151,7 @@ class StickyKeysIndicatorViewModelTest : SysuiTestCase() { fun emitsStickyKeysListWhenStickyKeyIsPressed() { fun emitsStickyKeysListWhenStickyKeyIsPressed() { testScope.runTest { testScope.runTest { val stickyKeys by collectLastValue(viewModel.indicatorContent) val stickyKeys by collectLastValue(viewModel.indicatorContent) keyboardRepository.setIsAnyKeyboardConnected(true) setStickyKeysActive() setStickyKeys(mapOf(ALT to false)) setStickyKeys(mapOf(ALT to false)) Loading @@ -123,7 +163,7 @@ class StickyKeysIndicatorViewModelTest : SysuiTestCase() { fun emitsEmptyListWhenNoStickyKeysAreActive() { fun emitsEmptyListWhenNoStickyKeysAreActive() { testScope.runTest { testScope.runTest { val stickyKeys by collectLastValue(viewModel.indicatorContent) val stickyKeys by collectLastValue(viewModel.indicatorContent) keyboardRepository.setIsAnyKeyboardConnected(true) setStickyKeysActive() setStickyKeys(emptyMap()) setStickyKeys(emptyMap()) Loading @@ -135,7 +175,7 @@ class StickyKeysIndicatorViewModelTest : SysuiTestCase() { fun passesAllStickyKeysToDialog() { fun passesAllStickyKeysToDialog() { testScope.runTest { testScope.runTest { val stickyKeys by collectLastValue(viewModel.indicatorContent) val stickyKeys by collectLastValue(viewModel.indicatorContent) keyboardRepository.setIsAnyKeyboardConnected(true) setStickyKeysActive() setStickyKeys(mapOf( setStickyKeys(mapOf( ALT to false, ALT to false, Loading @@ -154,7 +194,7 @@ class StickyKeysIndicatorViewModelTest : SysuiTestCase() { fun showsOnlyLockedStateIfKeyIsStickyAndLocked() { fun showsOnlyLockedStateIfKeyIsStickyAndLocked() { testScope.runTest { testScope.runTest { val stickyKeys by collectLastValue(viewModel.indicatorContent) val stickyKeys by collectLastValue(viewModel.indicatorContent) keyboardRepository.setIsAnyKeyboardConnected(true) setStickyKeysActive() setStickyKeys(mapOf( setStickyKeys(mapOf( ALT to false, ALT to false, Loading @@ -168,7 +208,7 @@ class StickyKeysIndicatorViewModelTest : SysuiTestCase() { fun doesNotChangeOrderOfKeysIfTheyBecomeLocked() { fun doesNotChangeOrderOfKeysIfTheyBecomeLocked() { testScope.runTest { testScope.runTest { val stickyKeys by collectLastValue(viewModel.indicatorContent) val stickyKeys by collectLastValue(viewModel.indicatorContent) keyboardRepository.setIsAnyKeyboardConnected(true) setStickyKeysActive() setStickyKeys(mapOf( setStickyKeys(mapOf( META to false, META to false, Loading @@ -186,6 +226,11 @@ class StickyKeysIndicatorViewModelTest : SysuiTestCase() { } } } } private fun setStickyKeysActive() { keyboardRepository.setIsAnyKeyboardConnected(true) setStickyKeySetting(enabled = true) } private fun TestScope.setStickyKeys(keys: Map<ModifierKey, Boolean>) { private fun TestScope.setStickyKeys(keys: Map<ModifierKey, Boolean>) { runCurrent() runCurrent() verify(inputManager).registerStickyModifierStateListener(any(), captor.capture()) verify(inputManager).registerStickyModifierStateListener(any(), captor.capture()) Loading