Move Chooser package-change shortcut reset to list adapter

The shortcut-resetting logic was implemented inline in ChooserActivity's
handler, and this CL moves the v2 implementation to a new callback in `ChooserListAdapter`. The v1 implementation is left as-is, so the design change is a no-op.

This makes the activity-side handling more generic so it can be
moved to the pager-adapter (go/chooser-ntab-refactoring), and it fixes
a minor bug (b/315460869).

This is based on "snapshot 4" and "5" of ag/25335069 (for more context, see that CL or go/chooser-ntab-refactoring).

Bug: 310211468, 315460869
Test: `IntentResolver-tests-{unit,activity,integration}`.
Change-Id: I29e10c801db553edc8132aaf8372140b4c35740e
diff --git a/java/src/com/android/intentresolver/ChooserActivity.java b/java/src/com/android/intentresolver/ChooserActivity.java
index 50ca5d0..9000ab3 100644
--- a/java/src/com/android/intentresolver/ChooserActivity.java
+++ b/java/src/com/android/intentresolver/ChooserActivity.java
@@ -1251,7 +1251,8 @@
                 getEventLog(),
                 maxTargetsPerRow,
                 initialIntentsUserSpace,
-                targetDataLoader);
+                targetDataLoader,
+                null);
     }
 
     @Override
diff --git a/java/src/com/android/intentresolver/ChooserListAdapter.java b/java/src/com/android/intentresolver/ChooserListAdapter.java
index 3af8a3a..876ad5c 100644
--- a/java/src/com/android/intentresolver/ChooserListAdapter.java
+++ b/java/src/com/android/intentresolver/ChooserListAdapter.java
@@ -30,7 +30,6 @@
 import android.content.pm.ResolveInfo;
 import android.content.pm.ShortcutInfo;
 import android.graphics.drawable.Drawable;
-import android.net.Uri;
 import android.os.AsyncTask;
 import android.os.Trace;
 import android.os.UserHandle;
@@ -68,6 +67,17 @@
 import java.util.stream.Collectors;
 
 public class ChooserListAdapter extends ResolverListAdapter {
+
+    /**
+     * Delegate interface for injecting a chooser-specific operation to be performed before handling
+     * a package-change event. This allows the "driver" invoking the package-change to be generic,
+     * with no knowledge specific to the chooser implementation.
+     */
+    public interface PackageChangeCallback {
+        /** Perform any steps necessary before processing the package-change event. */
+        void beforeHandlingPackagesChanged();
+    }
+
     private static final String TAG = "ChooserListAdapter";
     private static final boolean DEBUG = false;
 
@@ -93,6 +103,9 @@
 
     private final Set<TargetInfo> mRequestedIcons = new HashSet<>();
 
+    @Nullable
+    private final PackageChangeCallback mPackageChangeCallback;
+
     // Reserve spots for incoming direct share targets by adding placeholders
     private final TargetInfo mPlaceHolderTargetInfo;
     private final TargetDataLoader mTargetDataLoader;
@@ -152,7 +165,8 @@
             EventLog eventLog,
             int maxRankedTargets,
             UserHandle initialIntentsUserSpace,
-            TargetDataLoader targetDataLoader) {
+            TargetDataLoader targetDataLoader,
+            @Nullable PackageChangeCallback packageChangeCallback) {
         this(
                 context,
                 payloadIntents,
@@ -169,6 +183,7 @@
                 maxRankedTargets,
                 initialIntentsUserSpace,
                 targetDataLoader,
+                packageChangeCallback,
                 AsyncTask.SERIAL_EXECUTOR,
                 context.getMainExecutor());
     }
@@ -190,6 +205,7 @@
             int maxRankedTargets,
             UserHandle initialIntentsUserSpace,
             TargetDataLoader targetDataLoader,
+            @Nullable PackageChangeCallback packageChangeCallback,
             Executor bgExecutor,
             Executor mainExecutor) {
         // Don't send the initial intents through the shared ResolverActivity path,
@@ -214,6 +230,7 @@
 
         mPlaceHolderTargetInfo = NotSelectableTargetInfo.newPlaceHolderTargetInfo(context);
         mTargetDataLoader = targetDataLoader;
+        mPackageChangeCallback = packageChangeCallback;
         createPlaceHolders();
         mEventLog = eventLog;
         mShortcutSelectionLogic = new ShortcutSelectionLogic(
@@ -286,6 +303,9 @@
 
     @Override
     public void handlePackagesChanged() {
+        if (mPackageChangeCallback != null) {
+            mPackageChangeCallback.beforeHandlingPackagesChanged();
+        }
         if (DEBUG) {
             Log.d(TAG, "clearing queryTargets on package change");
         }
diff --git a/java/src/com/android/intentresolver/v2/ChooserActivity.java b/java/src/com/android/intentresolver/v2/ChooserActivity.java
index 95eedf4..6c961bb 100644
--- a/java/src/com/android/intentresolver/v2/ChooserActivity.java
+++ b/java/src/com/android/intentresolver/v2/ChooserActivity.java
@@ -594,25 +594,16 @@
         // Refresh pinned items
         mPinnedSharedPrefs = getPinnedSharedPrefs(this);
         if (listAdapter == null) {
-            handlePackageChangePerProfile(mChooserMultiProfilePagerAdapter.getActiveListAdapter());
+            mChooserMultiProfilePagerAdapter.getActiveListAdapter().handlePackagesChanged();
             if (mChooserMultiProfilePagerAdapter.getCount() > 1) {
-                handlePackageChangePerProfile(
-                        mChooserMultiProfilePagerAdapter.getInactiveListAdapter());
+                mChooserMultiProfilePagerAdapter.getInactiveListAdapter().handlePackagesChanged();
             }
         } else {
-            handlePackageChangePerProfile(listAdapter);
+            listAdapter.handlePackagesChanged();
         }
         updateProfileViewButton();
     }
 
-    private void handlePackageChangePerProfile(ResolverListAdapter adapter) {
-        ProfileRecord record = getProfileRecord(adapter.getUserHandle());
-        if (record != null && record.shortcutLoader != null) {
-            record.shortcutLoader.reset();
-        }
-        adapter.handlePackagesChanged();
-    }
-
     @Override
     protected void onResume() {
         super.onResume();
@@ -1272,7 +1263,13 @@
                 getEventLog(),
                 maxTargetsPerRow,
                 initialIntentsUserSpace,
-                targetDataLoader);
+                targetDataLoader,
+                () -> {
+                    ProfileRecord record = getProfileRecord(userHandle);
+                    if (record != null && record.shortcutLoader != null) {
+                        record.shortcutLoader.reset();
+                    }
+                });
     }
 
     @Override
