Remove "Device Controls" from Settings

Both device controls and wallet have moved to new areas outside of the
power menu. In step 1, we are deprecating the device controls settings,
as the user can now fully control availability within the new Quick
Settings device controls tile.

Bug: 185597511
Test: atest ControlsControllerImplTest ControlsComponentTest DeviceControlsTileTest ControlsRequestDialogTest
Change-Id: Ifdbb83dfd35263d62c9fd3dc67699769f9c9f408
This commit is contained in:
Matt Pietal
2021-04-19 12:48:37 -04:00
parent 0dd99e0c3c
commit 73702413f8
15 changed files with 62 additions and 137 deletions

View File

@@ -9428,9 +9428,12 @@ public final class Settings {
* 0 indicates disabled and 1 indicates enabled. A non existent value should be treated as
* enabled.
*
* @deprecated Controls are migrated to Quick Settings, rendering this unnecessary and will
* be removed in a future release.
* @hide
*/
@Readable
@Deprecated
public static final String CONTROLS_ENABLED = "controls_enabled";
/**

View File

@@ -40,11 +40,6 @@ import java.util.function.Consumer
*/
interface ControlsController : UserAwareController {
/**
* Whether the controls system is available for the current user.
*/
val available: Boolean
// SERVICE COMMUNICATION
/**

View File

@@ -28,7 +28,6 @@ import android.database.ContentObserver
import android.net.Uri
import android.os.Environment
import android.os.UserHandle
import android.provider.Settings
import android.service.controls.Control
import android.service.controls.actions.ControlAction
import android.util.ArrayMap
@@ -70,15 +69,10 @@ class ControlsControllerImpl @Inject constructor (
companion object {
private const val TAG = "ControlsControllerImpl"
internal const val CONTROLS_AVAILABLE = Settings.Secure.CONTROLS_ENABLED
internal val URI = Settings.Secure.getUriFor(CONTROLS_AVAILABLE)
private const val USER_CHANGE_RETRY_DELAY = 500L // ms
private const val DEFAULT_ENABLED = 1
private const val PERMISSION_SELF = "com.android.systemui.permission.SELF"
const val SUGGESTED_CONTROLS_PER_STRUCTURE = 6
private fun isAvailable(userId: Int, cr: ContentResolver) = Settings.Secure.getIntForUser(
cr, CONTROLS_AVAILABLE, DEFAULT_ENABLED, userId) != 0
}
private var userChanging: Boolean = true
@@ -93,8 +87,6 @@ class ControlsControllerImpl @Inject constructor (
private val contentResolver: ContentResolver
get() = context.contentResolver
override var available = isAvailable(currentUserId, contentResolver)
private set
private val persistenceWrapper: ControlsFavoritePersistenceWrapper
@VisibleForTesting
@@ -126,8 +118,7 @@ class ControlsControllerImpl @Inject constructor (
BackupManager(userStructure.userContext)
)
auxiliaryPersistenceWrapper.changeFile(userStructure.auxiliaryFile)
available = isAvailable(newUser.identifier, contentResolver)
resetFavorites(available)
resetFavorites()
bindingController.changeUser(newUser)
listingController.changeUser(newUser)
userChanging = false
@@ -157,7 +148,7 @@ class ControlsControllerImpl @Inject constructor (
Log.d(TAG, "Restore finished, storing auxiliary favorites")
auxiliaryPersistenceWrapper.initialize()
persistenceWrapper.storeFavorites(auxiliaryPersistenceWrapper.favorites)
resetFavorites(available)
resetFavorites()
}
}
}
@@ -176,8 +167,7 @@ class ControlsControllerImpl @Inject constructor (
if (userChanging || userId != currentUserId) {
return
}
available = isAvailable(currentUserId, contentResolver)
resetFavorites(available)
resetFavorites()
}
}
@@ -242,7 +232,7 @@ class ControlsControllerImpl @Inject constructor (
init {
dumpManager.registerDumpable(javaClass.name, this)
resetFavorites(available)
resetFavorites()
userChanging = false
broadcastDispatcher.registerReceiver(
userSwitchReceiver,
@@ -256,23 +246,18 @@ class ControlsControllerImpl @Inject constructor (
PERMISSION_SELF,
null
)
contentResolver.registerContentObserver(URI, false, settingObserver, UserHandle.USER_ALL)
listingController.addCallback(listingCallback)
}
fun destroy() {
broadcastDispatcher.unregisterReceiver(userSwitchReceiver)
context.unregisterReceiver(restoreFinishedReceiver)
contentResolver.unregisterContentObserver(settingObserver)
listingController.removeCallback(listingCallback)
}
private fun resetFavorites(shouldLoad: Boolean) {
private fun resetFavorites() {
Favorites.clear()
if (shouldLoad) {
Favorites.load(persistenceWrapper.readFavorites())
}
Favorites.load(persistenceWrapper.readFavorites())
}
private fun confirmAvailability(): Boolean {
@@ -280,10 +265,6 @@ class ControlsControllerImpl @Inject constructor (
Log.w(TAG, "Controls not available while user is changing")
return false
}
if (!available) {
Log.d(TAG, "Controls not available")
return false
}
return true
}
@@ -577,7 +558,6 @@ class ControlsControllerImpl @Inject constructor (
override fun dump(fd: FileDescriptor, pw: PrintWriter, args: Array<out String>) {
pw.println("ControlsController state:")
pw.println(" Available: $available")
pw.println(" Changing users: $userChanging")
pw.println(" Current user: ${currentUser.identifier}")
pw.println(" Favorites:")

View File

@@ -93,7 +93,7 @@ class ControlsComponent @Inject constructor(
/**
* @return true if controls are feature-enabled and the user has the setting enabled
*/
fun isEnabled() = featureEnabled && lazyControlsController.get().available
fun isEnabled() = featureEnabled
/**
* Returns one of 3 states:

View File

@@ -71,10 +71,7 @@ open class ControlsRequestDialog @Inject constructor(
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
if (!controller.available) {
Log.w(TAG, "Quick Controls not available for this user ")
finish()
}
currentUserTracker.startTracking()
controlsListingController.addCallback(callback)

View File

@@ -23,8 +23,6 @@ import android.service.controls.actions.ControlAction
import android.view.ViewGroup
interface ControlsUiController {
val available: Boolean
companion object {
public const val TAG = "ControlsUiController"
public const val EXTRA_ANIMATE = "extra_animate"

View File

@@ -128,9 +128,6 @@ class ControlsUiControllerImpl @Inject constructor (
reload(parent)
}
override val available: Boolean
get() = controlsController.get().available
private lateinit var activityContext: Context
private lateinit var listingCallback: ControlsListingController.ControlsListingCallback

View File

@@ -16,6 +16,7 @@ package com.android.systemui.statusbar.phone;
import static com.android.systemui.qs.dagger.QSFlagsModule.RBC_AVAILABLE;
import android.annotation.Nullable;
import android.content.Context;
import android.content.res.Resources;
import android.hardware.display.ColorDisplayManager;
@@ -294,9 +295,11 @@ public class AutoTileManager implements UserAwareController {
private final DeviceControlsController.Callback mDeviceControlsCallback =
new DeviceControlsController.Callback() {
@Override
public void onControlsAvailable(int position) {
public void onControlsUpdate(@Nullable Integer position) {
if (mAutoTracker.isAdded(DEVICE_CONTROLS)) return;
mHost.addTile(DEVICE_CONTROLS, position);
if (position != null) {
mHost.addTile(DEVICE_CONTROLS, position);
}
mAutoTracker.setTileAdded(DEVICE_CONTROLS);
mHandler.post(() -> mDeviceControlsController.removeCallback());
}

View File

@@ -24,7 +24,7 @@ interface DeviceControlsController {
/**
* If controls become available, initiate this callback with the desired position
*/
fun onControlsAvailable(position: Int)
fun onControlsUpdate(position: Int?)
}
/** Add callback, supporting only a single callback at once */

View File

@@ -19,6 +19,7 @@ package com.android.systemui.statusbar.policy
import android.content.ComponentName
import android.content.Context
import android.content.SharedPreferences
import android.provider.Settings
import android.util.Log
import com.android.systemui.R
@@ -29,6 +30,7 @@ import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.qs.QSTileHost.POSITION_AT_END
import com.android.systemui.settings.UserContextProvider
import com.android.systemui.statusbar.policy.DeviceControlsController.Callback
import com.android.systemui.util.settings.SecureSettings
import javax.inject.Inject
@@ -45,7 +47,8 @@ import javax.inject.Inject
public class DeviceControlsControllerImpl @Inject constructor(
private val context: Context,
private val controlsComponent: ControlsComponent,
private val userContextProvider: UserContextProvider
private val userContextProvider: UserContextProvider,
private val secureSettings: SecureSettings
) : DeviceControlsController {
private var callback: Callback? = null
@@ -73,6 +76,7 @@ public class DeviceControlsControllerImpl @Inject constructor(
controlsComponent.getControlsController().ifPresent {
if (!it.getFavorites().isEmpty()) {
position = QS_PRIORITY_POSITION
fireControlsUpdate()
}
}
}
@@ -80,20 +84,22 @@ public class DeviceControlsControllerImpl @Inject constructor(
/**
* This migration logic assumes that something like [AutoTileManager] is tracking state
* externally, and won't call this method after receiving a response via
* [Callback#onControlsAvailable], once per user. Otherwise the calculated position may be
* [Callback#onControlsUpdate], once per user. Otherwise the calculated position may be
* incorrect.
*/
override fun setCallback(callback: Callback) {
// Treat any additional call as a reset before recalculating
removeCallback()
checkMigrationToQs()
controlsComponent.getControlsListingController().ifPresent {
it.addCallback(listingCallback)
}
this.callback = callback
fireControlsAvailable()
if (secureSettings.getInt(Settings.Secure.CONTROLS_ENABLED, 1) == 0) {
fireControlsUpdate()
} else {
checkMigrationToQs()
controlsComponent.getControlsListingController().ifPresent {
it.addCallback(listingCallback)
}
}
}
override fun removeCallback() {
@@ -104,11 +110,9 @@ public class DeviceControlsControllerImpl @Inject constructor(
}
}
private fun fireControlsAvailable() {
position?.let {
Log.i(TAG, "Setting DeviceControlsTile position: $it")
callback?.onControlsAvailable(it)
}
private fun fireControlsUpdate() {
Log.i(TAG, "Setting DeviceControlsTile position: $position")
callback?.onControlsUpdate(position)
}
/**
@@ -155,7 +159,7 @@ public class DeviceControlsControllerImpl @Inject constructor(
if (position == null) {
position = QS_DEFAULT_POSITION
}
fireControlsAvailable()
fireControlsUpdate()
controlsComponent.getControlsListingController().ifPresent {
it.removeCallback(listingCallback)

View File

@@ -24,7 +24,6 @@ import android.content.ContextWrapper
import android.content.Intent
import android.content.pm.ServiceInfo
import android.os.UserHandle
import android.provider.Settings
import android.service.controls.Control
import android.service.controls.DeviceTypes
import android.service.controls.actions.ControlAction
@@ -141,11 +140,6 @@ class ControlsControllerImplTest : SysuiTestCase() {
fun setUp() {
MockitoAnnotations.initMocks(this)
Settings.Secure.putInt(mContext.contentResolver,
ControlsControllerImpl.CONTROLS_AVAILABLE, 1)
Settings.Secure.putIntForUser(mContext.contentResolver,
ControlsControllerImpl.CONTROLS_AVAILABLE, 1, otherUser)
`when`(userTracker.userHandle).thenReturn(UserHandle.of(user))
delayableExecutor = FakeExecutor(FakeSystemClock())
@@ -172,7 +166,6 @@ class ControlsControllerImplTest : SysuiTestCase() {
)
controller.auxiliaryPersistenceWrapper = auxiliaryPersistenceWrapper
assertTrue(controller.available)
verify(broadcastDispatcher).registerReceiver(
capture(broadcastReceiverCaptor), any(), any(), eq(UserHandle.ALL))
@@ -527,58 +520,6 @@ class ControlsControllerImplTest : SysuiTestCase() {
verify(listingController).changeUser(UserHandle.of(otherUser))
assertTrue(controller.getFavorites().isEmpty())
assertEquals(otherUser, controller.currentUserId)
assertTrue(controller.available)
}
@Test
fun testDisableFeature_notAvailable() {
Settings.Secure.putIntForUser(mContext.contentResolver,
ControlsControllerImpl.CONTROLS_AVAILABLE, 0, user)
controller.settingObserver.onChange(false, listOf(ControlsControllerImpl.URI), 0, 0)
assertFalse(controller.available)
}
@Test
fun testDisableFeature_clearFavorites() {
controller.replaceFavoritesForStructure(TEST_STRUCTURE_INFO)
delayableExecutor.runAllReady()
assertFalse(controller.getFavorites().isEmpty())
Settings.Secure.putIntForUser(mContext.contentResolver,
ControlsControllerImpl.CONTROLS_AVAILABLE, 0, user)
controller.settingObserver.onChange(false, listOf(ControlsControllerImpl.URI), 0, user)
assertTrue(controller.getFavorites().isEmpty())
}
@Test
fun testDisableFeature_noChangeForNotCurrentUser() {
controller.replaceFavoritesForStructure(TEST_STRUCTURE_INFO)
delayableExecutor.runAllReady()
Settings.Secure.putIntForUser(mContext.contentResolver,
ControlsControllerImpl.CONTROLS_AVAILABLE, 0, otherUser)
controller.settingObserver.onChange(false, listOf(ControlsControllerImpl.URI), 0, otherUser)
assertTrue(controller.available)
assertFalse(controller.getFavorites().isEmpty())
}
@Test
fun testCorrectUserSettingOnUserChange() {
Settings.Secure.putIntForUser(mContext.contentResolver,
ControlsControllerImpl.CONTROLS_AVAILABLE, 0, otherUser)
val intent = Intent(Intent.ACTION_USER_SWITCHED).apply {
putExtra(Intent.EXTRA_USER_HANDLE, otherUser)
}
val pendingResult = mock(BroadcastReceiver.PendingResult::class.java)
`when`(pendingResult.sendingUserId).thenReturn(otherUser)
broadcastReceiverCaptor.value.pendingResult = pendingResult
broadcastReceiverCaptor.value.onReceive(mContext, intent)
assertFalse(controller.available)
}
@Test

View File

@@ -103,7 +103,6 @@ class ControlsComponentTest : SysuiTestCase() {
@Test
fun testFeatureEnabledAfterBootVisibility() {
`when`(controller.available).thenReturn(true)
`when`(lockPatternUtils.getStrongAuthForUser(anyInt()))
.thenReturn(STRONG_AUTH_REQUIRED_AFTER_BOOT)
val component = setupComponent(true)
@@ -113,7 +112,6 @@ class ControlsComponentTest : SysuiTestCase() {
@Test
fun testFeatureEnabledAndCannotShowOnLockScreenVisibility() {
`when`(controller.available).thenReturn(true)
`when`(lockPatternUtils.getStrongAuthForUser(anyInt()))
.thenReturn(STRONG_AUTH_NOT_REQUIRED)
`when`(keyguardStateController.isUnlocked()).thenReturn(false)
@@ -126,7 +124,6 @@ class ControlsComponentTest : SysuiTestCase() {
@Test
fun testFeatureEnabledAndCanShowOnLockScreenVisibility() {
`when`(controller.available).thenReturn(true)
`when`(lockPatternUtils.getStrongAuthForUser(anyInt()))
.thenReturn(STRONG_AUTH_NOT_REQUIRED)
`when`(keyguardStateController.isUnlocked()).thenReturn(false)
@@ -141,7 +138,6 @@ class ControlsComponentTest : SysuiTestCase() {
fun testFeatureEnabledAndCanShowWhileUnlockedVisibility() {
`when`(secureSettings.getInt(eq(Settings.Secure.POWER_MENU_LOCKED_SHOW_CONTENT), anyInt()))
.thenReturn(0)
`when`(controller.available).thenReturn(true)
`when`(lockPatternUtils.getStrongAuthForUser(anyInt()))
.thenReturn(STRONG_AUTH_NOT_REQUIRED)
`when`(keyguardStateController.isUnlocked()).thenReturn(true)

View File

@@ -110,7 +110,6 @@ class ControlsRequestDialogTest : SysuiTestCase() {
intent.putExtra(ControlsProviderService.EXTRA_CONTROL, control)
`when`(controller.currentUserId).thenReturn(USER_ID)
`when`(controller.available).thenReturn(true)
`when`(listingController.getAppLabel(CONTROL_COMPONENT)).thenReturn(LABEL)
`when`(controller.getFavoritesForComponent(CONTROL_COMPONENT)).thenReturn(emptyList())
@@ -142,4 +141,4 @@ class ControlsRequestDialogTest : SysuiTestCase() {
assertEquals(control.deviceType, it.deviceType)
}
}
}
}

View File

@@ -105,7 +105,6 @@ class DeviceControlsTileTest : SysuiTestCase() {
doNothing().`when`(spiedContext).startActivity(any(Intent::class.java))
`when`(qsHost.context).thenReturn(spiedContext)
`when`(qsHost.uiEventLogger).thenReturn(uiEventLogger)
`when`(controlsController.available).thenReturn(true)
`when`(controlsComponent.isEnabled()).thenReturn(true)
secureSettings.putInt(Settings.Secure.POWER_MENU_LOCKED_SHOW_CONTENT, 1)
@@ -153,14 +152,6 @@ class DeviceControlsTileTest : SysuiTestCase() {
assertThat(tile.isAvailable).isFalse()
}
@Test
fun testAvailableControlsSettingOff() {
`when`(controlsController.available).thenReturn(false)
tile = createTile()
assertThat(tile.isAvailable).isTrue()
}
@Test
fun testObservingCallback() {
verify(controlsListingController).observe(

View File

@@ -19,6 +19,7 @@ package com.android.systemui.statusbar.policy
import android.content.ComponentName
import android.content.Context
import android.content.pm.ServiceInfo
import android.provider.Settings
import android.testing.AndroidTestingRunner
import androidx.test.filters.SmallTest
@@ -37,6 +38,7 @@ import com.android.systemui.statusbar.policy.DeviceControlsControllerImpl.Compan
import com.android.systemui.statusbar.policy.DeviceControlsControllerImpl.Companion.PREFS_CONTROLS_SEEDING_COMPLETED
import com.android.systemui.statusbar.policy.DeviceControlsControllerImpl.Companion.QS_DEFAULT_POSITION
import com.android.systemui.statusbar.policy.DeviceControlsControllerImpl.Companion.QS_PRIORITY_POSITION
import com.android.systemui.util.settings.SecureSettings
import java.util.Optional
import java.util.function.Consumer
@@ -55,6 +57,7 @@ import org.mockito.Mockito.times
import org.mockito.Mockito.verify
import org.mockito.Mockito.`when`
import org.mockito.ArgumentMatchers.anyInt
import org.mockito.ArgumentMatchers.anyObject
@SmallTest
@RunWith(AndroidTestingRunner::class)
@@ -76,6 +79,8 @@ class DeviceControlsControllerImplTest : SysuiTestCase() {
private lateinit var serviceInfo: ServiceInfo
@Mock
private lateinit var userContextProvider: UserContextProvider
@Mock
private lateinit var secureSettings: SecureSettings
@Captor
private lateinit var seedCallback: ArgumentCaptor<Consumer<SeedResponse>>
@@ -98,7 +103,14 @@ class DeviceControlsControllerImplTest : SysuiTestCase() {
`when`(controlsComponent.getControlsListingController())
.thenReturn(Optional.of(controlsListingController))
controller = DeviceControlsControllerImpl(mContext, controlsComponent, userContextProvider)
controller = DeviceControlsControllerImpl(
mContext,
controlsComponent,
userContextProvider,
secureSettings
)
`when`(secureSettings.getInt(Settings.Secure.CONTROLS_ENABLED, 1)).thenReturn(1)
`when`(serviceInfo.componentName).thenReturn(TEST_COMPONENT)
controlsServiceInfo = ControlsServiceInfo(mContext, serviceInfo)
@@ -116,7 +128,16 @@ class DeviceControlsControllerImplTest : SysuiTestCase() {
verify(controlsListingController).addCallback(capture(listingCallbackCaptor))
listingCallbackCaptor.value.onServicesUpdated(emptyList())
verify(callback, never()).onControlsAvailable(anyInt())
verify(callback, never()).onControlsUpdate(anyInt())
}
@Test
fun testCallbackWithNullValueWhenSettingIsDisabled() {
`when`(secureSettings.getInt(Settings.Secure.CONTROLS_ENABLED, 1)).thenReturn(0)
controller.setCallback(callback)
verify(controlsListingController, never()).addCallback(anyObject())
verify(callback).onControlsUpdate(null)
}
@Test
@@ -126,7 +147,7 @@ class DeviceControlsControllerImplTest : SysuiTestCase() {
verify(controlsListingController).addCallback(capture(listingCallbackCaptor))
listingCallbackCaptor.value.onServicesUpdated(listOf(controlsServiceInfo))
verify(callback).onControlsAvailable(QS_PRIORITY_POSITION)
verify(callback).onControlsUpdate(QS_PRIORITY_POSITION)
}
@Test
@@ -146,6 +167,6 @@ class DeviceControlsControllerImplTest : SysuiTestCase() {
capture(seedCallback)
)
seedCallback.value.accept(SeedResponse(TEST_PKG, true))
verify(callback).onControlsAvailable(QS_DEFAULT_POSITION)
verify(callback).onControlsUpdate(QS_DEFAULT_POSITION)
}
}