Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0b192ad4 authored by Michal Brzezinski's avatar Michal Brzezinski Committed by Michał Brzeziński
Browse files

Adding UserAwareSecureSettingsRepository

Extracting part of StickyKeysRepositoryImpl into reusable UserAwareSecureSettingsRepository.

Why new class?
- existing SecureSettingsRepository is in shared customization module because it's used by WallpaperPicker. It cannot be moved out of it so WallpaperPicker can still use it and it can't be modified because it doesn't have dependency on core sysui module that includes SecureSettings and UserRepository

Why not using SecureSettingsRepository inside UserAwareSecureSettingsRepository?
- because it's dependent on ContentResolver which makes user-dependency less explicit - user is just taken from associated context. In theory it could be implemented with UserTracker.userContentResolver but that requires more callbacks and seems less explicit about what's going on.

Bug: 319837892
Test: UserAwareSecureSettingsRepositoryTest
Flag: N/A
Change-Id: I29114ad561ae997998a984c6d91d2bb90af7148f
parent 1152b38d
Loading
Loading
Loading
Loading
+5 −1
Original line number Diff line number Diff line
@@ -27,7 +27,11 @@ import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.withContext

/** Defines interface for classes that can provide access to data from [Settings.Secure]. */
/**
 * Defines interface for classes that can provide access to data from [Settings.Secure].
 * This repository doesn't guarantee to provide value across different users. For that
 * see: [UserAwareSecureSettingsRepository]
 */
interface SecureSettingsRepository {

    /** Returns a [Flow] tracking the value of a setting as an [Int]. */
+5 −28
Original line number Diff line number Diff line
@@ -32,19 +32,13 @@ 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.META
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 com.android.systemui.util.settings.repository.UserAwareSecureSettingsRepository
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.onStart
import javax.inject.Inject

interface StickyKeysRepository {
@@ -53,14 +47,12 @@ interface StickyKeysRepository {
}

@SysUISingleton
@OptIn(ExperimentalCoroutinesApi::class)
class StickyKeysRepositoryImpl
@Inject
constructor(
    private val inputManager: InputManager,
    @Background private val backgroundDispatcher: CoroutineDispatcher,
    private val secureSettings: SecureSettings,
    userRepository: UserRepository,
    secureSettingsRepository: UserAwareSecureSettingsRepository,
    private val stickyKeysLogger: StickyKeysLogger,
) : StickyKeysRepository {

@@ -78,25 +70,10 @@ constructor(
            .flowOn(backgroundDispatcher)

    override val settingEnabled: Flow<Boolean> =
        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()
        secureSettingsRepository
            .boolSettingForActiveUser(SETTING_KEY, defaultValue = false)
            .onEach { stickyKeysLogger.logNewSettingValue(it) }
    }

    private fun isSettingEnabledForCurrentUser(userId: Int) =
        secureSettings.getIntForUser(
            /* name= */ SETTING_KEY,
            /* default= */ 0,
            /* userHandle= */ userId
        ) != 0
            .flowOn(backgroundDispatcher)

    private fun toStickyKeysMap(state: StickyModifierState): LinkedHashMap<ModifierKey, Locked> {
        val keys = linkedMapOf<ModifierKey, Locked>()
+8 −0
Original line number Diff line number Diff line
@@ -16,6 +16,9 @@

package com.android.systemui.util.settings;

import com.android.systemui.util.settings.repository.UserAwareSecureSettingsRepository;
import com.android.systemui.util.settings.repository.UserAwareSecureSettingsRepositoryImpl;

import dagger.Binds;
import dagger.Module;

@@ -36,4 +39,9 @@ public interface SettingsUtilModule {
    /** Bind GlobalSettingsImpl to GlobalSettings. */
    @Binds
    GlobalSettings bindsGlobalSettings(GlobalSettingsImpl impl);

    /** Bind UserAwareSecureSettingsRepositoryImpl to UserAwareSecureSettingsRepository. */
    @Binds
    UserAwareSecureSettingsRepository bindsUserAwareSecureSettingsRepository(
            UserAwareSecureSettingsRepositoryImpl impl);
}
+70 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.systemui.util.settings.repository

import android.provider.Settings
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.user.data.repository.UserRepository
import com.android.systemui.util.settings.SecureSettings
import com.android.systemui.util.settings.SettingsProxy
import com.android.systemui.util.settings.SettingsProxyExt.observerFlow
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onStart
import javax.inject.Inject

/**
 * Repository for observing values of [Settings.Secure] for the currently active user. That means
 * when user is switched and the new user has different value, flow will emit new value.
 */
interface UserAwareSecureSettingsRepository {

    /**
     * Emits boolean value of the setting for active user. Also emits starting value when
     * subscribed.
     * See: [SettingsProxy.getBool].
     */
    fun boolSettingForActiveUser(name: String, defaultValue: Boolean = false): Flow<Boolean>
}

@SysUISingleton
@OptIn(ExperimentalCoroutinesApi::class)
class UserAwareSecureSettingsRepositoryImpl @Inject constructor(
    private val secureSettings: SecureSettings,
    private val userRepository: UserRepository,
    @Background private val backgroundDispatcher: CoroutineDispatcher,
) : UserAwareSecureSettingsRepository {

    override fun boolSettingForActiveUser(name: String, defaultValue: Boolean): Flow<Boolean> =
        userRepository.selectedUserInfo
            .flatMapLatest { userInfo -> settingObserver(name, defaultValue, userInfo.id) }
            .distinctUntilChanged()
            .flowOn(backgroundDispatcher)

    private fun settingObserver(name: String, defaultValue: Boolean, userId: Int): Flow<Boolean> {
        return secureSettings
            .observerFlow(userId, name)
            .onStart { emit(Unit) }
            .map { secureSettings.getBoolForUser(name, defaultValue, userId) }
    }
}
 No newline at end of file
+7 −2
Original line number Diff line number Diff line
@@ -37,6 +37,7 @@ import com.android.systemui.user.data.repository.fakeUserRepository
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.mock
import com.android.systemui.util.settings.FakeSettings
import com.android.systemui.util.settings.repository.UserAwareSecureSettingsRepositoryImpl
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.StandardTestDispatcher
@@ -68,11 +69,15 @@ class StickyKeysIndicatorViewModelTest : SysuiTestCase() {

    @Before
    fun setup() {
        val settingsRepository = UserAwareSecureSettingsRepositoryImpl(
            secureSettings,
            userRepository,
            dispatcher
        )
        val stickyKeysRepository = StickyKeysRepositoryImpl(
            inputManager,
            dispatcher,
            secureSettings,
            userRepository,
            settingsRepository,
            mock<StickyKeysLogger>()
        )
        setStickyKeySetting(enabled = false)
Loading