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:
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
@@ -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> {
|
||||
|
||||
@@ -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() {
|
||||
|
||||
Reference in New Issue
Block a user