Force reload listings for ControlsStartable

This makes sure that by the time ControlsStartable needs to know about
the services, they have been fetched at least once. The call to
ControlsListingController#forceReload should happen in the background
thread.

Fixes: 271289611
Test: atest ControlsListingControllerImplTest
Test: atest ControlsStartableTest
Test: manual, adb shell dumpsys activity services
Change-Id: Ia6228854dbbc426cc50ef0626efc29ee3ac7bf44
This commit is contained in:
Fabian Kozynski
2023-03-02 13:03:10 -05:00
parent ae6c0cf5da
commit f1b8e7a94c
5 changed files with 159 additions and 27 deletions

View File

@@ -16,6 +16,7 @@
package com.android.systemui.controls.management
import android.annotation.WorkerThread
import android.content.ComponentName
import com.android.systemui.controls.ControlsServiceInfo
import com.android.systemui.util.UserAwareController
@@ -33,6 +34,9 @@ interface ControlsListingController :
*/
fun getCurrentServices(): List<ControlsServiceInfo>
@WorkerThread
fun forceReload()
/**
* Get the app label for a given component.
*

View File

@@ -16,8 +16,11 @@
package com.android.systemui.controls.management
import android.annotation.WorkerThread
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.os.UserHandle
import android.service.controls.ControlsProviderService
import android.util.Log
@@ -65,7 +68,7 @@ class ControlsListingControllerImpl @VisibleForTesting constructor(
private val serviceListingBuilder: (Context) -> ServiceListing,
private val userTracker: UserTracker,
dumpManager: DumpManager,
featureFlags: FeatureFlags
private val featureFlags: FeatureFlags
) : ControlsListingController, Dumpable {
@Inject
@@ -97,18 +100,7 @@ class ControlsListingControllerImpl @VisibleForTesting constructor(
// After here, `list` is not captured, so we don't risk modifying it outside of the callback
backgroundExecutor.execute {
if (userChangeInProgress.get() > 0) return@execute
if (featureFlags.isEnabled(Flags.USE_APP_PANELS)) {
val allowAllApps = featureFlags.isEnabled(Flags.APP_PANELS_ALL_APPS_ALLOWED)
newServices.forEach {
it.resolvePanelActivity(allowAllApps) }
}
if (newServices != availableServices) {
availableServices = newServices
callbacks.forEach {
it.onServicesUpdated(getCurrentServices())
}
}
updateServices(newServices)
}
}
@@ -120,6 +112,21 @@ class ControlsListingControllerImpl @VisibleForTesting constructor(
serviceListing.reload()
}
private fun updateServices(newServices: List<ControlsServiceInfo>) {
if (featureFlags.isEnabled(Flags.USE_APP_PANELS)) {
val allowAllApps = featureFlags.isEnabled(Flags.APP_PANELS_ALL_APPS_ALLOWED)
newServices.forEach {
it.resolvePanelActivity(allowAllApps) }
}
if (newServices != availableServices) {
availableServices = newServices
callbacks.forEach {
it.onServicesUpdated(getCurrentServices())
}
}
}
override fun changeUser(newUser: UserHandle) {
userChangeInProgress.incrementAndGet()
serviceListing.setListening(false)
@@ -178,6 +185,23 @@ class ControlsListingControllerImpl @VisibleForTesting constructor(
override fun getCurrentServices(): List<ControlsServiceInfo> =
availableServices.map(ControlsServiceInfo::copy)
@WorkerThread
override fun forceReload() {
val packageManager = context.packageManager
val intent = Intent(ControlsProviderService.SERVICE_CONTROLS)
val user = userTracker.userHandle
val flags = PackageManager.GET_SERVICES or
PackageManager.GET_META_DATA or
PackageManager.MATCH_DIRECT_BOOT_UNAWARE or
PackageManager.MATCH_DIRECT_BOOT_AWARE
val services = packageManager.queryIntentServicesAsUser(
intent,
PackageManager.ResolveInfoFlags.of(flags.toLong()),
user
).map { ControlsServiceInfo(userTracker.userContext, it.serviceInfo) }
updateServices(services)
}
/**
* Get the localized label for the component.
*

View File

@@ -19,6 +19,7 @@ package com.android.systemui.controls.start
import android.content.Context
import android.os.UserHandle
import androidx.annotation.WorkerThread
import com.android.systemui.CoreStartable
import com.android.systemui.controls.controller.ControlsController
import com.android.systemui.controls.dagger.ControlsComponent
@@ -75,11 +76,13 @@ constructor(
// Controls is disabled, we don't need this anymore
return
}
startForUser()
executor.execute(this::startForUser)
userTracker.addCallback(userTrackerCallback, executor)
}
@WorkerThread
private fun startForUser() {
controlsListingController.forceReload()
selectDefaultPanelIfNecessary()
bindToPanel()
}

View File

@@ -45,6 +45,8 @@ import com.android.systemui.util.mockito.argThat
import com.android.systemui.util.mockito.capture
import com.android.systemui.util.mockito.eq
import com.android.systemui.util.time.FakeSystemClock
import com.google.common.truth.Truth.assertThat
import java.util.concurrent.Executor
import org.junit.After
import org.junit.Assert.assertEquals
import org.junit.Assert.assertNull
@@ -62,7 +64,6 @@ import org.mockito.Mockito.never
import org.mockito.Mockito.reset
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
import java.util.concurrent.Executor
@SmallTest
@RunWith(AndroidTestingRunner::class)
@@ -106,6 +107,7 @@ class ControlsListingControllerImplTest : SysuiTestCase() {
MockitoAnnotations.initMocks(this)
`when`(userTracker.userId).thenReturn(user)
`when`(userTracker.userHandle).thenReturn(UserHandle.of(user))
`when`(userTracker.userContext).thenReturn(context)
// Return disabled by default
`when`(packageManager.getComponentEnabledSetting(any()))
@@ -564,6 +566,79 @@ class ControlsListingControllerImplTest : SysuiTestCase() {
assertTrue(controller.getCurrentServices().isEmpty())
}
@Test
fun testForceReloadQueriesPackageManager() {
val user = 10
`when`(userTracker.userHandle).thenReturn(UserHandle.of(user))
controller.forceReload()
verify(packageManager).queryIntentServicesAsUser(
argThat(IntentMatcherAction(ControlsProviderService.SERVICE_CONTROLS)),
argThat(FlagsMatcher(
PackageManager.GET_META_DATA.toLong() or
PackageManager.GET_SERVICES.toLong() or
PackageManager.MATCH_DIRECT_BOOT_AWARE.toLong() or
PackageManager.MATCH_DIRECT_BOOT_UNAWARE.toLong()
)),
eq(UserHandle.of(user))
)
}
@Test
fun testForceReloadUpdatesList() {
val resolveInfo = ResolveInfo()
resolveInfo.serviceInfo = ServiceInfo(componentName)
`when`(packageManager.queryIntentServicesAsUser(
argThat(IntentMatcherAction(ControlsProviderService.SERVICE_CONTROLS)),
argThat(FlagsMatcher(
PackageManager.GET_META_DATA.toLong() or
PackageManager.GET_SERVICES.toLong() or
PackageManager.MATCH_DIRECT_BOOT_AWARE.toLong() or
PackageManager.MATCH_DIRECT_BOOT_UNAWARE.toLong()
)),
any<UserHandle>()
)).thenReturn(listOf(resolveInfo))
controller.forceReload()
val services = controller.getCurrentServices()
assertThat(services.size).isEqualTo(1)
assertThat(services[0].serviceInfo.componentName).isEqualTo(componentName)
}
@Test
fun testForceReloadCallsListeners() {
controller.addCallback(mockCallback)
executor.runAllReady()
@Suppress("unchecked_cast")
val captor: ArgumentCaptor<List<ControlsServiceInfo>> =
ArgumentCaptor.forClass(List::class.java)
as ArgumentCaptor<List<ControlsServiceInfo>>
val resolveInfo = ResolveInfo()
resolveInfo.serviceInfo = ServiceInfo(componentName)
`when`(packageManager.queryIntentServicesAsUser(
any(),
any<PackageManager.ResolveInfoFlags>(),
any<UserHandle>()
)).thenReturn(listOf(resolveInfo))
reset(mockCallback)
controller.forceReload()
verify(mockCallback).onServicesUpdated(capture(captor))
val services = captor.value
assertThat(services.size).isEqualTo(1)
assertThat(services[0].serviceInfo.componentName).isEqualTo(componentName)
}
private fun ServiceInfo(
componentName: ComponentName,
panelActivityComponentName: ComponentName? = null
@@ -600,7 +675,7 @@ class ControlsListingControllerImplTest : SysuiTestCase() {
private fun setUpQueryResult(infos: List<ActivityInfo>) {
`when`(
packageManager.queryIntentActivitiesAsUser(
argThat(IntentMatcher(activityName)),
argThat(IntentMatcherComponent(activityName)),
argThat(FlagsMatcher(FLAGS)),
eq(UserHandle.of(user))
)
@@ -609,7 +684,7 @@ class ControlsListingControllerImplTest : SysuiTestCase() {
})
}
private class IntentMatcher(
private class IntentMatcherComponent(
private val componentName: ComponentName
) : ArgumentMatcher<Intent> {
override fun matches(argument: Intent?): Boolean {
@@ -617,6 +692,14 @@ class ControlsListingControllerImplTest : SysuiTestCase() {
}
}
private class IntentMatcherAction(
private val action: String
) : ArgumentMatcher<Intent> {
override fun matches(argument: Intent?): Boolean {
return argument?.action == action
}
}
private class FlagsMatcher(
private val flags: Long
) : ArgumentMatcher<PackageManager.ResolveInfoFlags> {

View File

@@ -42,6 +42,8 @@ import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mock
import org.mockito.Mockito.doAnswer
import org.mockito.Mockito.doReturn
import org.mockito.Mockito.never
import org.mockito.Mockito.verify
import org.mockito.Mockito.verifyZeroInteractions
@@ -80,9 +82,10 @@ class ControlsStartableTest : SysuiTestCase() {
fun testNoPreferredPackagesNoDefaultSelected_noNewSelection() {
`when`(controlsController.getPreferredSelection()).thenReturn(SelectedItem.EMPTY_SELECTION)
val listings = listOf(ControlsServiceInfo(TEST_COMPONENT_PANEL, "panel", hasPanel = true))
`when`(controlsListingController.getCurrentServices()).thenReturn(listings)
setUpControlsListingControls(listings)
createStartable(enabled = true).start()
fakeExecutor.runAllReady()
verify(controlsController, never()).setPreferredSelection(any())
}
@@ -92,9 +95,10 @@ class ControlsStartableTest : SysuiTestCase() {
whenever(authorizedPanelsRepository.getPreferredPackages())
.thenReturn(setOf(TEST_PACKAGE_PANEL))
`when`(controlsController.getPreferredSelection()).thenReturn(SelectedItem.EMPTY_SELECTION)
`when`(controlsListingController.getCurrentServices()).thenReturn(emptyList())
setUpControlsListingControls(emptyList())
createStartable(enabled = true).start()
fakeExecutor.runAllReady()
verify(controlsController, never()).setPreferredSelection(any())
}
@@ -105,9 +109,10 @@ class ControlsStartableTest : SysuiTestCase() {
.thenReturn(setOf(TEST_PACKAGE_PANEL))
`when`(controlsController.getPreferredSelection()).thenReturn(SelectedItem.EMPTY_SELECTION)
val listings = listOf(ControlsServiceInfo(TEST_COMPONENT, "not panel", hasPanel = false))
`when`(controlsListingController.getCurrentServices()).thenReturn(listings)
setUpControlsListingControls(listings)
createStartable(enabled = true).start()
fakeExecutor.runAllReady()
verify(controlsController, never()).setPreferredSelection(any())
}
@@ -119,9 +124,10 @@ class ControlsStartableTest : SysuiTestCase() {
`when`(controlsController.getPreferredSelection())
.thenReturn(mock<SelectedItem.PanelItem>())
val listings = listOf(ControlsServiceInfo(TEST_COMPONENT_PANEL, "panel", hasPanel = true))
`when`(controlsListingController.getCurrentServices()).thenReturn(listings)
setUpControlsListingControls(listings)
createStartable(enabled = true).start()
fakeExecutor.runAllReady()
verify(controlsController, never()).setPreferredSelection(any())
}
@@ -132,9 +138,10 @@ class ControlsStartableTest : SysuiTestCase() {
.thenReturn(setOf(TEST_PACKAGE_PANEL))
`when`(controlsController.getPreferredSelection()).thenReturn(SelectedItem.EMPTY_SELECTION)
val listings = listOf(ControlsServiceInfo(TEST_COMPONENT_PANEL, "panel", hasPanel = true))
`when`(controlsListingController.getCurrentServices()).thenReturn(listings)
setUpControlsListingControls(listings)
createStartable(enabled = true).start()
fakeExecutor.runAllReady()
verify(controlsController).setPreferredSelection(listings[0].toPanelItem())
}
@@ -149,9 +156,10 @@ class ControlsStartableTest : SysuiTestCase() {
ControlsServiceInfo(TEST_COMPONENT_PANEL, "panel", hasPanel = true),
ControlsServiceInfo(ComponentName("other_package", "cls"), "non panel", false)
)
`when`(controlsListingController.getCurrentServices()).thenReturn(listings)
setUpControlsListingControls(listings)
createStartable(enabled = true).start()
fakeExecutor.runAllReady()
verify(controlsController).setPreferredSelection(listings[0].toPanelItem())
}
@@ -166,9 +174,10 @@ class ControlsStartableTest : SysuiTestCase() {
ControlsServiceInfo(ComponentName("other_package", "cls"), "panel", true),
ControlsServiceInfo(TEST_COMPONENT_PANEL, "panel", hasPanel = true)
)
`when`(controlsListingController.getCurrentServices()).thenReturn(listings)
setUpControlsListingControls(listings)
createStartable(enabled = true).start()
fakeExecutor.runAllReady()
verify(controlsController).setPreferredSelection(listings[1].toPanelItem())
}
@@ -176,10 +185,11 @@ class ControlsStartableTest : SysuiTestCase() {
@Test
fun testPreferredSelectionIsPanel_bindOnStart() {
val listings = listOf(ControlsServiceInfo(TEST_COMPONENT_PANEL, "panel", hasPanel = true))
`when`(controlsListingController.getCurrentServices()).thenReturn(listings)
setUpControlsListingControls(listings)
`when`(controlsController.getPreferredSelection()).thenReturn(listings[0].toPanelItem())
createStartable(enabled = true).start()
fakeExecutor.runAllReady()
verify(controlsController).bindComponentForPanel(TEST_COMPONENT_PANEL)
}
@@ -187,11 +197,12 @@ class ControlsStartableTest : SysuiTestCase() {
@Test
fun testPreferredSelectionPanel_listingNoPanel_notBind() {
val listings = listOf(ControlsServiceInfo(TEST_COMPONENT_PANEL, "panel", hasPanel = false))
`when`(controlsListingController.getCurrentServices()).thenReturn(listings)
setUpControlsListingControls(listings)
`when`(controlsController.getPreferredSelection())
.thenReturn(SelectedItem.PanelItem("panel", TEST_COMPONENT_PANEL))
createStartable(enabled = true).start()
fakeExecutor.runAllReady()
verify(controlsController, never()).bindComponentForPanel(any())
}
@@ -199,10 +210,11 @@ class ControlsStartableTest : SysuiTestCase() {
@Test
fun testNotPanelSelection_noBind() {
val listings = listOf(ControlsServiceInfo(TEST_COMPONENT_PANEL, "panel", hasPanel = false))
`when`(controlsListingController.getCurrentServices()).thenReturn(listings)
setUpControlsListingControls(listings)
`when`(controlsController.getPreferredSelection()).thenReturn(SelectedItem.EMPTY_SELECTION)
createStartable(enabled = true).start()
fakeExecutor.runAllReady()
verify(controlsController, never()).bindComponentForPanel(any())
}
@@ -221,6 +233,12 @@ class ControlsStartableTest : SysuiTestCase() {
verify(controlsController, never()).setPreferredSelection(any())
}
private fun setUpControlsListingControls(listings: List<ControlsServiceInfo>) {
doAnswer { doReturn(listings).`when`(controlsListingController).getCurrentServices() }
.`when`(controlsListingController)
.forceReload()
}
private fun createStartable(enabled: Boolean): ControlsStartable {
val component: ControlsComponent =
mock() {