1 /*
<lambda>null2  * Copyright (C) 2024 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 package com.android.systemui.keyboard.stickykeys.data.repository
18 
19 import android.hardware.input.InputManager
20 import android.hardware.input.InputManager.StickyModifierStateListener
21 import android.hardware.input.StickyModifierState
22 import android.provider.Settings
23 import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging
24 import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
25 import com.android.systemui.dagger.SysUISingleton
26 import com.android.systemui.dagger.qualifiers.Background
27 import com.android.systemui.keyboard.stickykeys.StickyKeysLogger
28 import com.android.systemui.keyboard.stickykeys.shared.model.Locked
29 import com.android.systemui.keyboard.stickykeys.shared.model.ModifierKey
30 import com.android.systemui.keyboard.stickykeys.shared.model.ModifierKey.ALT
31 import com.android.systemui.keyboard.stickykeys.shared.model.ModifierKey.ALT_GR
32 import com.android.systemui.keyboard.stickykeys.shared.model.ModifierKey.CTRL
33 import com.android.systemui.keyboard.stickykeys.shared.model.ModifierKey.META
34 import com.android.systemui.keyboard.stickykeys.shared.model.ModifierKey.SHIFT
35 import com.android.systemui.util.settings.repository.UserAwareSecureSettingsRepository
36 import javax.inject.Inject
37 import kotlinx.coroutines.CoroutineDispatcher
38 import kotlinx.coroutines.channels.awaitClose
39 import kotlinx.coroutines.flow.Flow
40 import kotlinx.coroutines.flow.flowOn
41 import kotlinx.coroutines.flow.map
42 import kotlinx.coroutines.flow.onEach
43 
44 interface StickyKeysRepository {
45     val stickyKeys: Flow<LinkedHashMap<ModifierKey, Locked>>
46     val settingEnabled: Flow<Boolean>
47 }
48 
49 @SysUISingleton
50 class StickyKeysRepositoryImpl
51 @Inject
52 constructor(
53     private val inputManager: InputManager,
54     @Background private val backgroundDispatcher: CoroutineDispatcher,
55     // TODO: b/377244768 - Change to inject SecureSettingsRepository
56     secureSettingsRepository: UserAwareSecureSettingsRepository,
57     private val stickyKeysLogger: StickyKeysLogger,
58 ) : StickyKeysRepository {
59 
60     override val stickyKeys: Flow<LinkedHashMap<ModifierKey, Locked>> =
<lambda>null61         conflatedCallbackFlow {
62                 val listener = StickyModifierStateListener { stickyModifierState ->
63                     trySendWithFailureLogging(stickyModifierState, TAG)
64                 }
65                 // after registering, InputManager calls listener with the current value
66                 inputManager.registerStickyModifierStateListener(Runnable::run, listener)
67                 awaitClose { inputManager.unregisterStickyModifierStateListener(listener) }
68             }
<lambda>null69             .map { toStickyKeysMap(it) }
<lambda>null70             .onEach { stickyKeysLogger.logNewStickyKeysReceived(it) }
71             .flowOn(backgroundDispatcher)
72 
73     override val settingEnabled: Flow<Boolean> =
74         secureSettingsRepository
75             .boolSetting(SETTING_KEY, defaultValue = false)
<lambda>null76             .onEach { stickyKeysLogger.logNewSettingValue(it) }
77             .flowOn(backgroundDispatcher)
78 
toStickyKeysMapnull79     private fun toStickyKeysMap(state: StickyModifierState): LinkedHashMap<ModifierKey, Locked> {
80         val keys = linkedMapOf<ModifierKey, Locked>()
81         state.apply {
82             if (isAltGrModifierOn) keys[ALT_GR] = Locked(false)
83             if (isAltGrModifierLocked) keys[ALT_GR] = Locked(true)
84             if (isAltModifierOn) keys[ALT] = Locked(false)
85             if (isAltModifierLocked) keys[ALT] = Locked(true)
86             if (isCtrlModifierOn) keys[CTRL] = Locked(false)
87             if (isCtrlModifierLocked) keys[CTRL] = Locked(true)
88             if (isMetaModifierOn) keys[META] = Locked(false)
89             if (isMetaModifierLocked) keys[META] = Locked(true)
90             if (isShiftModifierOn) keys[SHIFT] = Locked(false)
91             if (isShiftModifierLocked) keys[SHIFT] = Locked(true)
92         }
93         return keys
94     }
95 
96     companion object {
97         const val TAG = "StickyKeysRepositoryImpl"
98         const val SETTING_KEY = Settings.Secure.ACCESSIBILITY_STICKY_KEYS
99     }
100 }
101