Minor controls fixes

* Check setting for correct user
* Remove admin restriction
* Cache available setting in ControlsController
* Make activities exported=false
* Add settings listener

Test: manual
Test: atest ControlsControllerImplTesst
Bug: 147732882

Change-Id: I003ee3ea8f725d4da79729ce76816d4a1615fb0d
This commit is contained in:
Fabian Kozynski
2020-02-04 15:16:30 -05:00
parent 70ee4c46a6
commit 8b5404502d
6 changed files with 111 additions and 16 deletions

View File

@@ -645,7 +645,6 @@
<activity android:name=".controls.management.ControlsProviderSelectorActivity"
android:label="Controls Providers"
android:theme="@style/Theme.ControlsManagement"
android:exported="true"
android:showForAllUsers="true"
android:excludeFromRecents="true"
android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation|keyboard|keyboardHidden"

View File

@@ -19,9 +19,12 @@ package com.android.systemui.controls.controller
import android.app.PendingIntent
import android.content.BroadcastReceiver
import android.content.ComponentName
import android.content.ContentResolver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.database.ContentObserver
import android.net.Uri
import android.os.Environment
import android.os.UserHandle
import android.provider.Settings
@@ -30,6 +33,7 @@ import android.service.controls.actions.ControlAction
import android.util.ArrayMap
import android.util.Log
import com.android.internal.annotations.GuardedBy
import com.android.internal.annotations.VisibleForTesting
import com.android.systemui.DumpController
import com.android.systemui.Dumpable
import com.android.systemui.broadcast.BroadcastDispatcher
@@ -53,15 +57,16 @@ class ControlsControllerImpl @Inject constructor (
private val uiController: ControlsUiController,
private val bindingController: ControlsBindingController,
private val listingController: ControlsListingController,
broadcastDispatcher: BroadcastDispatcher,
private val broadcastDispatcher: BroadcastDispatcher,
optionalWrapper: Optional<ControlsFavoritePersistenceWrapper>,
dumpController: DumpController
) : Dumpable, ControlsController {
companion object {
private const val TAG = "ControlsControllerImpl"
const val CONTROLS_AVAILABLE = "systemui.controls_available"
const val USER_CHANGE_RETRY_DELAY = 500L // ms
internal const val CONTROLS_AVAILABLE = "systemui.controls_available"
internal val URI = Settings.Secure.getUriFor(CONTROLS_AVAILABLE)
private const val USER_CHANGE_RETRY_DELAY = 500L // ms
}
// Map of map: ComponentName -> (String -> ControlInfo).
@@ -69,9 +74,11 @@ class ControlsControllerImpl @Inject constructor (
@GuardedBy("currentFavorites")
private val currentFavorites = ArrayMap<ComponentName, MutableMap<String, ControlInfo>>()
private var userChanging = true
override var available = Settings.Secure.getInt(
context.contentResolver, CONTROLS_AVAILABLE, 0) != 0
private var userChanging: Boolean = true
private val contentResolver: ContentResolver
get() = context.contentResolver
override var available = Settings.Secure.getInt(contentResolver, CONTROLS_AVAILABLE, 0) != 0
private set
private var currentUser = context.user
@@ -95,8 +102,8 @@ class ControlsControllerImpl @Inject constructor (
val fileName = Environment.buildPath(
userContext.filesDir, ControlsFavoritePersistenceWrapper.FILE_NAME)
persistenceWrapper.changeFile(fileName)
available = Settings.Secure.getIntForUser(
context.contentResolver, CONTROLS_AVAILABLE, 0) != 0
available = Settings.Secure.getIntForUser(contentResolver, CONTROLS_AVAILABLE,
/* default */ 0, newUser.identifier) != 0
synchronized(currentFavorites) {
currentFavorites.clear()
}
@@ -123,6 +130,25 @@ class ControlsControllerImpl @Inject constructor (
}
}
@VisibleForTesting
internal val settingObserver = object : ContentObserver(null) {
override fun onChange(selfChange: Boolean, uri: Uri, userId: Int) {
// Do not listen to changes in the middle of user change, those will be read by the
// user-switch receiver.
if (userChanging || userId != currentUserId) {
return
}
available = Settings.Secure.getIntForUser(contentResolver, CONTROLS_AVAILABLE,
/* default */ 0, currentUserId) != 0
synchronized(currentFavorites) {
currentFavorites.clear()
}
if (available) {
loadFavorites()
}
}
}
init {
dumpController.registerDumpable(this)
if (available) {
@@ -135,6 +161,7 @@ class ControlsControllerImpl @Inject constructor (
executor,
UserHandle.ALL
)
contentResolver.registerContentObserver(URI, false, settingObserver, UserHandle.USER_ALL)
}
private fun confirmAvailability(): Boolean {

View File

@@ -22,6 +22,8 @@ import android.service.controls.actions.ControlAction
import android.view.ViewGroup
interface ControlsUiController {
val available: Boolean
fun show(parent: ViewGroup)
fun hide()
fun onRefreshState(componentName: ComponentName, controls: List<Control>)

View File

@@ -116,6 +116,9 @@ class ControlsUiControllerImpl @Inject constructor (
private val controlViewsById = mutableMapOf<String, ControlViewHolder>()
private lateinit var parent: ViewGroup
override val available: Boolean
get() = controlsController.get().available
override fun show(parent: ViewGroup) {
Log.d(TAG, "show()")

View File

@@ -1899,9 +1899,7 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener,
}
private boolean shouldShowControls() {
return isCurrentUserOwner()
&& !mKeyguardManager.isDeviceLocked()
&& Settings.Secure.getInt(mContext.getContentResolver(),
"systemui.controls_available", 0) == 1;
return !mKeyguardManager.isDeviceLocked()
&& mControlsUiController.getAvailable();
}
}

View File

@@ -32,12 +32,13 @@ import androidx.test.filters.SmallTest
import com.android.systemui.DumpController
import com.android.systemui.SysuiTestCase
import com.android.systemui.broadcast.BroadcastDispatcher
import com.android.systemui.controls.management.ControlsListingController
import com.android.systemui.controls.ControlStatus
import com.android.systemui.controls.management.ControlsListingController
import com.android.systemui.controls.ui.ControlsUiController
import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.time.FakeSystemClock
import org.junit.Assert.assertEquals
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
import org.junit.Before
import org.junit.Test
@@ -82,7 +83,7 @@ class ControlsControllerImplTest : SysuiTestCase() {
private lateinit var broadcastReceiverCaptor: ArgumentCaptor<BroadcastReceiver>
private lateinit var delayableExecutor: FakeExecutor
private lateinit var controller: ControlsController
private lateinit var controller: ControlsControllerImpl
companion object {
fun <T> capture(argumentCaptor: ArgumentCaptor<T>): T = argumentCaptor.capture()
@@ -416,5 +417,70 @@ class ControlsControllerImplTest : SysuiTestCase() {
verify(listingController).changeUser(UserHandle.of(otherUser))
assertTrue(controller.getFavoriteControls().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, ControlsControllerImpl.URI, 0)
assertFalse(controller.available)
}
@Test
fun testDisableFeature_clearFavorites() {
controller.changeFavoriteStatus(TEST_CONTROL_INFO, true)
assertFalse(controller.getFavoriteControls().isEmpty())
Settings.Secure.putIntForUser(mContext.contentResolver,
ControlsControllerImpl.CONTROLS_AVAILABLE, 0, user)
controller.settingObserver.onChange(false, ControlsControllerImpl.URI, user)
assertTrue(controller.getFavoriteControls().isEmpty())
}
@Test
fun testDisableFeature_noChangeForNotCurrentUser() {
controller.changeFavoriteStatus(TEST_CONTROL_INFO, true)
Settings.Secure.putIntForUser(mContext.contentResolver,
ControlsControllerImpl.CONTROLS_AVAILABLE, 0, otherUser)
controller.settingObserver.onChange(false, ControlsControllerImpl.URI, otherUser)
assertTrue(controller.available)
assertFalse(controller.getFavoriteControls().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
fun testCountFavoritesForComponent_singleComponent() {
controller.changeFavoriteStatus(TEST_CONTROL_INFO, true)
assertEquals(1, controller.countFavoritesForComponent(TEST_COMPONENT))
assertEquals(0, controller.countFavoritesForComponent(TEST_COMPONENT_2))
}
@Test
fun testCountFavoritesForComponent_multipleComponents() {
controller.changeFavoriteStatus(TEST_CONTROL_INFO, true)
controller.changeFavoriteStatus(TEST_CONTROL_INFO_2, true)
assertEquals(1, controller.countFavoritesForComponent(TEST_COMPONENT))
assertEquals(1, controller.countFavoritesForComponent(TEST_COMPONENT_2))
}
}