diff --git a/tests/activity/src/com/android/intentresolver/ChooserWrapperActivity.java b/tests/activity/src/com/android/intentresolver/ChooserWrapperActivity.java
index 27d50ad..4ea0681 100644
--- a/tests/activity/src/com/android/intentresolver/ChooserWrapperActivity.java
+++ b/tests/activity/src/com/android/intentresolver/ChooserWrapperActivity.java
@@ -92,7 +92,8 @@
                 getEventLog(),
                 maxTargetsPerRow,
                 userHandle,
-                targetDataLoader);
+                targetDataLoader,
+                null);
     }
 
     @Override
diff --git a/tests/activity/src/com/android/intentresolver/v2/ChooserWrapperActivity.java b/tests/activity/src/com/android/intentresolver/v2/ChooserWrapperActivity.java
index a314ee9..3a40117 100644
--- a/tests/activity/src/com/android/intentresolver/v2/ChooserWrapperActivity.java
+++ b/tests/activity/src/com/android/intentresolver/v2/ChooserWrapperActivity.java
@@ -34,7 +34,6 @@
 import androidx.lifecycle.ViewModelProvider;
 
 import com.android.intentresolver.ChooserListAdapter;
-import com.android.intentresolver.ChooserRequestParameters;
 import com.android.intentresolver.IChooserWrapper;
 import com.android.intentresolver.ResolverListController;
 import com.android.intentresolver.TestContentPreviewViewModel;
@@ -107,7 +106,8 @@
                 getEventLog(),
                 maxTargetsPerRow,
                 userHandle,
-                targetDataLoader);
+                targetDataLoader,
+                null);
     }
 
     @Override
diff --git a/tests/unit/src/com/android/intentresolver/ChooserListAdapterDataTest.kt b/tests/unit/src/com/android/intentresolver/ChooserListAdapterDataTest.kt
index 9864d0b..98c5e00 100644
--- a/tests/unit/src/com/android/intentresolver/ChooserListAdapterDataTest.kt
+++ b/tests/unit/src/com/android/intentresolver/ChooserListAdapterDataTest.kt
@@ -44,7 +44,8 @@
     private val targetDataLoader = mock<TargetDataLoader>()
     private val backgroundExecutor = TestExecutor()
     private val immediateExecutor = TestExecutor(immediate = true)
-    private val referrerFillInIntent = Intent().putExtra(Intent.EXTRA_REFERRER, "org.referrer.package")
+    private val referrerFillInIntent =
+        Intent().putExtra(Intent.EXTRA_REFERRER, "org.referrer.package")
 
     @Test
     fun test_twoTargetsWithNonOverlappingInitialIntent_threeTargetsInResolverAdapter() {
@@ -93,6 +94,7 @@
                 /*maxRankedTargets=*/ 2,
                 /*initialIntentsUserSpace=*/ userHandle,
                 targetDataLoader,
+                null,
                 backgroundExecutor,
                 immediateExecutor,
             )
@@ -155,6 +157,7 @@
                 /*maxRankedTargets=*/ 2,
                 /*initialIntentsUserSpace=*/ userHandle,
                 targetDataLoader,
+                null,
                 backgroundExecutor,
                 immediateExecutor,
             )
diff --git a/tests/unit/src/com/android/intentresolver/ChooserListAdapterTest.kt b/tests/unit/src/com/android/intentresolver/ChooserListAdapterTest.kt
index a12c9ec..cb04394 100644
--- a/tests/unit/src/com/android/intentresolver/ChooserListAdapterTest.kt
+++ b/tests/unit/src/com/android/intentresolver/ChooserListAdapterTest.kt
@@ -56,6 +56,7 @@
     private val targetLabel = "Target"
     private val mEventLog = mock<EventLogImpl>()
     private val mTargetDataLoader = mock<TargetDataLoader>()
+    private val mPackageChangeCallback = mock<ChooserListAdapter.PackageChangeCallback>()
 
     private val testSubject by lazy {
         ChooserListAdapter(
@@ -73,7 +74,8 @@
             mEventLog,
             0,
             null,
-            mTargetDataLoader
+            mTargetDataLoader,
+            mPackageChangeCallback
         )
     }
 
@@ -168,6 +170,12 @@
         assertThat(view.contentDescription).isEqualTo("$appLabel. Pinned")
     }
 
+    @Test
+    fun handlePackagesChanged_invokesCallback() {
+        testSubject.handlePackagesChanged()
+        verify(mPackageChangeCallback, times(1)).beforeHandlingPackagesChanged()
+    }
+
     private fun createSelectableTargetInfo(isPinned: Boolean = false): TargetInfo {
         val shortcutInfo =
             createShortcutInfo("id-1", ComponentName("pkg", "Class"), 1).apply {