diff options
author | 2023-03-28 16:22:04 +0000 | |
---|---|---|
committer | 2023-03-28 16:22:04 +0000 | |
commit | fe666cd55aec4c3d8a7caf71978abe49902d737c (patch) | |
tree | 64d0b60810a07045180bd78997ce33cad0858b43 | |
parent | eabc904f06d9f2014e804ae4a6464abbd68eb814 (diff) | |
parent | a703bf08aa2212ca0dbefd535e9df92075d20cf4 (diff) |
Merge "Fallback to ShortcutManager if AppPredictor has crashed" into udc-dev am: 9c1f13565a am: a703bf08aa
Original change: https://googleplex-android-review.googlesource.com/c/platform/packages/modules/IntentResolver/+/22285708
Change-Id: I75f41ae1ae7b4be8d8abf6a851b14201e945656f
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
-rw-r--r-- | java/src/com/android/intentresolver/shortcuts/ShortcutLoader.kt | 11 | ||||
-rw-r--r-- | java/tests/src/com/android/intentresolver/shortcuts/ShortcutLoaderTest.kt | 75 |
2 files changed, 65 insertions, 21 deletions
diff --git a/java/src/com/android/intentresolver/shortcuts/ShortcutLoader.kt b/java/src/com/android/intentresolver/shortcuts/ShortcutLoader.kt index 6f7542f1..29e706d4 100644 --- a/java/src/com/android/intentresolver/shortcuts/ShortcutLoader.kt +++ b/java/src/com/android/intentresolver/shortcuts/ShortcutLoader.kt @@ -77,6 +77,7 @@ open class ShortcutLoader @VisibleForTesting constructor( private val userManager = context.getSystemService(Context.USER_SERVICE) as UserManager private val activeRequest = AtomicReference(NO_REQUEST) private val appPredictorCallback = AppPredictor.Callback { onAppPredictorCallback(it) } + @Volatile private var isDestroyed = false @MainThread @@ -134,8 +135,14 @@ open class ShortcutLoader @VisibleForTesting constructor( @WorkerThread private fun queryDirectShareTargets(skipAppPredictionService: Boolean) { if (!skipAppPredictionService && appPredictor != null) { - appPredictor.requestPredictionUpdate() - return + try { + appPredictor.requestPredictionUpdate() + return + } catch (e: Throwable) { + // we might have been destroyed concurrently, nothing left to do + if (isDestroyed) return + Log.e(TAG, "Failed to query AppPredictor", e) + } } // Default to just querying ShortcutManager if AppPredictor not present. if (targetIntentFilter == null) return diff --git a/java/tests/src/com/android/intentresolver/shortcuts/ShortcutLoaderTest.kt b/java/tests/src/com/android/intentresolver/shortcuts/ShortcutLoaderTest.kt index 0c817cb2..e8e2f862 100644 --- a/java/tests/src/com/android/intentresolver/shortcuts/ShortcutLoaderTest.kt +++ b/java/tests/src/com/android/intentresolver/shortcuts/ShortcutLoaderTest.kt @@ -58,7 +58,7 @@ class ShortcutLoaderTest { private val pm = mock<PackageManager> { whenever(getApplicationInfo(any(), any<ApplicationInfoFlags>())).thenReturn(appInfo) } - val userManager = mock<UserManager> { + private val userManager = mock<UserManager> { whenever(isUserRunning(any<UserHandle>())).thenReturn(true) whenever(isUserUnlocked(any<UserHandle>())).thenReturn(true) whenever(isQuietModeEnabled(any<UserHandle>())).thenReturn(false) @@ -72,14 +72,15 @@ class ShortcutLoaderTest { private val intentFilter = mock<IntentFilter>() private val appPredictor = mock<ShortcutLoader.AppPredictorProxy>() private val callback = mock<Consumer<ShortcutLoader.Result>>() + private val componentName = ComponentName("pkg", "Class") + private val appTarget = mock<DisplayResolveInfo> { + whenever(resolvedComponentName).thenReturn(componentName) + } + private val appTargets = arrayOf(appTarget) + private val matchingShortcutInfo = createShortcutInfo("id-0", componentName, 1) @Test fun test_queryShortcuts_result_consistency_with_AppPredictor() { - val componentName = ComponentName("pkg", "Class") - val appTarget = mock<DisplayResolveInfo> { - whenever(resolvedComponentName).thenReturn(componentName) - } - val appTargets = arrayOf(appTarget) val testSubject = ShortcutLoader( context, appPredictor, @@ -93,7 +94,6 @@ class ShortcutLoaderTest { testSubject.queryShortcuts(appTargets) - val matchingShortcutInfo = createShortcutInfo("id-0", componentName, 1) val matchingAppTarget = createAppTarget(matchingShortcutInfo) val shortcuts = listOf( matchingAppTarget, @@ -131,12 +131,6 @@ class ShortcutLoaderTest { @Test fun test_queryShortcuts_result_consistency_with_ShortcutManager() { - val componentName = ComponentName("pkg", "Class") - val appTarget = mock<DisplayResolveInfo> { - whenever(resolvedComponentName).thenReturn(componentName) - } - val appTargets = arrayOf(appTarget) - val matchingShortcutInfo = createShortcutInfo("id-0", componentName, 1) val shortcutManagerResult = listOf( ShortcutManager.ShareShortcutInfo(matchingShortcutInfo, componentName), // mismatching shortcut @@ -182,12 +176,6 @@ class ShortcutLoaderTest { @Test fun test_queryShortcuts_falls_back_to_ShortcutManager_on_empty_reply() { - val componentName = ComponentName("pkg", "Class") - val appTarget = mock<DisplayResolveInfo> { - whenever(resolvedComponentName).thenReturn(componentName) - } - val appTargets = arrayOf(appTarget) - val matchingShortcutInfo = createShortcutInfo("id-0", componentName, 1) val shortcutManagerResult = listOf( ShortcutManager.ShareShortcutInfo(matchingShortcutInfo, componentName), // mismatching shortcut @@ -238,6 +226,55 @@ class ShortcutLoaderTest { } @Test + fun test_queryShortcuts_onAppPredictorFailure_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, + appPredictor, + UserHandle.of(0), + true, + intentFilter, + executor, + executor, + callback + ) + + testSubject.queryShortcuts(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) + 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_queryShortcuts_do_not_call_services_for_not_running_work_profile() { testDisabledWorkProfileDoNotCallSystem(isUserRunning = false) } |