Merge "Add repository for controls related settings" into tm-qpr-dev

This commit is contained in:
Fabian Kozynski
2022-11-30 19:26:28 +00:00
committed by Android (Google) Code Review
9 changed files with 388 additions and 119 deletions

View File

@@ -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>
}

View File

@@ -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,
)
}
}

View File

@@ -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
} }

View File

@@ -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

View File

@@ -24,9 +24,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
@@ -40,6 +37,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
@@ -68,17 +66,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 {
@@ -86,38 +84,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() {
dialog?.dismiss() dialog?.dismiss()
dialog = null dialog = null
@@ -224,7 +190,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) {
@@ -282,7 +248,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
@@ -304,7 +270,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)

View File

@@ -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]!!)
}
}

View File

@@ -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
}
}

View File

@@ -18,30 +18,24 @@ package com.android.systemui.controls.ui
import android.content.Context import android.content.Context
import android.content.SharedPreferences 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.test.suitebuilder.annotation.SmallTest
import android.testing.AndroidTestingRunner import android.testing.AndroidTestingRunner
import com.android.systemui.SysuiTestCase import com.android.systemui.SysuiTestCase
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.FakeControlsSettingsRepository
import com.android.systemui.plugins.ActivityStarter import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.settings.UserContextProvider import com.android.systemui.settings.UserContextProvider
import com.android.systemui.statusbar.VibratorHelper import com.android.systemui.statusbar.VibratorHelper
import com.android.systemui.statusbar.policy.DeviceControlsControllerImpl import com.android.systemui.statusbar.policy.DeviceControlsControllerImpl
import com.android.systemui.statusbar.policy.KeyguardStateController import com.android.systemui.statusbar.policy.KeyguardStateController
import com.android.systemui.util.concurrency.DelayableExecutor import com.android.systemui.util.concurrency.DelayableExecutor
import com.android.systemui.util.mockito.any
import com.android.systemui.util.settings.SecureSettings import com.android.systemui.util.settings.SecureSettings
import com.android.wm.shell.TaskViewFactory import com.android.wm.shell.TaskViewFactory
import org.junit.Before import org.junit.Before
import org.junit.Test import org.junit.Test
import org.junit.runner.RunWith import org.junit.runner.RunWith
import org.mockito.Answers import org.mockito.Answers
import org.mockito.ArgumentMatchers.anyInt
import org.mockito.Mock import org.mockito.Mock
import org.mockito.Mockito import org.mockito.Mockito
import org.mockito.Mockito.`when` import org.mockito.Mockito.`when`
@@ -79,8 +73,6 @@ class ControlActionCoordinatorImplTest : SysuiTestCase() {
@Mock @Mock
private lateinit var secureSettings: SecureSettings private lateinit var secureSettings: SecureSettings
@Mock @Mock
private lateinit var mainHandler: Handler
@Mock
private lateinit var userContextProvider: UserContextProvider private lateinit var userContextProvider: UserContextProvider
companion object { companion object {
@@ -91,17 +83,15 @@ class ControlActionCoordinatorImplTest : SysuiTestCase() {
private lateinit var coordinator: ControlActionCoordinatorImpl private lateinit var coordinator: ControlActionCoordinatorImpl
private lateinit var action: ControlActionCoordinatorImpl.Action private lateinit var action: ControlActionCoordinatorImpl.Action
private lateinit var controlsSettingsRepository: FakeControlsSettingsRepository
@Before @Before
fun setUp() { fun setUp() {
MockitoAnnotations.initMocks(this) MockitoAnnotations.initMocks(this)
`when`(secureSettings.getUriFor(Settings.Secure.LOCKSCREEN_ALLOW_TRIVIAL_CONTROLS)) controlsSettingsRepository = FakeControlsSettingsRepository()
.thenReturn(Settings.Secure controlsSettingsRepository.setAllowActionOnTrivialControlsInLockscreen(true)
.getUriFor(Settings.Secure.LOCKSCREEN_ALLOW_TRIVIAL_CONTROLS)) controlsSettingsRepository.setCanShowControlsInLockscreen(true)
`when`(secureSettings.getIntForUser(Settings.Secure.LOCKSCREEN_ALLOW_TRIVIAL_CONTROLS,
0, UserHandle.USER_CURRENT))
.thenReturn(1)
coordinator = spy(ControlActionCoordinatorImpl( coordinator = spy(ControlActionCoordinatorImpl(
mContext, mContext,
@@ -115,7 +105,7 @@ class ControlActionCoordinatorImplTest : SysuiTestCase() {
vibratorHelper, vibratorHelper,
secureSettings, secureSettings,
userContextProvider, userContextProvider,
mainHandler controlsSettingsRepository
)) ))
val userContext = mock(Context::class.java) val userContext = mock(Context::class.java)
@@ -128,9 +118,6 @@ class ControlActionCoordinatorImplTest : SysuiTestCase() {
`when`(pref.getInt(DeviceControlsControllerImpl.PREFS_SETTINGS_DIALOG_ATTEMPTS, 0)) `when`(pref.getInt(DeviceControlsControllerImpl.PREFS_SETTINGS_DIALOG_ATTEMPTS, 0))
.thenReturn(2) .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.ci.controlId).thenReturn(ID)
`when`(cvh.cws.control?.isAuthRequired()).thenReturn(true) `when`(cvh.cws.control?.isAuthRequired()).thenReturn(true)
action = spy(coordinator.Action(ID, {}, false, true)) action = spy(coordinator.Action(ID, {}, false, true))

View File

@@ -17,19 +17,18 @@
package com.android.systemui.controls.dagger package com.android.systemui.controls.dagger
import android.testing.AndroidTestingRunner import android.testing.AndroidTestingRunner
import android.provider.Settings
import androidx.test.filters.SmallTest import androidx.test.filters.SmallTest
import com.android.internal.widget.LockPatternUtils 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_NOT_REQUIRED
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.SysuiTestCase import com.android.systemui.SysuiTestCase
import com.android.systemui.controls.FakeControlsSettingsRepository
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.management.ControlsListingController import com.android.systemui.controls.management.ControlsListingController
import com.android.systemui.controls.ui.ControlsUiController import com.android.systemui.controls.ui.ControlsUiController
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 java.util.Optional import java.util.Optional
import org.junit.Assert.assertEquals import org.junit.Assert.assertEquals
@@ -63,13 +62,13 @@ class ControlsComponentTest : SysuiTestCase() {
@Mock @Mock
private lateinit var lockPatternUtils: LockPatternUtils private lateinit var lockPatternUtils: LockPatternUtils
@Mock @Mock
private lateinit var secureSettings: SecureSettings
@Mock
private lateinit var optionalControlsTileResourceConfiguration: private lateinit var optionalControlsTileResourceConfiguration:
Optional<ControlsTileResourceConfiguration> Optional<ControlsTileResourceConfiguration>
@Mock @Mock
private lateinit var controlsTileResourceConfiguration: ControlsTileResourceConfiguration private lateinit var controlsTileResourceConfiguration: ControlsTileResourceConfiguration
private lateinit var controlsSettingsRepository: FakeControlsSettingsRepository
companion object { companion object {
fun <T> eq(value: T): T = Mockito.eq(value) ?: value fun <T> eq(value: T): T = Mockito.eq(value) ?: value
} }
@@ -78,6 +77,8 @@ class ControlsComponentTest : SysuiTestCase() {
fun setUp() { fun setUp() {
MockitoAnnotations.initMocks(this) MockitoAnnotations.initMocks(this)
controlsSettingsRepository = FakeControlsSettingsRepository()
`when`(userTracker.userHandle.identifier).thenReturn(0) `when`(userTracker.userHandle.identifier).thenReturn(0)
`when`(optionalControlsTileResourceConfiguration.orElse(any())) `when`(optionalControlsTileResourceConfiguration.orElse(any()))
.thenReturn(controlsTileResourceConfiguration) .thenReturn(controlsTileResourceConfiguration)
@@ -125,8 +126,7 @@ class ControlsComponentTest : SysuiTestCase() {
`when`(lockPatternUtils.getStrongAuthForUser(anyInt())) `when`(lockPatternUtils.getStrongAuthForUser(anyInt()))
.thenReturn(STRONG_AUTH_NOT_REQUIRED) .thenReturn(STRONG_AUTH_NOT_REQUIRED)
`when`(keyguardStateController.isUnlocked()).thenReturn(false) `when`(keyguardStateController.isUnlocked()).thenReturn(false)
`when`(secureSettings.getInt(eq(Settings.Secure.LOCKSCREEN_SHOW_CONTROLS), anyInt())) controlsSettingsRepository.setCanShowControlsInLockscreen(false)
.thenReturn(0)
val component = setupComponent(true) val component = setupComponent(true)
assertEquals(ControlsComponent.Visibility.AVAILABLE_AFTER_UNLOCK, component.getVisibility()) assertEquals(ControlsComponent.Visibility.AVAILABLE_AFTER_UNLOCK, component.getVisibility())
@@ -137,9 +137,7 @@ class ControlsComponentTest : SysuiTestCase() {
`when`(lockPatternUtils.getStrongAuthForUser(anyInt())) `when`(lockPatternUtils.getStrongAuthForUser(anyInt()))
.thenReturn(STRONG_AUTH_NOT_REQUIRED) .thenReturn(STRONG_AUTH_NOT_REQUIRED)
`when`(keyguardStateController.isUnlocked()).thenReturn(false) `when`(keyguardStateController.isUnlocked()).thenReturn(false)
`when`(secureSettings.getIntForUser(eq(Settings.Secure.LOCKSCREEN_SHOW_CONTROLS), controlsSettingsRepository.setCanShowControlsInLockscreen(true)
anyInt(), anyInt()))
.thenReturn(1)
val component = setupComponent(true) val component = setupComponent(true)
assertEquals(ControlsComponent.Visibility.AVAILABLE, component.getVisibility()) assertEquals(ControlsComponent.Visibility.AVAILABLE, component.getVisibility())
@@ -147,8 +145,7 @@ class ControlsComponentTest : SysuiTestCase() {
@Test @Test
fun testFeatureEnabledAndCanShowWhileUnlockedVisibility() { fun testFeatureEnabledAndCanShowWhileUnlockedVisibility() {
`when`(secureSettings.getInt(eq(Settings.Secure.LOCKSCREEN_SHOW_CONTROLS), anyInt())) controlsSettingsRepository.setCanShowControlsInLockscreen(false)
.thenReturn(0)
`when`(lockPatternUtils.getStrongAuthForUser(anyInt())) `when`(lockPatternUtils.getStrongAuthForUser(anyInt()))
.thenReturn(STRONG_AUTH_NOT_REQUIRED) .thenReturn(STRONG_AUTH_NOT_REQUIRED)
`when`(keyguardStateController.isUnlocked()).thenReturn(true) `when`(keyguardStateController.isUnlocked()).thenReturn(true)
@@ -187,7 +184,7 @@ class ControlsComponentTest : SysuiTestCase() {
lockPatternUtils, lockPatternUtils,
keyguardStateController, keyguardStateController,
userTracker, userTracker,
secureSettings, controlsSettingsRepository,
optionalControlsTileResourceConfiguration optionalControlsTileResourceConfiguration
) )
} }