Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f1b8e7a9 authored by Fabian Kozynski's avatar Fabian Kozynski
Browse files

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
parent ae6c0cf5
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -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.
     *
+37 −13
Original line number Diff line number Diff line
@@ -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,6 +100,19 @@ 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
            updateServices(newServices)
        }
    }

    init {
        Log.d(TAG, "Initializing")
        dumpManager.registerDumpable(TAG, this)
        serviceListing.addCallback(serviceListingCallback)
        serviceListing.setListening(true)
        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 {
@@ -110,15 +126,6 @@ class ControlsListingControllerImpl @VisibleForTesting constructor(
            }
        }
    }
    }

    init {
        Log.d(TAG, "Initializing")
        dumpManager.registerDumpable(TAG, this)
        serviceListing.addCallback(serviceListingCallback)
        serviceListing.setListening(true)
        serviceListing.reload()
    }

    override fun changeUser(newUser: UserHandle) {
        userChangeInProgress.incrementAndGet()
@@ -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.
     *
+4 −1
Original line number Diff line number Diff line
@@ -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()
    }
+86 −3
Original line number Diff line number Diff line
@@ -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> {
+28 −10
Original line number Diff line number Diff line
@@ -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() {