Merge "Add repository for controls related settings" into tm-qpr-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
dc5ae0129f
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* 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>
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* 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,
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -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`.
|
||||
@@ -46,47 +41,26 @@ import kotlinx.coroutines.flow.asStateFlow
|
||||
*/
|
||||
@SysUISingleton
|
||||
class ControlsComponent @Inject constructor(
|
||||
@ControlsFeatureEnabled private val featureEnabled: Boolean,
|
||||
private val context: Context,
|
||||
private val lazyControlsController: Lazy<ControlsController>,
|
||||
private val lazyControlsUiController: Lazy<ControlsUiController>,
|
||||
private val lazyControlsListingController: Lazy<ControlsListingController>,
|
||||
private val lockPatternUtils: LockPatternUtils,
|
||||
private val keyguardStateController: KeyguardStateController,
|
||||
private val userTracker: UserTracker,
|
||||
private val secureSettings: SecureSettings,
|
||||
private val optionalControlsTileResourceConfiguration:
|
||||
Optional<ControlsTileResourceConfiguration>
|
||||
@ControlsFeatureEnabled private val featureEnabled: Boolean,
|
||||
private val context: Context,
|
||||
private val lazyControlsController: Lazy<ControlsController>,
|
||||
private val lazyControlsUiController: Lazy<ControlsUiController>,
|
||||
private val lazyControlsListingController: Lazy<ControlsListingController>,
|
||||
private val lockPatternUtils: LockPatternUtils,
|
||||
private val keyguardStateController: KeyguardStateController,
|
||||
private val userTracker: UserTracker,
|
||||
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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -24,9 +24,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
|
||||
@@ -40,6 +37,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
|
||||
@@ -68,17 +66,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 {
|
||||
@@ -86,38 +84,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() {
|
||||
dialog?.dismiss()
|
||||
dialog = null
|
||||
@@ -224,7 +190,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) {
|
||||
@@ -282,7 +248,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
|
||||
@@ -304,7 +270,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)
|
||||
|
||||
@@ -0,0 +1,187 @@
|
||||
/*
|
||||
* 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.content.pm.UserInfo
|
||||
import android.provider.Settings
|
||||
import androidx.test.filters.SmallTest
|
||||
import com.android.systemui.SysuiTestCase
|
||||
import com.android.systemui.user.data.repository.FakeUserRepository
|
||||
import com.android.systemui.util.settings.FakeSettings
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.flow.toList
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.test.TestScope
|
||||
import kotlinx.coroutines.test.UnconfinedTestDispatcher
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.junit.runners.JUnit4
|
||||
|
||||
@SmallTest
|
||||
@RunWith(JUnit4::class)
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
class ControlsSettingsRepositoryImplTest : SysuiTestCase() {
|
||||
|
||||
companion object {
|
||||
private const val LOCKSCREEN_SHOW = Settings.Secure.LOCKSCREEN_SHOW_CONTROLS
|
||||
private const val LOCKSCREEN_ACTION = Settings.Secure.LOCKSCREEN_ALLOW_TRIVIAL_CONTROLS
|
||||
|
||||
private fun createUser(id: Int): UserInfo {
|
||||
return UserInfo(id, "user_$id", 0)
|
||||
}
|
||||
|
||||
private val ALL_USERS = (0..1).map { it to createUser(it) }.toMap()
|
||||
}
|
||||
|
||||
private lateinit var underTest: ControlsSettingsRepository
|
||||
|
||||
private lateinit var testScope: TestScope
|
||||
private lateinit var secureSettings: FakeSettings
|
||||
private lateinit var userRepository: FakeUserRepository
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
secureSettings = FakeSettings()
|
||||
userRepository = FakeUserRepository()
|
||||
userRepository.setUserInfos(ALL_USERS.values.toList())
|
||||
|
||||
val coroutineDispatcher = UnconfinedTestDispatcher()
|
||||
testScope = TestScope(coroutineDispatcher)
|
||||
|
||||
underTest =
|
||||
ControlsSettingsRepositoryImpl(
|
||||
scope = testScope.backgroundScope,
|
||||
backgroundDispatcher = coroutineDispatcher,
|
||||
userRepository = userRepository,
|
||||
secureSettings = secureSettings,
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun showInLockScreen() =
|
||||
testScope.runTest {
|
||||
setUser(0)
|
||||
val values = mutableListOf<Boolean>()
|
||||
val job =
|
||||
launch(UnconfinedTestDispatcher()) {
|
||||
underTest.canShowControlsInLockscreen.toList(values)
|
||||
}
|
||||
assertThat(values.last()).isFalse()
|
||||
|
||||
secureSettings.putBool(LOCKSCREEN_SHOW, true)
|
||||
assertThat(values.last()).isTrue()
|
||||
|
||||
secureSettings.putBool(LOCKSCREEN_SHOW, false)
|
||||
assertThat(values.last()).isFalse()
|
||||
|
||||
secureSettings.putBoolForUser(LOCKSCREEN_SHOW, true, 1)
|
||||
assertThat(values.last()).isFalse()
|
||||
|
||||
setUser(1)
|
||||
assertThat(values.last()).isTrue()
|
||||
|
||||
job.cancel()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun showInLockScreen_changesInOtherUsersAreNotQueued() =
|
||||
testScope.runTest {
|
||||
setUser(0)
|
||||
|
||||
val values = mutableListOf<Boolean>()
|
||||
val job =
|
||||
launch(UnconfinedTestDispatcher()) {
|
||||
underTest.canShowControlsInLockscreen.toList(values)
|
||||
}
|
||||
|
||||
secureSettings.putBoolForUser(LOCKSCREEN_SHOW, true, 1)
|
||||
secureSettings.putBoolForUser(LOCKSCREEN_SHOW, false, 1)
|
||||
|
||||
setUser(1)
|
||||
assertThat(values.last()).isFalse()
|
||||
assertThat(values).containsNoneIn(listOf(true))
|
||||
|
||||
job.cancel()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun actionInLockScreen() =
|
||||
testScope.runTest {
|
||||
setUser(0)
|
||||
val values = mutableListOf<Boolean>()
|
||||
val job =
|
||||
launch(UnconfinedTestDispatcher()) {
|
||||
underTest.allowActionOnTrivialControlsInLockscreen.toList(values)
|
||||
}
|
||||
assertThat(values.last()).isFalse()
|
||||
|
||||
secureSettings.putBool(LOCKSCREEN_ACTION, true)
|
||||
assertThat(values.last()).isTrue()
|
||||
|
||||
secureSettings.putBool(LOCKSCREEN_ACTION, false)
|
||||
assertThat(values.last()).isFalse()
|
||||
|
||||
secureSettings.putBoolForUser(LOCKSCREEN_ACTION, true, 1)
|
||||
assertThat(values.last()).isFalse()
|
||||
|
||||
setUser(1)
|
||||
assertThat(values.last()).isTrue()
|
||||
|
||||
job.cancel()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun actionInLockScreen_changesInOtherUsersAreNotQueued() =
|
||||
testScope.runTest {
|
||||
setUser(0)
|
||||
|
||||
val values = mutableListOf<Boolean>()
|
||||
val job =
|
||||
launch(UnconfinedTestDispatcher()) {
|
||||
underTest.allowActionOnTrivialControlsInLockscreen.toList(values)
|
||||
}
|
||||
|
||||
secureSettings.putBoolForUser(LOCKSCREEN_ACTION, true, 1)
|
||||
secureSettings.putBoolForUser(LOCKSCREEN_ACTION, false, 1)
|
||||
|
||||
setUser(1)
|
||||
assertThat(values.last()).isFalse()
|
||||
assertThat(values).containsNoneIn(listOf(true))
|
||||
|
||||
job.cancel()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun valueIsUpdatedWhenNotSubscribed() =
|
||||
testScope.runTest {
|
||||
setUser(0)
|
||||
assertThat(underTest.canShowControlsInLockscreen.value).isFalse()
|
||||
|
||||
secureSettings.putBool(LOCKSCREEN_SHOW, true)
|
||||
|
||||
assertThat(underTest.canShowControlsInLockscreen.value).isTrue()
|
||||
}
|
||||
|
||||
private suspend fun setUser(id: Int) {
|
||||
secureSettings.userId = id
|
||||
userRepository.setSelectedUserInfo(ALL_USERS[id]!!)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* 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.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
|
||||
class FakeControlsSettingsRepository : ControlsSettingsRepository {
|
||||
private val _canShowControlsInLockscreen = MutableStateFlow(false)
|
||||
override val canShowControlsInLockscreen = _canShowControlsInLockscreen.asStateFlow()
|
||||
private val _allowActionOnTrivialControlsInLockscreen = MutableStateFlow(false)
|
||||
override val allowActionOnTrivialControlsInLockscreen =
|
||||
_allowActionOnTrivialControlsInLockscreen.asStateFlow()
|
||||
|
||||
fun setCanShowControlsInLockscreen(value: Boolean) {
|
||||
_canShowControlsInLockscreen.value = value
|
||||
}
|
||||
|
||||
fun setAllowActionOnTrivialControlsInLockscreen(value: Boolean) {
|
||||
_allowActionOnTrivialControlsInLockscreen.value = value
|
||||
}
|
||||
}
|
||||
@@ -18,30 +18,24 @@ package com.android.systemui.controls.ui
|
||||
|
||||
import android.content.Context
|
||||
import android.content.SharedPreferences
|
||||
import android.database.ContentObserver
|
||||
import android.net.Uri
|
||||
import android.os.Handler
|
||||
import android.os.UserHandle
|
||||
import android.provider.Settings
|
||||
import android.test.suitebuilder.annotation.SmallTest
|
||||
import android.testing.AndroidTestingRunner
|
||||
import com.android.systemui.SysuiTestCase
|
||||
import com.android.systemui.broadcast.BroadcastSender
|
||||
import com.android.systemui.controls.ControlsMetricsLogger
|
||||
import com.android.systemui.controls.FakeControlsSettingsRepository
|
||||
import com.android.systemui.plugins.ActivityStarter
|
||||
import com.android.systemui.settings.UserContextProvider
|
||||
import com.android.systemui.statusbar.VibratorHelper
|
||||
import com.android.systemui.statusbar.policy.DeviceControlsControllerImpl
|
||||
import com.android.systemui.statusbar.policy.KeyguardStateController
|
||||
import com.android.systemui.util.concurrency.DelayableExecutor
|
||||
import com.android.systemui.util.mockito.any
|
||||
import com.android.systemui.util.settings.SecureSettings
|
||||
import com.android.wm.shell.TaskViewFactory
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mockito.Answers
|
||||
import org.mockito.ArgumentMatchers.anyInt
|
||||
import org.mockito.Mock
|
||||
import org.mockito.Mockito
|
||||
import org.mockito.Mockito.`when`
|
||||
@@ -79,8 +73,6 @@ class ControlActionCoordinatorImplTest : SysuiTestCase() {
|
||||
@Mock
|
||||
private lateinit var secureSettings: SecureSettings
|
||||
@Mock
|
||||
private lateinit var mainHandler: Handler
|
||||
@Mock
|
||||
private lateinit var userContextProvider: UserContextProvider
|
||||
|
||||
companion object {
|
||||
@@ -91,17 +83,15 @@ class ControlActionCoordinatorImplTest : SysuiTestCase() {
|
||||
|
||||
private lateinit var coordinator: ControlActionCoordinatorImpl
|
||||
private lateinit var action: ControlActionCoordinatorImpl.Action
|
||||
private lateinit var controlsSettingsRepository: FakeControlsSettingsRepository
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
MockitoAnnotations.initMocks(this)
|
||||
|
||||
`when`(secureSettings.getUriFor(Settings.Secure.LOCKSCREEN_ALLOW_TRIVIAL_CONTROLS))
|
||||
.thenReturn(Settings.Secure
|
||||
.getUriFor(Settings.Secure.LOCKSCREEN_ALLOW_TRIVIAL_CONTROLS))
|
||||
`when`(secureSettings.getIntForUser(Settings.Secure.LOCKSCREEN_ALLOW_TRIVIAL_CONTROLS,
|
||||
0, UserHandle.USER_CURRENT))
|
||||
.thenReturn(1)
|
||||
controlsSettingsRepository = FakeControlsSettingsRepository()
|
||||
controlsSettingsRepository.setAllowActionOnTrivialControlsInLockscreen(true)
|
||||
controlsSettingsRepository.setCanShowControlsInLockscreen(true)
|
||||
|
||||
coordinator = spy(ControlActionCoordinatorImpl(
|
||||
mContext,
|
||||
@@ -115,7 +105,7 @@ class ControlActionCoordinatorImplTest : SysuiTestCase() {
|
||||
vibratorHelper,
|
||||
secureSettings,
|
||||
userContextProvider,
|
||||
mainHandler
|
||||
controlsSettingsRepository
|
||||
))
|
||||
|
||||
val userContext = mock(Context::class.java)
|
||||
@@ -128,9 +118,6 @@ class ControlActionCoordinatorImplTest : SysuiTestCase() {
|
||||
`when`(pref.getInt(DeviceControlsControllerImpl.PREFS_SETTINGS_DIALOG_ATTEMPTS, 0))
|
||||
.thenReturn(2)
|
||||
|
||||
verify(secureSettings).registerContentObserverForUser(any(Uri::class.java),
|
||||
anyBoolean(), any(ContentObserver::class.java), anyInt())
|
||||
|
||||
`when`(cvh.cws.ci.controlId).thenReturn(ID)
|
||||
`when`(cvh.cws.control?.isAuthRequired()).thenReturn(true)
|
||||
action = spy(coordinator.Action(ID, {}, false, true))
|
||||
|
||||
@@ -17,19 +17,18 @@
|
||||
package com.android.systemui.controls.dagger
|
||||
|
||||
import android.testing.AndroidTestingRunner
|
||||
import android.provider.Settings
|
||||
import androidx.test.filters.SmallTest
|
||||
import com.android.internal.widget.LockPatternUtils
|
||||
import com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_NOT_REQUIRED
|
||||
import com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_BOOT
|
||||
import com.android.systemui.SysuiTestCase
|
||||
import com.android.systemui.controls.FakeControlsSettingsRepository
|
||||
import com.android.systemui.controls.controller.ControlsController
|
||||
import com.android.systemui.controls.controller.ControlsTileResourceConfiguration
|
||||
import com.android.systemui.controls.management.ControlsListingController
|
||||
import com.android.systemui.controls.ui.ControlsUiController
|
||||
import com.android.systemui.settings.UserTracker
|
||||
import com.android.systemui.statusbar.policy.KeyguardStateController
|
||||
import com.android.systemui.util.settings.SecureSettings
|
||||
import dagger.Lazy
|
||||
import java.util.Optional
|
||||
import org.junit.Assert.assertEquals
|
||||
@@ -63,13 +62,13 @@ class ControlsComponentTest : SysuiTestCase() {
|
||||
@Mock
|
||||
private lateinit var lockPatternUtils: LockPatternUtils
|
||||
@Mock
|
||||
private lateinit var secureSettings: SecureSettings
|
||||
@Mock
|
||||
private lateinit var optionalControlsTileResourceConfiguration:
|
||||
Optional<ControlsTileResourceConfiguration>
|
||||
@Mock
|
||||
private lateinit var controlsTileResourceConfiguration: ControlsTileResourceConfiguration
|
||||
|
||||
private lateinit var controlsSettingsRepository: FakeControlsSettingsRepository
|
||||
|
||||
companion object {
|
||||
fun <T> eq(value: T): T = Mockito.eq(value) ?: value
|
||||
}
|
||||
@@ -78,6 +77,8 @@ class ControlsComponentTest : SysuiTestCase() {
|
||||
fun setUp() {
|
||||
MockitoAnnotations.initMocks(this)
|
||||
|
||||
controlsSettingsRepository = FakeControlsSettingsRepository()
|
||||
|
||||
`when`(userTracker.userHandle.identifier).thenReturn(0)
|
||||
`when`(optionalControlsTileResourceConfiguration.orElse(any()))
|
||||
.thenReturn(controlsTileResourceConfiguration)
|
||||
@@ -125,8 +126,7 @@ class ControlsComponentTest : SysuiTestCase() {
|
||||
`when`(lockPatternUtils.getStrongAuthForUser(anyInt()))
|
||||
.thenReturn(STRONG_AUTH_NOT_REQUIRED)
|
||||
`when`(keyguardStateController.isUnlocked()).thenReturn(false)
|
||||
`when`(secureSettings.getInt(eq(Settings.Secure.LOCKSCREEN_SHOW_CONTROLS), anyInt()))
|
||||
.thenReturn(0)
|
||||
controlsSettingsRepository.setCanShowControlsInLockscreen(false)
|
||||
val component = setupComponent(true)
|
||||
|
||||
assertEquals(ControlsComponent.Visibility.AVAILABLE_AFTER_UNLOCK, component.getVisibility())
|
||||
@@ -137,9 +137,7 @@ class ControlsComponentTest : SysuiTestCase() {
|
||||
`when`(lockPatternUtils.getStrongAuthForUser(anyInt()))
|
||||
.thenReturn(STRONG_AUTH_NOT_REQUIRED)
|
||||
`when`(keyguardStateController.isUnlocked()).thenReturn(false)
|
||||
`when`(secureSettings.getIntForUser(eq(Settings.Secure.LOCKSCREEN_SHOW_CONTROLS),
|
||||
anyInt(), anyInt()))
|
||||
.thenReturn(1)
|
||||
controlsSettingsRepository.setCanShowControlsInLockscreen(true)
|
||||
val component = setupComponent(true)
|
||||
|
||||
assertEquals(ControlsComponent.Visibility.AVAILABLE, component.getVisibility())
|
||||
@@ -147,8 +145,7 @@ class ControlsComponentTest : SysuiTestCase() {
|
||||
|
||||
@Test
|
||||
fun testFeatureEnabledAndCanShowWhileUnlockedVisibility() {
|
||||
`when`(secureSettings.getInt(eq(Settings.Secure.LOCKSCREEN_SHOW_CONTROLS), anyInt()))
|
||||
.thenReturn(0)
|
||||
controlsSettingsRepository.setCanShowControlsInLockscreen(false)
|
||||
`when`(lockPatternUtils.getStrongAuthForUser(anyInt()))
|
||||
.thenReturn(STRONG_AUTH_NOT_REQUIRED)
|
||||
`when`(keyguardStateController.isUnlocked()).thenReturn(true)
|
||||
@@ -187,7 +184,7 @@ class ControlsComponentTest : SysuiTestCase() {
|
||||
lockPatternUtils,
|
||||
keyguardStateController,
|
||||
userTracker,
|
||||
secureSettings,
|
||||
controlsSettingsRepository,
|
||||
optionalControlsTileResourceConfiguration
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user