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

Commit 91f41ce6 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

parents 0ee11c7d dc5ae012
Loading
Loading
Loading
Loading
+29 −0
Original line number Original line 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 Original line 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 Original line Diff line number Diff line
@@ -16,13 +16,10 @@


package com.android.systemui.controls.dagger
package com.android.systemui.controls.dagger


import android.content.ContentResolver
import android.content.Context
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
import com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_BOOT
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.ControlsController
import com.android.systemui.controls.controller.ControlsTileResourceConfiguration
import com.android.systemui.controls.controller.ControlsTileResourceConfiguration
import com.android.systemui.controls.controller.ControlsTileResourceConfigurationImpl
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.dagger.SysUISingleton
import com.android.systemui.settings.UserTracker
import com.android.systemui.settings.UserTracker
import com.android.systemui.statusbar.policy.KeyguardStateController
import com.android.systemui.statusbar.policy.KeyguardStateController
import com.android.systemui.util.settings.SecureSettings
import dagger.Lazy
import dagger.Lazy
import kotlinx.coroutines.flow.StateFlow
import java.util.Optional
import java.util.Optional
import javax.inject.Inject
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`.
 * 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 lockPatternUtils: LockPatternUtils,
        private val keyguardStateController: KeyguardStateController,
        private val keyguardStateController: KeyguardStateController,
        private val userTracker: UserTracker,
        private val userTracker: UserTracker,
    private val secureSettings: SecureSettings,
        controlsSettingsRepository: ControlsSettingsRepository,
    private val optionalControlsTileResourceConfiguration:
        optionalControlsTileResourceConfiguration: Optional<ControlsTileResourceConfiguration>
        Optional<ControlsTileResourceConfiguration>
) {
) {
    private val contentResolver: ContentResolver
        get() = context.contentResolver


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


    private val controlsTileResourceConfiguration: ControlsTileResourceConfiguration =
    private val controlsTileResourceConfiguration: ControlsTileResourceConfiguration =
        optionalControlsTileResourceConfiguration.orElse(
        optionalControlsTileResourceConfiguration.orElse(
            ControlsTileResourceConfigurationImpl()
            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> {
    fun getControlsController(): Optional<ControlsController> {
        return if (featureEnabled) Optional.of(lazyControlsController.get()) else Optional.empty()
        return if (featureEnabled) Optional.of(lazyControlsController.get()) else Optional.empty()
    }
    }
@@ -127,11 +101,6 @@ class ControlsComponent @Inject constructor(
        return Visibility.AVAILABLE
        return Visibility.AVAILABLE
    }
    }


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

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


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

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


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


    companion object {
    companion object {
@@ -87,38 +85,6 @@ class ControlActionCoordinatorImpl @Inject constructor(
        private const val MAX_NUMBER_ATTEMPTS_CONTROLS_DIALOG = 2
        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() {
    override fun closeDialogs() {
        val isActivityFinishing =
        val isActivityFinishing =
            (activityContext as? Activity)?.let { it.isFinishing || it.isDestroyed }
            (activityContext as? Activity)?.let { it.isFinishing || it.isDestroyed }
@@ -233,7 +199,7 @@ class ControlActionCoordinatorImpl @Inject constructor(
    @AnyThread
    @AnyThread
    @VisibleForTesting
    @VisibleForTesting
    fun bouncerOrRun(action: Action) {
    fun bouncerOrRun(action: Action) {
        val authRequired = action.authIsRequired || !mAllowTrivialControls
        val authRequired = action.authIsRequired || !allowTrivialControls


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


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