diff options
| author | 2023-09-06 21:15:01 -0700 | |
|---|---|---|
| committer | 2023-09-08 16:16:11 +0000 | |
| commit | b8f2dd471020d6334d7552ecc6cd428e0f796cdb (patch) | |
| tree | c22de657863cbf106a5ef13f11c18e24d4b83282 /java | |
| parent | e7b6dce2df1de1e57ccbe617fe34a51666958ff3 (diff) | |
ShortcutLoader to use a CoroutineScope instead of a Lifecycle
A preparation step to make transfer ShortcutLoader ownership from
ChooserActivity to a view model.
Test: atest IntentResolverUnitTests
Change-Id: Id4e02b3418f49644c11e562a89ce3c00e61f8e5f
Diffstat (limited to 'java')
3 files changed, 319 insertions, 310 deletions
diff --git a/java/src/com/android/intentresolver/ChooserActivity.java b/java/src/com/android/intentresolver/ChooserActivity.java index b27f054e..d244fa2d 100644 --- a/java/src/com/android/intentresolver/ChooserActivity.java +++ b/java/src/com/android/intentresolver/ChooserActivity.java @@ -24,6 +24,7 @@ import static android.app.admin.DevicePolicyResources.Strings.Core.RESOLVER_CROS import static android.stats.devicepolicy.nano.DevicePolicyEnums.RESOLVER_EMPTY_STATE_NO_SHARING_TO_PERSONAL; import static android.stats.devicepolicy.nano.DevicePolicyEnums.RESOLVER_EMPTY_STATE_NO_SHARING_TO_WORK; +import static androidx.lifecycle.LifecycleKt.getCoroutineScope; import static com.android.internal.util.LatencyTracker.ACTION_LOAD_SHARE_SHEET; import android.annotation.IntDef; @@ -406,7 +407,7 @@ public class ChooserActivity extends ResolverActivity implements Consumer<ShortcutLoader.Result> callback) { return new ShortcutLoader( context, - getLifecycle(), + getCoroutineScope(getLifecycle()), appPredictor, userHandle, targetIntentFilter, diff --git a/java/src/com/android/intentresolver/shortcuts/ShortcutLoader.kt b/java/src/com/android/intentresolver/shortcuts/ShortcutLoader.kt index f05542e2..e7f71661 100644 --- a/java/src/com/android/intentresolver/shortcuts/ShortcutLoader.kt +++ b/java/src/com/android/intentresolver/shortcuts/ShortcutLoader.kt @@ -35,14 +35,13 @@ import androidx.annotation.MainThread import androidx.annotation.OpenForTesting import androidx.annotation.VisibleForTesting import androidx.annotation.WorkerThread -import androidx.lifecycle.Lifecycle -import androidx.lifecycle.coroutineScope import com.android.intentresolver.chooser.DisplayResolveInfo import com.android.intentresolver.measurements.Tracer import com.android.intentresolver.measurements.runTracing import java.util.concurrent.Executor import java.util.function.Consumer import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.asExecutor import kotlinx.coroutines.channels.BufferOverflow @@ -50,6 +49,7 @@ import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.flowOn +import kotlinx.coroutines.isActive import kotlinx.coroutines.launch /** @@ -58,14 +58,14 @@ import kotlinx.coroutines.launch * A ShortcutLoader instance can be viewed as a per-profile singleton hot stream of shortcut * updates. The shortcut loading is triggered in the constructor or by the [reset] method, the * processing happens on the [dispatcher] and the result is delivered through the [callback] on the - * default [lifecycle]'s dispatcher, the main thread. + * default [scope]'s dispatcher, the main thread. */ @OpenForTesting open class ShortcutLoader @VisibleForTesting constructor( private val context: Context, - private val lifecycle: Lifecycle, + private val scope: CoroutineScope, private val appPredictor: AppPredictorProxy?, private val userHandle: UserHandle, private val isPersonalProfile: Boolean, @@ -84,19 +84,19 @@ constructor( private val shortcutSource = MutableSharedFlow<ShortcutData?>(replay = 1, onBufferOverflow = BufferOverflow.DROP_OLDEST) private val isDestroyed - get() = !lifecycle.currentState.isAtLeast(Lifecycle.State.CREATED) + get() = !scope.isActive @MainThread constructor( context: Context, - lifecycle: Lifecycle, + scope: CoroutineScope, appPredictor: AppPredictor?, userHandle: UserHandle, targetIntentFilter: IntentFilter?, callback: Consumer<Result> ) : this( context, - lifecycle, + scope, appPredictor?.let { AppPredictorProxy(it) }, userHandle, userHandle == UserHandle.of(ActivityManager.getCurrentUser()), @@ -107,7 +107,7 @@ constructor( init { appPredictor?.registerPredictionUpdates(dispatcher.asExecutor(), appPredictorCallback) - lifecycle.coroutineScope + scope .launch { appTargetSource .combine(shortcutSource) { appTargets, shortcutData -> @@ -135,13 +135,13 @@ constructor( reset() } - /** Clear application targets (see [updateAppTargets] and initiate shrtcuts loading. */ + /** Clear application targets (see [updateAppTargets] and initiate shortcuts loading. */ @OpenForTesting open fun reset() { Log.d(TAG, "reset shortcut loader for user $userHandle") appTargetSource.tryEmit(null) shortcutSource.tryEmit(null) - lifecycle.coroutineScope.launch(dispatcher) { loadShortcuts() } + scope.launch(dispatcher) { loadShortcuts() } } /** diff --git a/java/tests/src/com/android/intentresolver/shortcuts/ShortcutLoaderTest.kt b/java/tests/src/com/android/intentresolver/shortcuts/ShortcutLoaderTest.kt index 9b4a8057..43d0df79 100644 --- a/java/tests/src/com/android/intentresolver/shortcuts/ShortcutLoaderTest.kt +++ b/java/tests/src/com/android/intentresolver/shortcuts/ShortcutLoaderTest.kt @@ -26,8 +26,6 @@ import android.content.pm.PackageManager.ApplicationInfoFlags import android.content.pm.ShortcutManager import android.os.UserHandle import android.os.UserManager -import androidx.lifecycle.Lifecycle -import androidx.lifecycle.testing.TestLifecycleOwner import androidx.test.filters.SmallTest import com.android.intentresolver.any import com.android.intentresolver.argumentCaptor @@ -39,18 +37,15 @@ import com.android.intentresolver.createShortcutInfo import com.android.intentresolver.mock import com.android.intentresolver.whenever import java.util.function.Consumer -import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.TestCoroutineScheduler +import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.UnconfinedTestDispatcher -import kotlinx.coroutines.test.resetMain -import kotlinx.coroutines.test.setMain -import org.junit.After +import kotlinx.coroutines.test.runTest import org.junit.Assert.assertArrayEquals import org.junit.Assert.assertEquals import org.junit.Assert.assertFalse import org.junit.Assert.assertTrue -import org.junit.Before import org.junit.Test import org.mockito.Mockito.anyInt import org.mockito.Mockito.atLeastOnce @@ -84,7 +79,7 @@ class ShortcutLoaderTest { } private val scheduler = TestCoroutineScheduler() private val dispatcher = UnconfinedTestDispatcher(scheduler) - private val lifecycleOwner = TestLifecycleOwner() + private val scope = TestScope(dispatcher) private val intentFilter = mock<IntentFilter>() private val appPredictor = mock<ShortcutLoader.AppPredictorProxy>() private val callback = mock<Consumer<ShortcutLoader.Result>>() @@ -94,135 +89,239 @@ class ShortcutLoaderTest { private val appTargets = arrayOf(appTarget) private val matchingShortcutInfo = createShortcutInfo("id-0", componentName, 1) - @Before - fun setup() { - Dispatchers.setMain(dispatcher) - lifecycleOwner.handleLifecycleEvent(Lifecycle.Event.ON_CREATE) - } - - @After - fun cleanup() { - lifecycleOwner.handleLifecycleEvent(Lifecycle.Event.ON_DESTROY) - Dispatchers.resetMain() - } - @Test - fun test_loadShortcutsWithAppPredictor_resultIntegrity() { - val testSubject = - ShortcutLoader( - context, - lifecycleOwner.lifecycle, - appPredictor, - UserHandle.of(0), - true, - intentFilter, - dispatcher, - callback - ) - - testSubject.updateAppTargets(appTargets) + fun test_loadShortcutsWithAppPredictor_resultIntegrity() = + scope.runTest { + val testSubject = + ShortcutLoader( + context, + backgroundScope, + appPredictor, + UserHandle.of(0), + true, + intentFilter, + dispatcher, + callback + ) - val matchingAppTarget = createAppTarget(matchingShortcutInfo) - val shortcuts = - listOf( - matchingAppTarget, - // an AppTarget that does not belong to any resolved application; should be ignored - createAppTarget( - createShortcutInfo("id-1", ComponentName("mismatching.pkg", "Class"), 1) + testSubject.updateAppTargets(appTargets) + + val matchingAppTarget = createAppTarget(matchingShortcutInfo) + val shortcuts = + listOf( + matchingAppTarget, + // an AppTarget that does not belong to any resolved application; should be + // ignored + createAppTarget( + createShortcutInfo("id-1", ComponentName("mismatching.pkg", "Class"), 1) + ) ) + val appPredictorCallbackCaptor = argumentCaptor<AppPredictor.Callback>() + verify(appPredictor, atLeastOnce()) + .registerPredictionUpdates(any(), capture(appPredictorCallbackCaptor)) + appPredictorCallbackCaptor.value.onTargetsAvailable(shortcuts) + + val resultCaptor = argumentCaptor<ShortcutLoader.Result>() + verify(callback, times(1)).accept(capture(resultCaptor)) + + val result = resultCaptor.value + assertTrue("An app predictor result is expected", result.isFromAppPredictor) + assertArrayEquals( + "Wrong input app targets in the result", + appTargets, + result.appTargets ) - val appPredictorCallbackCaptor = argumentCaptor<AppPredictor.Callback>() - verify(appPredictor, atLeastOnce()) - .registerPredictionUpdates(any(), capture(appPredictorCallbackCaptor)) - appPredictorCallbackCaptor.value.onTargetsAvailable(shortcuts) - - val resultCaptor = argumentCaptor<ShortcutLoader.Result>() - verify(callback, times(1)).accept(capture(resultCaptor)) - - val result = resultCaptor.value - assertTrue("An app predictor result is expected", result.isFromAppPredictor) - assertArrayEquals("Wrong input app targets in the result", appTargets, result.appTargets) - assertEquals("Wrong shortcut count", 1, result.shortcutsByApp.size) - assertEquals("Wrong app target", appTarget, result.shortcutsByApp[0].appTarget) - for (shortcut in result.shortcutsByApp[0].shortcuts) { - assertEquals( - "Wrong AppTarget in the cache", - matchingAppTarget, - result.directShareAppTargetCache[shortcut] - ) - assertEquals( - "Wrong ShortcutInfo in the cache", - matchingShortcutInfo, - result.directShareShortcutInfoCache[shortcut] - ) + assertEquals("Wrong shortcut count", 1, result.shortcutsByApp.size) + assertEquals("Wrong app target", appTarget, result.shortcutsByApp[0].appTarget) + for (shortcut in result.shortcutsByApp[0].shortcuts) { + assertEquals( + "Wrong AppTarget in the cache", + matchingAppTarget, + result.directShareAppTargetCache[shortcut] + ) + assertEquals( + "Wrong ShortcutInfo in the cache", + matchingShortcutInfo, + result.directShareShortcutInfoCache[shortcut] + ) + } } - } @Test - fun test_loadShortcutsWithShortcutManager_resultIntegrity() { - val shortcutManagerResult = - listOf( - ShortcutManager.ShareShortcutInfo(matchingShortcutInfo, componentName), - // mismatching shortcut - createShareShortcutInfo("id-1", ComponentName("mismatching.pkg", "Class"), 1) + fun test_loadShortcutsWithShortcutManager_resultIntegrity() = + scope.runTest { + val shortcutManagerResult = + listOf( + ShortcutManager.ShareShortcutInfo(matchingShortcutInfo, componentName), + // mismatching shortcut + createShareShortcutInfo("id-1", ComponentName("mismatching.pkg", "Class"), 1) + ) + val shortcutManager = + mock<ShortcutManager> { + whenever(getShareTargets(intentFilter)).thenReturn(shortcutManagerResult) + } + whenever(context.getSystemService(Context.SHORTCUT_SERVICE)).thenReturn(shortcutManager) + val testSubject = + ShortcutLoader( + context, + backgroundScope, + null, + UserHandle.of(0), + true, + intentFilter, + dispatcher, + callback + ) + + testSubject.updateAppTargets(appTargets) + + val resultCaptor = argumentCaptor<ShortcutLoader.Result>() + verify(callback, times(1)).accept(capture(resultCaptor)) + + val result = resultCaptor.value + assertFalse("An ShortcutManager result is expected", result.isFromAppPredictor) + assertArrayEquals( + "Wrong input app targets in the result", + appTargets, + result.appTargets ) - val shortcutManager = - mock<ShortcutManager> { - whenever(getShareTargets(intentFilter)).thenReturn(shortcutManagerResult) + assertEquals("Wrong shortcut count", 1, result.shortcutsByApp.size) + assertEquals("Wrong app target", appTarget, result.shortcutsByApp[0].appTarget) + for (shortcut in result.shortcutsByApp[0].shortcuts) { + assertTrue( + "AppTargets are not expected the cache of a ShortcutManager result", + result.directShareAppTargetCache.isEmpty() + ) + assertEquals( + "Wrong ShortcutInfo in the cache", + matchingShortcutInfo, + result.directShareShortcutInfoCache[shortcut] + ) } - whenever(context.getSystemService(Context.SHORTCUT_SERVICE)).thenReturn(shortcutManager) - val testSubject = - ShortcutLoader( - context, - lifecycleOwner.lifecycle, - null, - UserHandle.of(0), - true, - intentFilter, - dispatcher, - callback - ) + } - testSubject.updateAppTargets(appTargets) + @Test + fun test_appPredictorReturnsEmptyList_fallbackToShortcutManager() = + scope.runTest { + val shortcutManagerResult = + listOf( + ShortcutManager.ShareShortcutInfo(matchingShortcutInfo, componentName), + // mismatching shortcut + createShareShortcutInfo("id-1", ComponentName("mismatching.pkg", "Class"), 1) + ) + val shortcutManager = + mock<ShortcutManager> { + whenever(getShareTargets(intentFilter)).thenReturn(shortcutManagerResult) + } + whenever(context.getSystemService(Context.SHORTCUT_SERVICE)).thenReturn(shortcutManager) + val testSubject = + ShortcutLoader( + context, + backgroundScope, + appPredictor, + UserHandle.of(0), + true, + intentFilter, + dispatcher, + callback + ) - val resultCaptor = argumentCaptor<ShortcutLoader.Result>() - verify(callback, times(1)).accept(capture(resultCaptor)) + testSubject.updateAppTargets(appTargets) - val result = resultCaptor.value - assertFalse("An ShortcutManager result is expected", result.isFromAppPredictor) - assertArrayEquals("Wrong input app targets in the result", appTargets, result.appTargets) - assertEquals("Wrong shortcut count", 1, result.shortcutsByApp.size) - assertEquals("Wrong app target", appTarget, result.shortcutsByApp[0].appTarget) - for (shortcut in result.shortcutsByApp[0].shortcuts) { - assertTrue( - "AppTargets are not expected the cache of a ShortcutManager result", - result.directShareAppTargetCache.isEmpty() - ) - assertEquals( - "Wrong ShortcutInfo in the cache", - matchingShortcutInfo, - result.directShareShortcutInfoCache[shortcut] + verify(appPredictor, times(1)).requestPredictionUpdate() + val appPredictorCallbackCaptor = argumentCaptor<AppPredictor.Callback>() + verify(appPredictor, times(1)) + .registerPredictionUpdates(any(), capture(appPredictorCallbackCaptor)) + appPredictorCallbackCaptor.value.onTargetsAvailable(emptyList()) + + val resultCaptor = argumentCaptor<ShortcutLoader.Result>() + verify(callback, times(1)).accept(capture(resultCaptor)) + + val result = resultCaptor.value + assertFalse("An ShortcutManager result is expected", result.isFromAppPredictor) + assertArrayEquals( + "Wrong input app targets in the result", + appTargets, + result.appTargets ) + assertEquals("Wrong shortcut count", 1, result.shortcutsByApp.size) + assertEquals("Wrong app target", appTarget, result.shortcutsByApp[0].appTarget) + for (shortcut in result.shortcutsByApp[0].shortcuts) { + assertTrue( + "AppTargets are not expected the cache of a ShortcutManager result", + result.directShareAppTargetCache.isEmpty() + ) + assertEquals( + "Wrong ShortcutInfo in the cache", + matchingShortcutInfo, + result.directShareShortcutInfoCache[shortcut] + ) + } } - } @Test - fun test_appPredictorReturnsEmptyList_fallbackToShortcutManager() { - val shortcutManagerResult = - listOf( - ShortcutManager.ShareShortcutInfo(matchingShortcutInfo, componentName), - // mismatching shortcut - createShareShortcutInfo("id-1", ComponentName("mismatching.pkg", "Class"), 1) + fun test_appPredictor_requestPredictionUpdateFailure_fallbackToShortcutManager() = + scope.runTest { + val shortcutManagerResult = + listOf( + ShortcutManager.ShareShortcutInfo(matchingShortcutInfo, componentName), + // mismatching shortcut + createShareShortcutInfo("id-1", ComponentName("mismatching.pkg", "Class"), 1) + ) + val shortcutManager = + mock<ShortcutManager> { + whenever(getShareTargets(intentFilter)).thenReturn(shortcutManagerResult) + } + whenever(context.getSystemService(Context.SHORTCUT_SERVICE)).thenReturn(shortcutManager) + whenever(appPredictor.requestPredictionUpdate()) + .thenThrow(IllegalStateException("Test exception")) + val testSubject = + ShortcutLoader( + context, + backgroundScope, + appPredictor, + UserHandle.of(0), + true, + intentFilter, + dispatcher, + callback + ) + + testSubject.updateAppTargets(appTargets) + + verify(appPredictor, times(1)).requestPredictionUpdate() + + val resultCaptor = argumentCaptor<ShortcutLoader.Result>() + verify(callback, times(1)).accept(capture(resultCaptor)) + + val result = resultCaptor.value + assertFalse("An ShortcutManager result is expected", result.isFromAppPredictor) + assertArrayEquals( + "Wrong input app targets in the result", + appTargets, + result.appTargets ) - val shortcutManager = - mock<ShortcutManager> { - whenever(getShareTargets(intentFilter)).thenReturn(shortcutManagerResult) + assertEquals("Wrong shortcut count", 1, result.shortcutsByApp.size) + assertEquals("Wrong app target", appTarget, result.shortcutsByApp[0].appTarget) + for (shortcut in result.shortcutsByApp[0].shortcuts) { + assertTrue( + "AppTargets are not expected the cache of a ShortcutManager result", + result.directShareAppTargetCache.isEmpty() + ) + assertEquals( + "Wrong ShortcutInfo in the cache", + matchingShortcutInfo, + result.directShareShortcutInfoCache[shortcut] + ) } - whenever(context.getSystemService(Context.SHORTCUT_SERVICE)).thenReturn(shortcutManager) - val testSubject = + } + + @Test + fun test_ShortcutLoader_shortcutsRequestedIndependentlyFromAppTargets() = + scope.runTest { ShortcutLoader( context, - lifecycleOwner.lifecycle, + backgroundScope, appPredictor, UserHandle.of(0), true, @@ -231,122 +330,57 @@ class ShortcutLoaderTest { callback ) - testSubject.updateAppTargets(appTargets) - - verify(appPredictor, times(1)).requestPredictionUpdate() - val appPredictorCallbackCaptor = argumentCaptor<AppPredictor.Callback>() - verify(appPredictor, times(1)) - .registerPredictionUpdates(any(), capture(appPredictorCallbackCaptor)) - appPredictorCallbackCaptor.value.onTargetsAvailable(emptyList()) - - val resultCaptor = argumentCaptor<ShortcutLoader.Result>() - verify(callback, times(1)).accept(capture(resultCaptor)) - - val result = resultCaptor.value - assertFalse("An ShortcutManager result is expected", result.isFromAppPredictor) - assertArrayEquals("Wrong input app targets in the result", appTargets, result.appTargets) - assertEquals("Wrong shortcut count", 1, result.shortcutsByApp.size) - assertEquals("Wrong app target", appTarget, result.shortcutsByApp[0].appTarget) - for (shortcut in result.shortcutsByApp[0].shortcuts) { - assertTrue( - "AppTargets are not expected the cache of a ShortcutManager result", - result.directShareAppTargetCache.isEmpty() - ) - assertEquals( - "Wrong ShortcutInfo in the cache", - matchingShortcutInfo, - result.directShareShortcutInfoCache[shortcut] - ) + verify(appPredictor, times(1)).requestPredictionUpdate() + verify(callback, never()).accept(any()) } - } @Test - fun test_appPredictor_requestPredictionUpdateFailure_fallbackToShortcutManager() { - val shortcutManagerResult = - listOf( - ShortcutManager.ShareShortcutInfo(matchingShortcutInfo, componentName), - // mismatching shortcut - createShareShortcutInfo("id-1", ComponentName("mismatching.pkg", "Class"), 1) - ) - val shortcutManager = - mock<ShortcutManager> { - whenever(getShareTargets(intentFilter)).thenReturn(shortcutManagerResult) - } - whenever(context.getSystemService(Context.SHORTCUT_SERVICE)).thenReturn(shortcutManager) - whenever(appPredictor.requestPredictionUpdate()) - .thenThrow(IllegalStateException("Test exception")) - val testSubject = - ShortcutLoader( - context, - lifecycleOwner.lifecycle, - appPredictor, - UserHandle.of(0), - true, - intentFilter, - dispatcher, - callback - ) + fun test_ShortcutLoader_noResultsWithoutAppTargets() = + scope.runTest { + val shortcutManagerResult = + listOf( + ShortcutManager.ShareShortcutInfo(matchingShortcutInfo, componentName), + // mismatching shortcut + createShareShortcutInfo("id-1", ComponentName("mismatching.pkg", "Class"), 1) + ) + val shortcutManager = + mock<ShortcutManager> { + whenever(getShareTargets(intentFilter)).thenReturn(shortcutManagerResult) + } + whenever(context.getSystemService(Context.SHORTCUT_SERVICE)).thenReturn(shortcutManager) + val testSubject = + ShortcutLoader( + context, + backgroundScope, + null, + UserHandle.of(0), + true, + intentFilter, + dispatcher, + callback + ) - testSubject.updateAppTargets(appTargets) + verify(shortcutManager, times(1)).getShareTargets(any()) + verify(callback, never()).accept(any()) - verify(appPredictor, times(1)).requestPredictionUpdate() + testSubject.reset() - val resultCaptor = argumentCaptor<ShortcutLoader.Result>() - verify(callback, times(1)).accept(capture(resultCaptor)) + verify(shortcutManager, times(2)).getShareTargets(any()) + verify(callback, never()).accept(any()) - val result = resultCaptor.value - assertFalse("An ShortcutManager result is expected", result.isFromAppPredictor) - assertArrayEquals("Wrong input app targets in the result", appTargets, result.appTargets) - assertEquals("Wrong shortcut count", 1, result.shortcutsByApp.size) - assertEquals("Wrong app target", appTarget, result.shortcutsByApp[0].appTarget) - for (shortcut in result.shortcutsByApp[0].shortcuts) { - assertTrue( - "AppTargets are not expected the cache of a ShortcutManager result", - result.directShareAppTargetCache.isEmpty() - ) - assertEquals( - "Wrong ShortcutInfo in the cache", - matchingShortcutInfo, - result.directShareShortcutInfoCache[shortcut] - ) - } - } + testSubject.updateAppTargets(appTargets) - @Test - fun test_ShortcutLoader_shortcutsRequestedIndependentlyFromAppTargets() { - ShortcutLoader( - context, - lifecycleOwner.lifecycle, - appPredictor, - UserHandle.of(0), - true, - intentFilter, - dispatcher, - callback - ) - - verify(appPredictor, times(1)).requestPredictionUpdate() - verify(callback, never()).accept(any()) - } + verify(shortcutManager, times(2)).getShareTargets(any()) + verify(callback, times(1)).accept(any()) + } @Test - fun test_ShortcutLoader_noResultsWithoutAppTargets() { - val shortcutManagerResult = - listOf( - ShortcutManager.ShareShortcutInfo(matchingShortcutInfo, componentName), - // mismatching shortcut - createShareShortcutInfo("id-1", ComponentName("mismatching.pkg", "Class"), 1) - ) - val shortcutManager = - mock<ShortcutManager> { - whenever(getShareTargets(intentFilter)).thenReturn(shortcutManagerResult) - } - whenever(context.getSystemService(Context.SHORTCUT_SERVICE)).thenReturn(shortcutManager) - val testSubject = + fun test_OnScopeCancellation_unsubscribeFromAppPredictor() { + scope.runTest { ShortcutLoader( context, - lifecycleOwner.lifecycle, - null, + backgroundScope, + appPredictor, UserHandle.of(0), true, intentFilter, @@ -354,36 +388,8 @@ class ShortcutLoaderTest { callback ) - verify(shortcutManager, times(1)).getShareTargets(any()) - verify(callback, never()).accept(any()) - - testSubject.reset() - - verify(shortcutManager, times(2)).getShareTargets(any()) - verify(callback, never()).accept(any()) - - testSubject.updateAppTargets(appTargets) - - verify(shortcutManager, times(2)).getShareTargets(any()) - verify(callback, times(1)).accept(any()) - } - - @Test - fun test_OnLifecycleDestroyed_unsubscribeFromAppPredictor() { - ShortcutLoader( - context, - lifecycleOwner.lifecycle, - appPredictor, - UserHandle.of(0), - true, - intentFilter, - dispatcher, - callback - ) - - verify(appPredictor, never()).unregisterPredictionUpdates(any()) - - lifecycleOwner.handleLifecycleEvent(Lifecycle.Event.ON_DESTROY) + verify(appPredictor, never()).unregisterPredictionUpdates(any()) + } verify(appPredictor, times(1)).unregisterPredictionUpdates(any()) } @@ -422,61 +428,63 @@ class ShortcutLoaderTest { isUserRunning: Boolean = true, isUserUnlocked: Boolean = true, isQuietModeEnabled: Boolean = false - ) { - val userHandle = UserHandle.of(10) - with(userManager) { - whenever(isUserRunning(userHandle)).thenReturn(isUserRunning) - whenever(isUserUnlocked(userHandle)).thenReturn(isUserUnlocked) - whenever(isQuietModeEnabled(userHandle)).thenReturn(isQuietModeEnabled) - } - whenever(context.getSystemService(Context.USER_SERVICE)).thenReturn(userManager) - val appPredictor = mock<ShortcutLoader.AppPredictorProxy>() - val callback = mock<Consumer<ShortcutLoader.Result>>() - val testSubject = - ShortcutLoader( - context, - lifecycleOwner.lifecycle, - appPredictor, - userHandle, - false, - intentFilter, - dispatcher, - callback - ) + ) = + scope.runTest { + val userHandle = UserHandle.of(10) + with(userManager) { + whenever(isUserRunning(userHandle)).thenReturn(isUserRunning) + whenever(isUserUnlocked(userHandle)).thenReturn(isUserUnlocked) + whenever(isQuietModeEnabled(userHandle)).thenReturn(isQuietModeEnabled) + } + whenever(context.getSystemService(Context.USER_SERVICE)).thenReturn(userManager) + val appPredictor = mock<ShortcutLoader.AppPredictorProxy>() + val callback = mock<Consumer<ShortcutLoader.Result>>() + val testSubject = + ShortcutLoader( + context, + backgroundScope, + appPredictor, + userHandle, + false, + intentFilter, + dispatcher, + callback + ) - testSubject.updateAppTargets(arrayOf<DisplayResolveInfo>(mock())) + testSubject.updateAppTargets(arrayOf<DisplayResolveInfo>(mock())) - verify(appPredictor, never()).requestPredictionUpdate() - } + verify(appPredictor, never()).requestPredictionUpdate() + } private fun testAlwaysCallSystemForMainProfile( isUserRunning: Boolean = true, isUserUnlocked: Boolean = true, isQuietModeEnabled: Boolean = false - ) { - val userHandle = UserHandle.of(10) - with(userManager) { - whenever(isUserRunning(userHandle)).thenReturn(isUserRunning) - whenever(isUserUnlocked(userHandle)).thenReturn(isUserUnlocked) - whenever(isQuietModeEnabled(userHandle)).thenReturn(isQuietModeEnabled) - } - whenever(context.getSystemService(Context.USER_SERVICE)).thenReturn(userManager) - val appPredictor = mock<ShortcutLoader.AppPredictorProxy>() - val callback = mock<Consumer<ShortcutLoader.Result>>() - val testSubject = - ShortcutLoader( - context, - lifecycleOwner.lifecycle, - appPredictor, - userHandle, - true, - intentFilter, - dispatcher, - callback - ) + ) = + scope.runTest { + val userHandle = UserHandle.of(10) + with(userManager) { + whenever(isUserRunning(userHandle)).thenReturn(isUserRunning) + whenever(isUserUnlocked(userHandle)).thenReturn(isUserUnlocked) + whenever(isQuietModeEnabled(userHandle)).thenReturn(isQuietModeEnabled) + } + whenever(context.getSystemService(Context.USER_SERVICE)).thenReturn(userManager) + val appPredictor = mock<ShortcutLoader.AppPredictorProxy>() + val callback = mock<Consumer<ShortcutLoader.Result>>() + val testSubject = + ShortcutLoader( + context, + backgroundScope, + appPredictor, + userHandle, + true, + intentFilter, + dispatcher, + callback + ) - testSubject.updateAppTargets(arrayOf<DisplayResolveInfo>(mock())) + testSubject.updateAppTargets(arrayOf<DisplayResolveInfo>(mock())) - verify(appPredictor, times(1)).requestPredictionUpdate() - } + verify(appPredictor, times(1)).requestPredictionUpdate() + } } |