• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * 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.shortcut.data.repository
18 
19 import android.content.Context
20 import android.content.Context.INPUT_SERVICE
21 import android.hardware.input.InputGestureData
22 import android.hardware.input.InputManager
23 import android.hardware.input.InputManager.CUSTOM_INPUT_GESTURE_RESULT_ERROR_ALREADY_EXISTS
24 import android.hardware.input.InputManager.CUSTOM_INPUT_GESTURE_RESULT_ERROR_RESERVED_GESTURE
25 import android.hardware.input.InputManager.CUSTOM_INPUT_GESTURE_RESULT_SUCCESS
26 import android.hardware.input.InputSettings
27 import android.util.Log
28 import com.android.systemui.dagger.SysUISingleton
29 import com.android.systemui.dagger.qualifiers.Background
30 import com.android.systemui.keyboard.shared.model.ShortcutCustomizationRequestResult
31 import com.android.systemui.keyboard.shared.model.ShortcutCustomizationRequestResult.ERROR_OTHER
32 import com.android.systemui.keyboard.shared.model.ShortcutCustomizationRequestResult.ERROR_RESERVED_COMBINATION
33 import com.android.systemui.keyboard.shared.model.ShortcutCustomizationRequestResult.SUCCESS
34 import com.android.systemui.settings.UserTracker
35 import javax.inject.Inject
36 import kotlin.coroutines.CoroutineContext
37 import kotlinx.coroutines.flow.MutableStateFlow
38 import kotlinx.coroutines.flow.onStart
39 import kotlinx.coroutines.withContext
40 
41 @SysUISingleton
42 class CustomInputGesturesRepository
43 @Inject
44 constructor(
45     private val userTracker: UserTracker,
46     @Background private val bgCoroutineContext: CoroutineContext,
47 ) {
48 
49     private val userContext: Context
50         get() = userTracker.createCurrentUserContext(userTracker.userContext)
51 
52     // Input manager created with user context to provide correct user id when requesting custom
53     // shortcut
54     private val inputManager: InputManager
55         get() = userContext.getSystemService(INPUT_SERVICE) as InputManager
56 
57     private val _customInputGesture = MutableStateFlow<List<InputGestureData>>(emptyList())
58 
<lambda>null59     val customInputGestures = _customInputGesture.onStart { refreshCustomInputGestures() }
60 
refreshCustomInputGesturesnull61     fun refreshCustomInputGestures() {
62         setCustomInputGestures(inputGestures = retrieveCustomInputGestures())
63     }
64 
setCustomInputGesturesnull65     private fun setCustomInputGestures(inputGestures: List<InputGestureData>) {
66         _customInputGesture.value = inputGestures
67     }
68 
retrieveCustomInputGesturesnull69     fun retrieveCustomInputGestures(): List<InputGestureData> {
70         return if (InputSettings.isCustomizableInputGesturesFeatureFlagEnabled()) {
71             inputManager.getCustomInputGestures(/* filter= */ InputGestureData.Filter.KEY)
72         } else emptyList()
73     }
74 
addCustomInputGesturenull75     suspend fun addCustomInputGesture(
76         inputGesture: InputGestureData
77     ): ShortcutCustomizationRequestResult {
78         return withContext(bgCoroutineContext) {
79             when (val result = inputManager.addCustomInputGesture(inputGesture)) {
80                 CUSTOM_INPUT_GESTURE_RESULT_SUCCESS -> {
81                     refreshCustomInputGestures()
82                     SUCCESS
83                 }
84                 CUSTOM_INPUT_GESTURE_RESULT_ERROR_ALREADY_EXISTS -> ERROR_RESERVED_COMBINATION
85 
86                 CUSTOM_INPUT_GESTURE_RESULT_ERROR_RESERVED_GESTURE -> ERROR_RESERVED_COMBINATION
87 
88                 else -> {
89                     Log.w(
90                         TAG,
91                         "Attempted to add inputGesture: $inputGesture " +
92                             "but ran into an error with code: $result",
93                     )
94                     ERROR_OTHER
95                 }
96             }
97         }
98     }
99 
deleteCustomInputGesturenull100     suspend fun deleteCustomInputGesture(
101         inputGesture: InputGestureData
102     ): ShortcutCustomizationRequestResult {
103         return withContext(bgCoroutineContext) {
104             when (val result = inputManager.removeCustomInputGesture(inputGesture)) {
105                 CUSTOM_INPUT_GESTURE_RESULT_SUCCESS -> {
106                     refreshCustomInputGestures()
107                     SUCCESS
108                 }
109                 else -> {
110                     Log.w(
111                         TAG,
112                         "Attempted to delete inputGesture: $inputGesture " +
113                             "but ran into an error with code: $result",
114                     )
115                     ERROR_OTHER
116                 }
117             }
118         }
119     }
120 
resetAllCustomInputGesturesnull121     suspend fun resetAllCustomInputGestures(): ShortcutCustomizationRequestResult {
122         return withContext(bgCoroutineContext) {
123             try {
124                 inputManager.removeAllCustomInputGestures(/* filter= */ InputGestureData.Filter.KEY)
125                 setCustomInputGestures(emptyList())
126                 SUCCESS
127             } catch (e: Exception) {
128                 Log.w(
129                     TAG,
130                     "Attempted to remove all custom shortcut but ran into a remote error: $e",
131                 )
132                 ERROR_OTHER
133             }
134         }
135     }
136 
getInputGestureByTriggernull137     suspend fun getInputGestureByTrigger(trigger: InputGestureData.Trigger): InputGestureData? =
138         withContext(bgCoroutineContext) { inputManager.getInputGesture(trigger) }
139 
140     private companion object {
141         private const val TAG = "CustomInputGesturesRepository"
142     }
143 }
144