Loading packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/data/repository/InstalledTilesComponentRepositoryImplTest.kt +12 −86 Original line number Original line Diff line number Diff line Loading @@ -17,11 +17,9 @@ package com.android.systemui.qs.pipeline.data.repository package com.android.systemui.qs.pipeline.data.repository import android.Manifest.permission.BIND_QUICK_SETTINGS_TILE import android.Manifest.permission.BIND_QUICK_SETTINGS_TILE import android.content.BroadcastReceiver import android.content.ComponentName import android.content.ComponentName import android.content.Context import android.content.Context import android.content.Intent import android.content.Intent import android.content.IntentFilter import android.content.pm.ApplicationInfo import android.content.pm.ApplicationInfo import android.content.pm.PackageManager import android.content.pm.PackageManager import android.content.pm.PackageManager.ResolveInfoFlags import android.content.pm.PackageManager.ResolveInfoFlags Loading @@ -33,44 +31,36 @@ import android.testing.TestableLooper import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.SysuiTestCase import com.android.systemui.common.data.repository.fakePackageChangeRepository import com.android.systemui.common.data.repository.packageChangeRepository import com.android.systemui.common.data.shared.model.PackageChangeModel import com.android.systemui.coroutines.collectLastValue import com.android.systemui.coroutines.collectLastValue import com.android.systemui.kosmos.testDispatcher import com.android.systemui.kosmos.testScope import com.android.systemui.testKosmos import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.argThat 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.eq import com.android.systemui.util.mockito.mock import com.android.systemui.util.mockito.mock import com.android.systemui.util.mockito.nullable import com.android.systemui.util.mockito.whenever import com.android.systemui.util.mockito.whenever import com.google.common.truth.Truth.assertThat import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.launch import kotlinx.coroutines.test.StandardTestDispatcher import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.runCurrent import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest import org.junit.Before import org.junit.Before import org.junit.Test import org.junit.Test import org.junit.runner.RunWith import org.junit.runner.RunWith import org.mockito.ArgumentCaptor import org.mockito.ArgumentMatchers.anyInt import org.mockito.ArgumentMatchers.anyInt import org.mockito.Captor import org.mockito.Mock import org.mockito.Mock import org.mockito.Mockito.never import org.mockito.Mockito.verify import org.mockito.MockitoAnnotations import org.mockito.MockitoAnnotations @SmallTest @SmallTest @RunWith(AndroidJUnit4::class) @RunWith(AndroidJUnit4::class) @TestableLooper.RunWithLooper @TestableLooper.RunWithLooper @OptIn(ExperimentalCoroutinesApi::class) class InstalledTilesComponentRepositoryImplTest : SysuiTestCase() { class InstalledTilesComponentRepositoryImplTest : SysuiTestCase() { private val testDispatcher = StandardTestDispatcher() private val kosmos = testKosmos() private val testScope = TestScope(testDispatcher) private val testScope = kosmos.testScope @Mock private lateinit var context: Context @Mock private lateinit var context: Context @Mock private lateinit var packageManager: PackageManager @Mock private lateinit var packageManager: PackageManager @Captor private lateinit var receiverCaptor: ArgumentCaptor<BroadcastReceiver> private lateinit var underTest: InstalledTilesComponentRepositoryImpl private lateinit var underTest: InstalledTilesComponentRepositoryImpl Loading @@ -92,62 +82,11 @@ class InstalledTilesComponentRepositoryImplTest : SysuiTestCase() { underTest = underTest = InstalledTilesComponentRepositoryImpl( InstalledTilesComponentRepositoryImpl( context, context, testDispatcher, kosmos.testDispatcher, kosmos.packageChangeRepository ) ) } } @Test fun registersAndUnregistersBroadcastReceiver() = testScope.runTest { val user = 10 val job = launch { underTest.getInstalledTilesComponents(user).collect {} } runCurrent() verify(context) .registerReceiverAsUser( capture(receiverCaptor), eq(UserHandle.of(user)), any(), nullable(), nullable(), ) verify(context, never()).unregisterReceiver(receiverCaptor.value) job.cancel() runCurrent() verify(context).unregisterReceiver(receiverCaptor.value) } @Test fun intentFilterForCorrectActionsAndScheme() = testScope.runTest { val filterCaptor = argumentCaptor<IntentFilter>() backgroundScope.launch { underTest.getInstalledTilesComponents(0).collect {} } runCurrent() verify(context) .registerReceiverAsUser( any(), any(), capture(filterCaptor), nullable(), nullable(), ) with(filterCaptor.value) { assertThat(matchAction(Intent.ACTION_PACKAGE_CHANGED)).isTrue() assertThat(matchAction(Intent.ACTION_PACKAGE_ADDED)).isTrue() assertThat(matchAction(Intent.ACTION_PACKAGE_REMOVED)).isTrue() assertThat(matchAction(Intent.ACTION_PACKAGE_REPLACED)).isTrue() assertThat(countActions()).isEqualTo(4) assertThat(hasDataScheme("package")).isTrue() assertThat(countDataSchemes()).isEqualTo(1) } } @Test @Test fun componentsLoadedOnStart() = fun componentsLoadedOnStart() = testScope.runTest { testScope.runTest { Loading @@ -169,7 +108,7 @@ class InstalledTilesComponentRepositoryImplTest : SysuiTestCase() { } } @Test @Test fun componentAdded_foundAfterBroadcast() = fun componentAdded_foundAfterPackageChange() = testScope.runTest { testScope.runTest { val userId = 0 val userId = 0 val resolveInfo = val resolveInfo = Loading @@ -186,7 +125,7 @@ class InstalledTilesComponentRepositoryImplTest : SysuiTestCase() { ) ) ) ) .thenReturn(listOf(resolveInfo)) .thenReturn(listOf(resolveInfo)) getRegisteredReceiver().onReceive(context, Intent(Intent.ACTION_PACKAGE_ADDED)) kosmos.fakePackageChangeRepository.notifyChange(PackageChangeModel.Empty) assertThat(componentNames).containsExactly(TEST_COMPONENT) assertThat(componentNames).containsExactly(TEST_COMPONENT) } } Loading Loading @@ -275,19 +214,6 @@ class InstalledTilesComponentRepositoryImplTest : SysuiTestCase() { assertThat(componentNames).containsExactly(TEST_COMPONENT) assertThat(componentNames).containsExactly(TEST_COMPONENT) } } private fun getRegisteredReceiver(): BroadcastReceiver { verify(context) .registerReceiverAsUser( capture(receiverCaptor), any(), any(), nullable(), nullable(), ) return receiverCaptor.value } companion object { companion object { private val INTENT = Intent(TileService.ACTION_QS_TILE) private val INTENT = Intent(TileService.ACTION_QS_TILE) private val FLAGS = private val FLAGS = Loading packages/SystemUI/src/com/android/systemui/common/data/repository/PackageUpdateLogger.kt +1 −0 Original line number Original line Diff line number Diff line Loading @@ -31,6 +31,7 @@ private fun getChangeString(model: PackageChangeModel) = is PackageChangeModel.UpdateStarted -> "started updating" is PackageChangeModel.UpdateStarted -> "started updating" is PackageChangeModel.UpdateFinished -> "finished updating" is PackageChangeModel.UpdateFinished -> "finished updating" is PackageChangeModel.Changed -> "changed" is PackageChangeModel.Changed -> "changed" is PackageChangeModel.Empty -> throw IllegalStateException("Unexpected empty value: $model") } } /** A debug logger for [PackageChangeRepository]. */ /** A debug logger for [PackageChangeRepository]. */ Loading packages/SystemUI/src/com/android/systemui/common/data/shared/model/PackageChangeModel.kt +8 −0 Original line number Original line Diff line number Diff line Loading @@ -23,6 +23,14 @@ sealed interface PackageChangeModel { val packageName: String val packageName: String val packageUid: Int val packageUid: Int /** Empty change, provided for convenience when a sensible default value is needed. */ data object Empty : PackageChangeModel { override val packageName: String get() = "" override val packageUid: Int get() = 0 } /** /** * An existing application package was uninstalled. * An existing application package was uninstalled. * * Loading packages/SystemUI/src/com/android/systemui/qs/pipeline/data/repository/InstalledTilesComponentRepository.kt +6 −30 Original line number Original line Diff line number Diff line Loading @@ -18,23 +18,21 @@ package com.android.systemui.qs.pipeline.data.repository import android.Manifest.permission.BIND_QUICK_SETTINGS_TILE import android.Manifest.permission.BIND_QUICK_SETTINGS_TILE import android.annotation.WorkerThread import android.annotation.WorkerThread import android.content.BroadcastReceiver import android.content.ComponentName import android.content.ComponentName import android.content.Context import android.content.Context import android.content.Intent import android.content.Intent import android.content.IntentFilter import android.content.pm.PackageManager import android.content.pm.PackageManager import android.content.pm.PackageManager.ResolveInfoFlags import android.content.pm.PackageManager.ResolveInfoFlags import android.os.UserHandle import android.os.UserHandle import android.service.quicksettings.TileService import android.service.quicksettings.TileService import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow import com.android.systemui.common.data.repository.PackageChangeRepository import com.android.systemui.common.data.shared.model.PackageChangeModel import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.util.kotlin.isComponentActuallyEnabled import com.android.systemui.util.kotlin.isComponentActuallyEnabled import javax.inject.Inject import javax.inject.Inject import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.flowOn Loading @@ -52,6 +50,7 @@ class InstalledTilesComponentRepositoryImpl constructor( constructor( @Application private val applicationContext: Context, @Application private val applicationContext: Context, @Background private val backgroundDispatcher: CoroutineDispatcher, @Background private val backgroundDispatcher: CoroutineDispatcher, private val packageChangeRepository: PackageChangeRepository ) : InstalledTilesComponentRepository { ) : InstalledTilesComponentRepository { override fun getInstalledTilesComponents(userId: Int): Flow<Set<ComponentName>> { override fun getInstalledTilesComponents(userId: Int): Flow<Set<ComponentName>> { Loading @@ -70,24 +69,9 @@ constructor( ) ) .packageManager .packageManager } } return conflatedCallbackFlow { return packageChangeRepository val receiver = .packageChanged(UserHandle.of(userId)) object : BroadcastReceiver() { .onStart { emit(PackageChangeModel.Empty) } override fun onReceive(context: Context?, intent: Intent?) { trySend(Unit) } } applicationContext.registerReceiverAsUser( receiver, UserHandle.of(userId), INTENT_FILTER, /* broadcastPermission = */ null, /* scheduler = */ null ) awaitClose { applicationContext.unregisterReceiver(receiver) } } .onStart { emit(Unit) } .map { reloadComponents(userId, packageManager) } .map { reloadComponents(userId, packageManager) } .distinctUntilChanged() .distinctUntilChanged() .flowOn(backgroundDispatcher) .flowOn(backgroundDispatcher) Loading @@ -104,14 +88,6 @@ constructor( } } companion object { companion object { private val INTENT_FILTER = IntentFilter().apply { addAction(Intent.ACTION_PACKAGE_ADDED) addAction(Intent.ACTION_PACKAGE_CHANGED) addAction(Intent.ACTION_PACKAGE_REMOVED) addAction(Intent.ACTION_PACKAGE_REPLACED) addDataScheme("package") } private val INTENT = Intent(TileService.ACTION_QS_TILE) private val INTENT = Intent(TileService.ACTION_QS_TILE) private val FLAGS = private val FLAGS = ResolveInfoFlags.of( ResolveInfoFlags.of( Loading Loading
packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/data/repository/InstalledTilesComponentRepositoryImplTest.kt +12 −86 Original line number Original line Diff line number Diff line Loading @@ -17,11 +17,9 @@ package com.android.systemui.qs.pipeline.data.repository package com.android.systemui.qs.pipeline.data.repository import android.Manifest.permission.BIND_QUICK_SETTINGS_TILE import android.Manifest.permission.BIND_QUICK_SETTINGS_TILE import android.content.BroadcastReceiver import android.content.ComponentName import android.content.ComponentName import android.content.Context import android.content.Context import android.content.Intent import android.content.Intent import android.content.IntentFilter import android.content.pm.ApplicationInfo import android.content.pm.ApplicationInfo import android.content.pm.PackageManager import android.content.pm.PackageManager import android.content.pm.PackageManager.ResolveInfoFlags import android.content.pm.PackageManager.ResolveInfoFlags Loading @@ -33,44 +31,36 @@ import android.testing.TestableLooper import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.SysuiTestCase import com.android.systemui.common.data.repository.fakePackageChangeRepository import com.android.systemui.common.data.repository.packageChangeRepository import com.android.systemui.common.data.shared.model.PackageChangeModel import com.android.systemui.coroutines.collectLastValue import com.android.systemui.coroutines.collectLastValue import com.android.systemui.kosmos.testDispatcher import com.android.systemui.kosmos.testScope import com.android.systemui.testKosmos import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.argThat 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.eq import com.android.systemui.util.mockito.mock import com.android.systemui.util.mockito.mock import com.android.systemui.util.mockito.nullable import com.android.systemui.util.mockito.whenever import com.android.systemui.util.mockito.whenever import com.google.common.truth.Truth.assertThat import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.launch import kotlinx.coroutines.test.StandardTestDispatcher import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.runCurrent import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest import org.junit.Before import org.junit.Before import org.junit.Test import org.junit.Test import org.junit.runner.RunWith import org.junit.runner.RunWith import org.mockito.ArgumentCaptor import org.mockito.ArgumentMatchers.anyInt import org.mockito.ArgumentMatchers.anyInt import org.mockito.Captor import org.mockito.Mock import org.mockito.Mock import org.mockito.Mockito.never import org.mockito.Mockito.verify import org.mockito.MockitoAnnotations import org.mockito.MockitoAnnotations @SmallTest @SmallTest @RunWith(AndroidJUnit4::class) @RunWith(AndroidJUnit4::class) @TestableLooper.RunWithLooper @TestableLooper.RunWithLooper @OptIn(ExperimentalCoroutinesApi::class) class InstalledTilesComponentRepositoryImplTest : SysuiTestCase() { class InstalledTilesComponentRepositoryImplTest : SysuiTestCase() { private val testDispatcher = StandardTestDispatcher() private val kosmos = testKosmos() private val testScope = TestScope(testDispatcher) private val testScope = kosmos.testScope @Mock private lateinit var context: Context @Mock private lateinit var context: Context @Mock private lateinit var packageManager: PackageManager @Mock private lateinit var packageManager: PackageManager @Captor private lateinit var receiverCaptor: ArgumentCaptor<BroadcastReceiver> private lateinit var underTest: InstalledTilesComponentRepositoryImpl private lateinit var underTest: InstalledTilesComponentRepositoryImpl Loading @@ -92,62 +82,11 @@ class InstalledTilesComponentRepositoryImplTest : SysuiTestCase() { underTest = underTest = InstalledTilesComponentRepositoryImpl( InstalledTilesComponentRepositoryImpl( context, context, testDispatcher, kosmos.testDispatcher, kosmos.packageChangeRepository ) ) } } @Test fun registersAndUnregistersBroadcastReceiver() = testScope.runTest { val user = 10 val job = launch { underTest.getInstalledTilesComponents(user).collect {} } runCurrent() verify(context) .registerReceiverAsUser( capture(receiverCaptor), eq(UserHandle.of(user)), any(), nullable(), nullable(), ) verify(context, never()).unregisterReceiver(receiverCaptor.value) job.cancel() runCurrent() verify(context).unregisterReceiver(receiverCaptor.value) } @Test fun intentFilterForCorrectActionsAndScheme() = testScope.runTest { val filterCaptor = argumentCaptor<IntentFilter>() backgroundScope.launch { underTest.getInstalledTilesComponents(0).collect {} } runCurrent() verify(context) .registerReceiverAsUser( any(), any(), capture(filterCaptor), nullable(), nullable(), ) with(filterCaptor.value) { assertThat(matchAction(Intent.ACTION_PACKAGE_CHANGED)).isTrue() assertThat(matchAction(Intent.ACTION_PACKAGE_ADDED)).isTrue() assertThat(matchAction(Intent.ACTION_PACKAGE_REMOVED)).isTrue() assertThat(matchAction(Intent.ACTION_PACKAGE_REPLACED)).isTrue() assertThat(countActions()).isEqualTo(4) assertThat(hasDataScheme("package")).isTrue() assertThat(countDataSchemes()).isEqualTo(1) } } @Test @Test fun componentsLoadedOnStart() = fun componentsLoadedOnStart() = testScope.runTest { testScope.runTest { Loading @@ -169,7 +108,7 @@ class InstalledTilesComponentRepositoryImplTest : SysuiTestCase() { } } @Test @Test fun componentAdded_foundAfterBroadcast() = fun componentAdded_foundAfterPackageChange() = testScope.runTest { testScope.runTest { val userId = 0 val userId = 0 val resolveInfo = val resolveInfo = Loading @@ -186,7 +125,7 @@ class InstalledTilesComponentRepositoryImplTest : SysuiTestCase() { ) ) ) ) .thenReturn(listOf(resolveInfo)) .thenReturn(listOf(resolveInfo)) getRegisteredReceiver().onReceive(context, Intent(Intent.ACTION_PACKAGE_ADDED)) kosmos.fakePackageChangeRepository.notifyChange(PackageChangeModel.Empty) assertThat(componentNames).containsExactly(TEST_COMPONENT) assertThat(componentNames).containsExactly(TEST_COMPONENT) } } Loading Loading @@ -275,19 +214,6 @@ class InstalledTilesComponentRepositoryImplTest : SysuiTestCase() { assertThat(componentNames).containsExactly(TEST_COMPONENT) assertThat(componentNames).containsExactly(TEST_COMPONENT) } } private fun getRegisteredReceiver(): BroadcastReceiver { verify(context) .registerReceiverAsUser( capture(receiverCaptor), any(), any(), nullable(), nullable(), ) return receiverCaptor.value } companion object { companion object { private val INTENT = Intent(TileService.ACTION_QS_TILE) private val INTENT = Intent(TileService.ACTION_QS_TILE) private val FLAGS = private val FLAGS = Loading
packages/SystemUI/src/com/android/systemui/common/data/repository/PackageUpdateLogger.kt +1 −0 Original line number Original line Diff line number Diff line Loading @@ -31,6 +31,7 @@ private fun getChangeString(model: PackageChangeModel) = is PackageChangeModel.UpdateStarted -> "started updating" is PackageChangeModel.UpdateStarted -> "started updating" is PackageChangeModel.UpdateFinished -> "finished updating" is PackageChangeModel.UpdateFinished -> "finished updating" is PackageChangeModel.Changed -> "changed" is PackageChangeModel.Changed -> "changed" is PackageChangeModel.Empty -> throw IllegalStateException("Unexpected empty value: $model") } } /** A debug logger for [PackageChangeRepository]. */ /** A debug logger for [PackageChangeRepository]. */ Loading
packages/SystemUI/src/com/android/systemui/common/data/shared/model/PackageChangeModel.kt +8 −0 Original line number Original line Diff line number Diff line Loading @@ -23,6 +23,14 @@ sealed interface PackageChangeModel { val packageName: String val packageName: String val packageUid: Int val packageUid: Int /** Empty change, provided for convenience when a sensible default value is needed. */ data object Empty : PackageChangeModel { override val packageName: String get() = "" override val packageUid: Int get() = 0 } /** /** * An existing application package was uninstalled. * An existing application package was uninstalled. * * Loading
packages/SystemUI/src/com/android/systemui/qs/pipeline/data/repository/InstalledTilesComponentRepository.kt +6 −30 Original line number Original line Diff line number Diff line Loading @@ -18,23 +18,21 @@ package com.android.systemui.qs.pipeline.data.repository import android.Manifest.permission.BIND_QUICK_SETTINGS_TILE import android.Manifest.permission.BIND_QUICK_SETTINGS_TILE import android.annotation.WorkerThread import android.annotation.WorkerThread import android.content.BroadcastReceiver import android.content.ComponentName import android.content.ComponentName import android.content.Context import android.content.Context import android.content.Intent import android.content.Intent import android.content.IntentFilter import android.content.pm.PackageManager import android.content.pm.PackageManager import android.content.pm.PackageManager.ResolveInfoFlags import android.content.pm.PackageManager.ResolveInfoFlags import android.os.UserHandle import android.os.UserHandle import android.service.quicksettings.TileService import android.service.quicksettings.TileService import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow import com.android.systemui.common.data.repository.PackageChangeRepository import com.android.systemui.common.data.shared.model.PackageChangeModel import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.util.kotlin.isComponentActuallyEnabled import com.android.systemui.util.kotlin.isComponentActuallyEnabled import javax.inject.Inject import javax.inject.Inject import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.flowOn Loading @@ -52,6 +50,7 @@ class InstalledTilesComponentRepositoryImpl constructor( constructor( @Application private val applicationContext: Context, @Application private val applicationContext: Context, @Background private val backgroundDispatcher: CoroutineDispatcher, @Background private val backgroundDispatcher: CoroutineDispatcher, private val packageChangeRepository: PackageChangeRepository ) : InstalledTilesComponentRepository { ) : InstalledTilesComponentRepository { override fun getInstalledTilesComponents(userId: Int): Flow<Set<ComponentName>> { override fun getInstalledTilesComponents(userId: Int): Flow<Set<ComponentName>> { Loading @@ -70,24 +69,9 @@ constructor( ) ) .packageManager .packageManager } } return conflatedCallbackFlow { return packageChangeRepository val receiver = .packageChanged(UserHandle.of(userId)) object : BroadcastReceiver() { .onStart { emit(PackageChangeModel.Empty) } override fun onReceive(context: Context?, intent: Intent?) { trySend(Unit) } } applicationContext.registerReceiverAsUser( receiver, UserHandle.of(userId), INTENT_FILTER, /* broadcastPermission = */ null, /* scheduler = */ null ) awaitClose { applicationContext.unregisterReceiver(receiver) } } .onStart { emit(Unit) } .map { reloadComponents(userId, packageManager) } .map { reloadComponents(userId, packageManager) } .distinctUntilChanged() .distinctUntilChanged() .flowOn(backgroundDispatcher) .flowOn(backgroundDispatcher) Loading @@ -104,14 +88,6 @@ constructor( } } companion object { companion object { private val INTENT_FILTER = IntentFilter().apply { addAction(Intent.ACTION_PACKAGE_ADDED) addAction(Intent.ACTION_PACKAGE_CHANGED) addAction(Intent.ACTION_PACKAGE_REMOVED) addAction(Intent.ACTION_PACKAGE_REPLACED) addDataScheme("package") } private val INTENT = Intent(TileService.ACTION_QS_TILE) private val INTENT = Intent(TileService.ACTION_QS_TILE) private val FLAGS = private val FLAGS = ResolveInfoFlags.of( ResolveInfoFlags.of( Loading