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

Commit 9831f62d authored by Fabian Kozynski's avatar Fabian Kozynski Committed by Automerger Merge Worker
Browse files

Merge "Add repository for controls related settings" into tm-qpr-dev am: dc5ae012 am: 91f41ce6

parents 97009f37 91f41ce6
Loading
Loading
Loading
Loading
+29 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2022 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.controls

import kotlinx.coroutines.flow.StateFlow

/** Repository for Device controls related settings. */
interface ControlsSettingsRepository {
    /** Whether device controls activity can be shown above lockscreen for this user. */
    val canShowControlsInLockscreen: StateFlow<Boolean>

    /** Whether trivial controls can be actioned from the lockscreen for this user. */
    val allowActionOnTrivialControlsInLockscreen: StateFlow<Boolean>
}
+90 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2022 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.controls

import android.provider.Settings
import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.qs.SettingObserver
import com.android.systemui.user.data.repository.UserRepository
import com.android.systemui.util.settings.SecureSettings
import javax.inject.Inject
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.stateIn

/**
 * This implementation uses an `@Application` [CoroutineScope] to provide hot flows for the values
 * of the tracked settings.
 */
@SysUISingleton
class ControlsSettingsRepositoryImpl
@Inject
constructor(
    @Application private val scope: CoroutineScope,
    @Background private val backgroundDispatcher: CoroutineDispatcher,
    private val userRepository: UserRepository,
    private val secureSettings: SecureSettings
) : ControlsSettingsRepository {

    override val canShowControlsInLockscreen =
        makeFlowForSetting(Settings.Secure.LOCKSCREEN_SHOW_CONTROLS)

    override val allowActionOnTrivialControlsInLockscreen =
        makeFlowForSetting(Settings.Secure.LOCKSCREEN_ALLOW_TRIVIAL_CONTROLS)

    @OptIn(ExperimentalCoroutinesApi::class)
    private fun makeFlowForSetting(setting: String): StateFlow<Boolean> {
        return userRepository.selectedUserInfo
            .distinctUntilChanged()
            .flatMapLatest { userInfo ->
                conflatedCallbackFlow {
                        val observer =
                            object : SettingObserver(secureSettings, null, setting, userInfo.id) {
                                override fun handleValueChanged(
                                    value: Int,
                                    observedChange: Boolean
                                ) {
                                    trySend(value == 1)
                                }
                            }
                        observer.isListening = true
                        trySend(observer.value == 1)
                        awaitClose { observer.isListening = false }
                    }
                    .flowOn(backgroundDispatcher)
                    .distinctUntilChanged()
            }
            .stateIn(
                scope,
                started = SharingStarted.Eagerly,
                // When the observer starts listening, the flow will emit the current value
                // so the initialValue here is irrelevant.
                initialValue = false,
            )
    }
}
+14 −45
Original line number Diff line number Diff line
@@ -16,13 +16,10 @@

package com.android.systemui.controls.dagger

import android.content.ContentResolver
import android.content.Context
import android.database.ContentObserver
import android.os.UserHandle
import android.provider.Settings
import com.android.internal.widget.LockPatternUtils
import com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_BOOT
import com.android.systemui.controls.ControlsSettingsRepository
import com.android.systemui.controls.controller.ControlsController
import com.android.systemui.controls.controller.ControlsTileResourceConfiguration
import com.android.systemui.controls.controller.ControlsTileResourceConfigurationImpl
@@ -31,12 +28,10 @@ import com.android.systemui.controls.ui.ControlsUiController
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.settings.UserTracker
import com.android.systemui.statusbar.policy.KeyguardStateController
import com.android.systemui.util.settings.SecureSettings
import dagger.Lazy
import kotlinx.coroutines.flow.StateFlow
import java.util.Optional
import javax.inject.Inject
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow

