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.accessibility.data.repository
18 
19 import android.os.UserHandle
20 import android.provider.Settings
21 import com.android.systemui.dagger.SysUISingleton
22 import com.android.systemui.dagger.qualifiers.Application
23 import com.android.systemui.dagger.qualifiers.Background
24 import com.android.systemui.util.settings.SecureSettings
25 import com.android.systemui.util.settings.SettingsProxyExt.observerFlow
26 import javax.inject.Inject
27 import kotlin.coroutines.CoroutineContext
28 import kotlinx.coroutines.CoroutineScope
29 import kotlinx.coroutines.flow.Flow
30 import kotlinx.coroutines.flow.SharingStarted
31 import kotlinx.coroutines.flow.distinctUntilChanged
32 import kotlinx.coroutines.flow.flowOn
33 import kotlinx.coroutines.flow.map
34 import kotlinx.coroutines.flow.onStart
35 import kotlinx.coroutines.flow.stateIn
36 import kotlinx.coroutines.withContext
37 
38 /** Provides data related to one handed mode. */
39 interface OneHandedModeRepository {
40     /** Observable for whether one handed mode is enabled */
isEnablednull41     fun isEnabled(userHandle: UserHandle): Flow<Boolean>
42 
43     /** Sets one handed mode enabled state. */
44     suspend fun setIsEnabled(isEnabled: Boolean, userHandle: UserHandle): Boolean
45 }
46 
47 @SysUISingleton
48 class OneHandedModeRepositoryImpl
49 @Inject
50 constructor(
51     @Background private val bgCoroutineContext: CoroutineContext,
52     @Application private val scope: CoroutineScope,
53     private val secureSettings: SecureSettings,
54 ) : OneHandedModeRepository {
55 
56     private val userMap = mutableMapOf<Int, Flow<Boolean>>()
57 
58     override fun isEnabled(userHandle: UserHandle): Flow<Boolean> =
59         userMap.getOrPut(userHandle.identifier) {
60             secureSettings
61                 .observerFlow(userHandle.identifier, SETTING_NAME)
62                 .onStart { emit(Unit) }
63                 .map {
64                     secureSettings.getIntForUser(SETTING_NAME, DISABLED, userHandle.identifier) ==
65                         ENABLED
66                 }
67                 .distinctUntilChanged()
68                 .flowOn(bgCoroutineContext)
69                 .stateIn(scope, SharingStarted.WhileSubscribed(), DEFAULT_VALUE)
70         }
71 
72     override suspend fun setIsEnabled(isEnabled: Boolean, userHandle: UserHandle): Boolean =
73         withContext(bgCoroutineContext) {
74             secureSettings.putIntForUser(
75                 SETTING_NAME,
76                 if (isEnabled) ENABLED else DISABLED,
77                 userHandle.identifier
78             )
79         }
80 
81     companion object {
82         private const val SETTING_NAME = Settings.Secure.ONE_HANDED_MODE_ENABLED
83         private const val DISABLED = 0
84         private const val ENABLED = 1
85         private const val DEFAULT_VALUE = false
86     }
87 }
88