Loading packages/SystemUI/src/com/android/systemui/qs/pipeline/data/repository/InstalledTilesComponentRepository.kt +20 −5 Original line number Diff line number Diff line Loading @@ -51,12 +51,26 @@ class InstalledTilesComponentRepositoryImpl @Inject constructor( @Application private val applicationContext: Context, private val packageManager: PackageManager, @Background private val backgroundDispatcher: CoroutineDispatcher, ) : InstalledTilesComponentRepository { override fun getInstalledTilesComponents(userId: Int): Flow<Set<ComponentName>> = conflatedCallbackFlow { override fun getInstalledTilesComponents(userId: Int): Flow<Set<ComponentName>> { /* * In order to query [PackageManager] for different users, this implementation will call * [Context.createContextAsUser] and retrieve the [PackageManager] from that context. */ val packageManager = if (applicationContext.userId == userId) { applicationContext.packageManager } else { applicationContext .createContextAsUser( UserHandle.of(userId), /* flags */ 0, ) .packageManager } return conflatedCallbackFlow { val receiver = object : BroadcastReceiver() { override fun onReceive(context: Context?, intent: Intent?) { Loading @@ -74,12 +88,13 @@ constructor( awaitClose { applicationContext.unregisterReceiver(receiver) } } .onStart { emit(Unit) } .map { reloadComponents(userId) } .map { reloadComponents(userId, packageManager) } .distinctUntilChanged() .flowOn(backgroundDispatcher) } @WorkerThread private fun reloadComponents(userId: Int): Set<ComponentName> { private fun reloadComponents(userId: Int, packageManager: PackageManager): Set<ComponentName> { return packageManager .queryIntentServicesAsUser(INTENT, FLAGS, userId) .mapNotNull { it.serviceInfo } Loading packages/SystemUI/src/com/android/systemui/util/kotlin/PackageManagerExt.kt +7 −0 Original line number Diff line number Diff line Loading @@ -16,12 +16,19 @@ package com.android.systemui.util.kotlin import android.annotation.UserHandleAware import android.annotation.WorkerThread import android.content.pm.ComponentInfo import android.content.pm.PackageManager import com.android.systemui.util.Assert /** * Determines whether a component is actually enabled (not just its default value). * * @throws IllegalArgumentException if the component is not found */ @WorkerThread @UserHandleAware fun PackageManager.isComponentActuallyEnabled(componentInfo: ComponentInfo): Boolean { Assert.isNotMainThread() return when (getComponentEnabledSetting(componentInfo.componentName)) { Loading packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/data/repository/InstalledTilesComponentRepositoryImplTest.kt +50 −1 Original line number Diff line number Diff line Loading @@ -38,6 +38,7 @@ import com.android.systemui.util.mockito.argThat import com.android.systemui.util.mockito.argumentCaptor import com.android.systemui.util.mockito.capture import com.android.systemui.util.mockito.eq import com.android.systemui.util.mockito.mock import com.android.systemui.util.mockito.nullable import com.android.systemui.util.mockito.whenever import com.google.common.truth.Truth.assertThat Loading Loading @@ -75,6 +76,9 @@ class InstalledTilesComponentRepositoryImplTest : SysuiTestCase() { fun setUp() { MockitoAnnotations.initMocks(this) whenever(context.createContextAsUser(any(), anyInt())).thenReturn(context) whenever(context.packageManager).thenReturn(packageManager) // Use the default value set in the ServiceInfo whenever(packageManager.getComponentEnabledSetting(any())) .thenReturn(PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) Loading @@ -86,7 +90,6 @@ class InstalledTilesComponentRepositoryImplTest : SysuiTestCase() { underTest = InstalledTilesComponentRepositoryImpl( context, packageManager, testDispatcher, ) } Loading Loading @@ -224,6 +227,52 @@ class InstalledTilesComponentRepositoryImplTest : SysuiTestCase() { assertThat(componentNames).isEmpty() } @Test fun packageOnlyInSecondaryUser_noException() = testScope.runTest { val userId = 10 val secondaryUserContext: Context = mock() whenever(context.userId).thenReturn(0) // System context whenever(context.createContextAsUser(eq(UserHandle.of(userId)), anyInt())) .thenReturn(secondaryUserContext) val secondaryUserPackageManager: PackageManager = mock() whenever(secondaryUserContext.packageManager).thenReturn(secondaryUserPackageManager) // Use the default value set in the ServiceInfo whenever(secondaryUserPackageManager.getComponentEnabledSetting(any())) .thenReturn(PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) // System User package manager throws exception if the component doesn't exist for that // user whenever(packageManager.getComponentEnabledSetting(TEST_COMPONENT)) .thenThrow(IllegalArgumentException()) // The package is not in the system user val resolveInfo = ResolveInfo(TEST_COMPONENT, hasPermission = true, defaultEnabled = true) // Both package manager should return the same (because the query is for the secondary // user) whenever( secondaryUserPackageManager.queryIntentServicesAsUser( matchIntent(), matchFlags(), eq(userId) ) ) .thenReturn(listOf(resolveInfo)) whenever( packageManager.queryIntentServicesAsUser( matchIntent(), matchFlags(), eq(userId) ) ) .thenReturn(listOf(resolveInfo)) val componentNames by collectLastValue(underTest.getInstalledTilesComponents(userId)) assertThat(componentNames).containsExactly(TEST_COMPONENT) } private fun getRegisteredReceiver(): BroadcastReceiver { verify(context) .registerReceiverAsUser( Loading Loading
packages/SystemUI/src/com/android/systemui/qs/pipeline/data/repository/InstalledTilesComponentRepository.kt +20 −5 Original line number Diff line number Diff line Loading @@ -51,12 +51,26 @@ class InstalledTilesComponentRepositoryImpl @Inject constructor( @Application private val applicationContext: Context, private val packageManager: PackageManager, @Background private val backgroundDispatcher: CoroutineDispatcher, ) : InstalledTilesComponentRepository { override fun getInstalledTilesComponents(userId: Int): Flow<Set<ComponentName>> = conflatedCallbackFlow { override fun getInstalledTilesComponents(userId: Int): Flow<Set<ComponentName>> { /* * In order to query [PackageManager] for different users, this implementation will call * [Context.createContextAsUser] and retrieve the [PackageManager] from that context. */ val packageManager = if (applicationContext.userId == userId) { applicationContext.packageManager } else { applicationContext .createContextAsUser( UserHandle.of(userId), /* flags */ 0, ) .packageManager } return conflatedCallbackFlow { val receiver = object : BroadcastReceiver() { override fun onReceive(context: Context?, intent: Intent?) { Loading @@ -74,12 +88,13 @@ constructor( awaitClose { applicationContext.unregisterReceiver(receiver) } } .onStart { emit(Unit) } .map { reloadComponents(userId) } .map { reloadComponents(userId, packageManager) } .distinctUntilChanged() .flowOn(backgroundDispatcher) } @WorkerThread private fun reloadComponents(userId: Int): Set<ComponentName> { private fun reloadComponents(userId: Int, packageManager: PackageManager): Set<ComponentName> { return packageManager .queryIntentServicesAsUser(INTENT, FLAGS, userId) .mapNotNull { it.serviceInfo } Loading
packages/SystemUI/src/com/android/systemui/util/kotlin/PackageManagerExt.kt +7 −0 Original line number Diff line number Diff line Loading @@ -16,12 +16,19 @@ package com.android.systemui.util.kotlin import android.annotation.UserHandleAware import android.annotation.WorkerThread import android.content.pm.ComponentInfo import android.content.pm.PackageManager import com.android.systemui.util.Assert /** * Determines whether a component is actually enabled (not just its default value). * * @throws IllegalArgumentException if the component is not found */ @WorkerThread @UserHandleAware fun PackageManager.isComponentActuallyEnabled(componentInfo: ComponentInfo): Boolean { Assert.isNotMainThread() return when (getComponentEnabledSetting(componentInfo.componentName)) { Loading
packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/data/repository/InstalledTilesComponentRepositoryImplTest.kt +50 −1 Original line number Diff line number Diff line Loading @@ -38,6 +38,7 @@ import com.android.systemui.util.mockito.argThat import com.android.systemui.util.mockito.argumentCaptor import com.android.systemui.util.mockito.capture import com.android.systemui.util.mockito.eq import com.android.systemui.util.mockito.mock import com.android.systemui.util.mockito.nullable import com.android.systemui.util.mockito.whenever import com.google.common.truth.Truth.assertThat Loading Loading @@ -75,6 +76,9 @@ class InstalledTilesComponentRepositoryImplTest : SysuiTestCase() { fun setUp() { MockitoAnnotations.initMocks(this) whenever(context.createContextAsUser(any(), anyInt())).thenReturn(context) whenever(context.packageManager).thenReturn(packageManager) // Use the default value set in the ServiceInfo whenever(packageManager.getComponentEnabledSetting(any())) .thenReturn(PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) Loading @@ -86,7 +90,6 @@ class InstalledTilesComponentRepositoryImplTest : SysuiTestCase() { underTest = InstalledTilesComponentRepositoryImpl( context, packageManager, testDispatcher, ) } Loading Loading @@ -224,6 +227,52 @@ class InstalledTilesComponentRepositoryImplTest : SysuiTestCase() { assertThat(componentNames).isEmpty() } @Test fun packageOnlyInSecondaryUser_noException() = testScope.runTest { val userId = 10 val secondaryUserContext: Context = mock() whenever(context.userId).thenReturn(0) // System context whenever(context.createContextAsUser(eq(UserHandle.of(userId)), anyInt())) .thenReturn(secondaryUserContext) val secondaryUserPackageManager: PackageManager = mock() whenever(secondaryUserContext.packageManager).thenReturn(secondaryUserPackageManager) // Use the default value set in the ServiceInfo whenever(secondaryUserPackageManager.getComponentEnabledSetting(any())) .thenReturn(PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) // System User package manager throws exception if the component doesn't exist for that // user whenever(packageManager.getComponentEnabledSetting(TEST_COMPONENT)) .thenThrow(IllegalArgumentException()) // The package is not in the system user val resolveInfo = ResolveInfo(TEST_COMPONENT, hasPermission = true, defaultEnabled = true) // Both package manager should return the same (because the query is for the secondary // user) whenever( secondaryUserPackageManager.queryIntentServicesAsUser( matchIntent(), matchFlags(), eq(userId) ) ) .thenReturn(listOf(resolveInfo)) whenever( packageManager.queryIntentServicesAsUser( matchIntent(), matchFlags(), eq(userId) ) ) .thenReturn(listOf(resolveInfo)) val componentNames by collectLastValue(underTest.getInstalledTilesComponents(userId)) assertThat(componentNames).containsExactly(TEST_COMPONENT) } private fun getRegisteredReceiver(): BroadcastReceiver { verify(context) .registerReceiverAsUser( Loading