/**
 * Pseudo-component to inject into classes outside `com.android.systemui.controls`.
@@ -54,39 +49,18 @@ class ControlsComponent @Inject constructor(
        private val lockPatternUtils: LockPatternUtils,
        private val keyguardStateController: KeyguardStateController,
        private val userTracker: UserTracker,
    private val secureSettings: SecureSettings,
    private val optionalControlsTileResourceConfiguration:
        Optional<ControlsTileResourceConfiguration>
        controlsSettingsRepository: ControlsSettingsRepository,
        optionalControlsTileResourceConfiguration: Optional<ControlsTileResourceConfiguration>
) {
    private val contentResolver: ContentResolver
        get() = context.contentResolver

    private val _canShowWhileLockedSetting = MutableStateFlow(false)
    val canShowWhileLockedSetting = _canShowWhileLockedSetting.asStateFlow()
    val canShowWhileLockedSetting: StateFlow<Boolean> =
            controlsSettingsRepository.canShowControlsInLockscreen

    private val controlsTileResourceConfiguration: ControlsTileResourceConfiguration =
        optionalControlsTileResourceConfiguration.orElse(
            ControlsTileResourceConfigurationImpl()
        )

    val showWhileLockedObserver = object : ContentObserver(null) {
        override fun onChange(selfChange: Boolean) {
            updateShowWhileLocked()
        }
    }

    init {
        if (featureEnabled) {
            secureSettings.registerContentObserverForUser(
                Settings.Secure.getUriFor(Settings.Secure.LOCKSCREEN_SHOW_CONTROLS),
                false, /* notifyForDescendants */
                showWhileLockedObserver,
                UserHandle.USER_ALL
            )
            updateShowWhileLocked()
        }
    }

    fun getControlsController(): Optional<ControlsController> {
        return if (featureEnabled) Optional.of(lazyControlsController.get()) else Optional.empty()
    }
@@ -127,11 +101,6 @@ class ControlsComponent @Inject constructor(
        return Visibility.AVAILABLE
    }

    private fun updateShowWhileLocked() {
        _canShowWhileLockedSetting.value = secureSettings.getIntForUser(
            Settings.Secure.LOCKSCREEN_SHOW_CONTROLS, 0, UserHandle.USER_CURRENT) != 0
    }

    enum class Visibility {
        AVAILABLE, AVAILABLE_AFTER_UNLOCK, UNAVAILABLE
    }
+7 −0
Original line number Diff line number Diff line
@@ -20,6 +20,8 @@ import android.app.Activity
import android.content.pm.PackageManager
import com.android.systemui.controls.ControlsMetricsLogger
import com.android.systemui.controls.ControlsMetricsLoggerImpl
import com.android.systemui.controls.ControlsSettingsRepository
import com.android.systemui.controls.ControlsSettingsRepositoryImpl
import com.android.systemui.controls.controller.ControlsBindingController
import com.android.systemui.controls.controller.ControlsBindingControllerImpl
import com.android.systemui.controls.controller.ControlsController
@@ -82,6 +84,11 @@ abstract class ControlsModule {
    @Binds
    abstract fun provideUiController(controller: ControlsUiControllerImpl): ControlsUiController

    @Binds
    abstract fun provideSettingsManager(
            manager: ControlsSettingsRepositoryImpl
    ): ControlsSettingsRepository

    @Binds
    abstract fun provideMetricsLogger(logger: ControlsMetricsLoggerImpl): ControlsMetricsLogger

+9 −43
Original line number Diff line number Diff line
@@ -25,9 +25,6 @@ import android.app.PendingIntent
import android.content.Context
import android.content.pm.PackageManager
import android.content.pm.ResolveInfo
import android.database.ContentObserver
import android.net.Uri
import android.os.Handler
import android.os.UserHandle
import android.os.VibrationEffect
import android.provider.Settings.Secure
@@ -41,6 +38,7 @@ import com.android.internal.annotations.VisibleForTesting
import com.android.systemui.R
import com.android.systemui.broadcast.BroadcastSender
import com.android.systemui.controls.ControlsMetricsLogger
import com.android.systemui.controls.ControlsSettingsRepository
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.plugins.ActivityStarter
@@ -69,17 +67,17 @@ class ControlActionCoordinatorImpl @Inject constructor(
    private val vibrator: VibratorHelper,
    private val secureSettings: SecureSettings,
    private val userContextProvider: UserContextProvider,
    @Main mainHandler: Handler
    private val controlsSettingsRepository: ControlsSettingsRepository,
) : ControlActionCoordinator {
    private var dialog: Dialog? = null
    private var pendingAction: Action? = null
    private var actionsInProgress = mutableSetOf<String>()
    private val isLocked: Boolean
        get() = !keyguardStateController.isUnlocked()
    private var mAllowTrivialControls: Boolean = secureSettings.getIntForUser(
            Secure.LOCKSCREEN_ALLOW_TRIVIAL_CONTROLS, 0, UserHandle.USER_CURRENT) != 0
    private var mShowDeviceControlsInLockscreen: Boolean = secureSettings.getIntForUser(
            Secure.LOCKSCREEN_SHOW_CONTROLS, 0, UserHandle.USER_CURRENT) != 0
    private val allowTrivialControls: Boolean
        get() = controlsSettingsRepository.allowActionOnTrivialControlsInLockscreen.value
    private val showDeviceControlsInLockscreen: Boolean
        get() = controlsSettingsRepository.canShowControlsInLockscreen.value
    override lateinit var activityContext: Context

    companion object {
@@ -87,38 +85,6 @@ class ControlActionCoordinatorImpl @Inject constructor(
        private const val MAX_NUMBER_ATTEMPTS_CONTROLS_DIALOG = 2
    }

    init {
        val lockScreenShowControlsUri =
            secureSettings.getUriFor(Secure.LOCKSCREEN_ALLOW_TRIVIAL_CONTROLS)
        val showControlsUri =
                secureSettings.getUriFor(Secure.LOCKSCREEN_SHOW_CONTROLS)
        val controlsContentObserver = object : ContentObserver(mainHandler) {
            override fun onChange(selfChange: Boolean, uri: Uri?) {
                super.onChange(selfChange, uri)
                when (uri) {
                    lockScreenShowControlsUri -> {
                        mAllowTrivialControls = secureSettings.getIntForUser(
                                Secure.LOCKSCREEN_ALLOW_TRIVIAL_CONTROLS,
                                0, UserHandle.USER_CURRENT) != 0
                    }
                    showControlsUri -> {
                        mShowDeviceControlsInLockscreen = secureSettings
                                .getIntForUser(Secure.LOCKSCREEN_SHOW_CONTROLS,
                                        0, UserHandle.USER_CURRENT) != 0
                    }
                }
            }
        }
        secureSettings.registerContentObserverForUser(
            lockScreenShowControlsUri,
            false /* notifyForDescendants */, controlsContentObserver, UserHandle.USER_ALL
        )
        secureSettings.registerContentObserverForUser(
            showControlsUri,
            false /* notifyForDescendants */, controlsContentObserver, UserHandle.USER_ALL
        )
    }

    override fun closeDialogs() {
        val isActivityFinishing =
            (activityContext as? Activity)?.let { it.isFinishing || it.isDestroyed }
@@ -233,7 +199,7 @@ class ControlActionCoordinatorImpl @Inject constructor(
    @AnyThread
    @VisibleForTesting
    fun bouncerOrRun(action: Action) {
        val authRequired = action.authIsRequired || !mAllowTrivialControls
        val authRequired = action.authIsRequired || !allowTrivialControls

        if (keyguardStateController.isShowing() && authRequired) {
            if (isLocked) {
@@ -291,7 +257,7 @@ class ControlActionCoordinatorImpl @Inject constructor(
                PREFS_CONTROLS_FILE, Context.MODE_PRIVATE)
        val attempts = prefs.getInt(PREFS_SETTINGS_DIALOG_ATTEMPTS, 0)
        if (attempts >= MAX_NUMBER_ATTEMPTS_CONTROLS_DIALOG ||
                (mShowDeviceControlsInLockscreen && mAllowTrivialControls)) {
                (showDeviceControlsInLockscreen && allowTrivialControls)) {
            return
        }
        val builder = AlertDialog
@@ -313,7 +279,7 @@ class ControlActionCoordinatorImpl @Inject constructor(
                    true
                }

        if (mShowDeviceControlsInLockscreen) {
        if (showDeviceControlsInLockscreen) {
            dialog = builder
                    .setTitle(R.string.controls_settings_trivial_controls_dialog_title)
                    .setMessage(R.string.controls_settings_trivial_controls_dialog_message)
Loading