summaryrefslogtreecommitdiff
path: root/java/src
diff options
context:
space:
mode:
author Matt Casey <mrcasey@google.com> 2023-03-03 01:34:25 +0000
committer Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com> 2023-03-03 01:34:25 +0000
commit30b80f61506b61a1182c03e696f1327dbb1540bc (patch)
treeb130179b70809c4d5871ccbd4eecca64b3a7601c /java/src
parentb15f2315544c33d1792bfc53bf87dd2576a800ef (diff)
parent8a081608bb679f5f922e101d8971220c21ac5d07 (diff)
Merge "Allow refinement of any matching source intent." into tm-qpr-dev am: a115be39e6 am: a2cd2f9753 am: 5e719ed805 am: 8a081608bb
Original change: https://googleplex-android-review.googlesource.com/c/platform/packages/modules/IntentResolver/+/21560196 Change-Id: I463c4033c4d869d1847b83dab3da7a8488dd2b2f Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
Diffstat (limited to 'java/src')
-rw-r--r--java/src/com/android/intentresolver/ChooserRefinementManager.java33
-rw-r--r--java/src/com/android/intentresolver/chooser/DisplayResolveInfo.java42
-rw-r--r--java/src/com/android/intentresolver/chooser/ImmutableTargetInfo.java139
-rw-r--r--java/src/com/android/intentresolver/chooser/MultiDisplayResolveInfo.java27
-rw-r--r--java/src/com/android/intentresolver/chooser/SelectableTargetInfo.java56
-rw-r--r--java/src/com/android/intentresolver/chooser/TargetInfo.java19
6 files changed, 193 insertions, 123 deletions
diff --git a/java/src/com/android/intentresolver/ChooserRefinementManager.java b/java/src/com/android/intentresolver/ChooserRefinementManager.java
index 5b5c1d32..3ddc1c7c 100644
--- a/java/src/com/android/intentresolver/ChooserRefinementManager.java
+++ b/java/src/com/android/intentresolver/ChooserRefinementManager.java
@@ -40,12 +40,6 @@ import java.util.function.Consumer;
* additional extras and other refinements (subject to {@link Intent#filterEquals()}), e.g., to
* convert the format of the payload, or lazy-download some data that was deferred in the original
* call).
- *
- * TODO(b/262805893): this currently requires the result to be a refinement of <em>the best</em>
- * match for the user's selected target among the initially-provided source intents (according to
- * their originally-provided priority order). In order to support alternate formats/actions, we
- * should instead require it to refine <em>any</em> of the source intents -- presumably, the first
- * in priority order that matches according to {@link Intent#filterEquals()}.
*/
public final class ChooserRefinementManager {
private static final String TAG = "ChooserRefinement";
@@ -88,10 +82,12 @@ public final class ChooserRefinementManager {
mRefinementResultReceiver = new RefinementResultReceiver(
refinedIntent -> {
destroy();
- TargetInfo refinedTarget = getValidRefinedTarget(selectedTarget, refinedIntent);
+ TargetInfo refinedTarget =
+ selectedTarget.tryToCloneWithAppliedRefinement(refinedIntent);
if (refinedTarget != null) {
mOnSelectionRefined.accept(refinedTarget);
} else {
+ Log.e(TAG, "Failed to apply refinement to any matching source intent");
mOnRefinementCancelled.run();
}
},
@@ -195,27 +191,4 @@ public final class ChooserRefinementManager {
return receiverForSending;
}
}
-
- private static TargetInfo getValidRefinedTarget(
- TargetInfo originalTarget, Intent proposedRefinement) {
- if (originalTarget == null) {
- // TODO: this legacy log message doesn't seem to describe the real condition we just
- // checked; probably this method should never be invoked with a null target.
- Log.e(TAG, "Refinement result intent did not match any known targets; canceling");
- return null;
- }
- if (!checkProposalRefinesSourceIntent(originalTarget, proposedRefinement)) {
- Log.e(TAG, "Refinement " + proposedRefinement + " has no match in " + originalTarget);
- return null;
- }
- return originalTarget.cloneFilledIn(proposedRefinement, 0); // TODO: select the right base.
- }
-
- // TODO: return the actual match, to use as the base that we fill in? Or, if that's handled by
- // `TargetInfo.cloneFilledIn()`, just let it be nullable (it already is?) and don't bother doing
- // this pre-check.
- private static boolean checkProposalRefinesSourceIntent(
- TargetInfo originalTarget, Intent proposedMatch) {
- return originalTarget.getAllSourceIntents().stream().anyMatch(proposedMatch::filterEquals);
- }
}
diff --git a/java/src/com/android/intentresolver/chooser/DisplayResolveInfo.java b/java/src/com/android/intentresolver/chooser/DisplayResolveInfo.java
index 0bbd6901..29be6dc6 100644
--- a/java/src/com/android/intentresolver/chooser/DisplayResolveInfo.java
+++ b/java/src/com/android/intentresolver/chooser/DisplayResolveInfo.java
@@ -96,25 +96,22 @@ public class DisplayResolveInfo implements TargetInfo {
final ActivityInfo ai = mResolveInfo.activityInfo;
mIsSuspended = (ai.applicationInfo.flags & ApplicationInfo.FLAG_SUSPENDED) != 0;
- final Intent intent = new Intent(resolvedIntent);
- intent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT
- | Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP);
- intent.setComponent(new ComponentName(ai.applicationInfo.packageName, ai.name));
- mResolvedIntent = intent;
+ mResolvedIntent = createResolvedIntent(resolvedIntent, ai);
}
private DisplayResolveInfo(
DisplayResolveInfo other,
- Intent fillInIntent,
- int flags,
+ @Nullable Intent baseIntentToSend,
TargetPresentationGetter presentationGetter) {
mSourceIntents.addAll(other.getAllSourceIntents());
mResolveInfo = other.mResolveInfo;
mIsSuspended = other.mIsSuspended;
mDisplayLabel = other.mDisplayLabel;
mExtendedInfo = other.mExtendedInfo;
- mResolvedIntent = new Intent(other.mResolvedIntent);
- mResolvedIntent.fillIn(fillInIntent, flags);
+
+ mResolvedIntent = createResolvedIntent(
+ baseIntentToSend == null ? other.mResolvedIntent : baseIntentToSend,
+ mResolveInfo.activityInfo);
mPresentationGetter = presentationGetter;
mDisplayIconHolder.setDisplayIcon(other.mDisplayIconHolder.getDisplayIcon());
@@ -132,6 +129,14 @@ public class DisplayResolveInfo implements TargetInfo {
mDisplayIconHolder.setDisplayIcon(other.mDisplayIconHolder.getDisplayIcon());
}
+ private static Intent createResolvedIntent(Intent resolvedIntent, ActivityInfo ai) {
+ final Intent result = new Intent(resolvedIntent);
+ result.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT
+ | Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP);
+ result.setComponent(new ComponentName(ai.applicationInfo.packageName, ai.name));
+ return result;
+ }
+
@Override
public final boolean isDisplayResolveInfo() {
return true;
@@ -167,12 +172,21 @@ public class DisplayResolveInfo implements TargetInfo {
}
@Override
- public TargetInfo cloneFilledIn(Intent fillInIntent, int flags) {
- return cloneFilledInInternal(fillInIntent, flags);
- }
+ @Nullable
+ public DisplayResolveInfo tryToCloneWithAppliedRefinement(Intent proposedRefinement) {
+ Intent matchingBase =
+ getAllSourceIntents()
+ .stream()
+ .filter(i -> i.filterEquals(proposedRefinement))
+ .findFirst()
+ .orElse(null);
+ if (matchingBase == null) {
+ return null;
+ }
- protected final DisplayResolveInfo cloneFilledInInternal(Intent fillInIntent, int flags) {
- return new DisplayResolveInfo(this, fillInIntent, flags, mPresentationGetter);
+ Intent merged = new Intent(matchingBase);
+ merged.fillIn(proposedRefinement, 0);
+ return new DisplayResolveInfo(this, merged, mPresentationGetter);
}
@Override
diff --git a/java/src/com/android/intentresolver/chooser/ImmutableTargetInfo.java b/java/src/com/android/intentresolver/chooser/ImmutableTargetInfo.java
index 38991c78..2d9683e1 100644
--- a/java/src/com/android/intentresolver/chooser/ImmutableTargetInfo.java
+++ b/java/src/com/android/intentresolver/chooser/ImmutableTargetInfo.java
@@ -16,6 +16,7 @@
package com.android.intentresolver.chooser;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.Activity;
import android.app.prediction.AppTarget;
@@ -27,7 +28,6 @@ import android.content.pm.ShortcutInfo;
import android.os.Bundle;
import android.os.UserHandle;
import android.util.HashedStringCache;
-import android.util.Log;
import androidx.annotation.VisibleForTesting;
@@ -84,6 +84,15 @@ public final class ImmutableTargetInfo implements TargetInfo {
private ComponentName mResolvedComponentName;
@Nullable
+ private Intent mResolvedIntent;
+
+ @Nullable
+ private Intent mBaseIntentToSend;
+
+ @Nullable
+ private Intent mTargetIntent;
+
+ @Nullable
private ComponentName mChooserTargetComponentName;
@Nullable
@@ -101,20 +110,29 @@ public final class ImmutableTargetInfo implements TargetInfo {
@Nullable
private Intent mReferrerFillInIntent;
- private Intent mResolvedIntent;
- private Intent mTargetIntent;
+ @Nullable
private TargetActivityStarter mActivityStarter;
+
+ @Nullable
private ResolveInfo mResolveInfo;
+
+ @Nullable
private CharSequence mDisplayLabel;
+
+ @Nullable
private CharSequence mExtendedInfo;
+
+ @Nullable
private IconHolder mDisplayIconHolder;
- private List<Intent> mSourceIntents;
- private List<DisplayResolveInfo> mAllDisplayTargets;
+
private boolean mIsSuspended;
private boolean mIsPinned;
private float mModifiedScore = -0.1f;
private LegacyTargetType mLegacyType = LegacyTargetType.NOT_LEGACY_TARGET;
+ private ImmutableList<Intent> mAlternateSourceIntents = ImmutableList.of();
+ private ImmutableList<DisplayResolveInfo> mAllDisplayTargets = ImmutableList.of();
+
/**
* Configure an {@link Intent} to be built in to the output target as the resolution for the
* requested target data.
@@ -125,6 +143,17 @@ public final class ImmutableTargetInfo implements TargetInfo {
}
/**
+ * Configure an {@link Intent} to be built in to the output target as the "base intent to
+ * send," which may be a refinement of any of our source targets. This is private because
+ * it's only used internally by {@link #tryToCloneWithAppliedRefinement()}; if it's ever
+ * expanded, the builder should probably be responsible for enforcing the refinement check.
+ */
+ private Builder setBaseIntentToSend(Intent baseIntent) {
+ mBaseIntentToSend = baseIntent;
+ return this;
+ }
+
+ /**
* Configure an {@link Intent} to be built in to the output as the "target intent."
*/
public Builder setTargetIntent(Intent targetIntent) {
@@ -192,15 +221,33 @@ public final class ImmutableTargetInfo implements TargetInfo {
return this;
}
- /** Configure the list of source intents to be built in to the output target. */
+ /** Configure the list of alternate source intents we could resolve for this target. */
+ public Builder setAlternateSourceIntents(List<Intent> sourceIntents) {
+ mAlternateSourceIntents = immutableCopyOrEmpty(sourceIntents);
+ return this;
+ }
+
+ /**
+ * Configure the full list of source intents we could resolve for this target. This is
+ * effectively the same as calling {@link #setResolvedIntent()} with the first element of
+ * the list, and {@link #setAlternateSourceIntents()} with the remainder (or clearing those
+ * fields on the builder if there are no corresponding elements in the list).
+ */
public Builder setAllSourceIntents(List<Intent> sourceIntents) {
- mSourceIntents = sourceIntents;
+ if ((sourceIntents == null) || sourceIntents.isEmpty()) {
+ setResolvedIntent(null);
+ setAlternateSourceIntents(null);
+ return this;
+ }
+
+ setResolvedIntent(sourceIntents.get(0));
+ setAlternateSourceIntents(sourceIntents.subList(1, sourceIntents.size()));
return this;
}
/** Configure the list of display targets to be built in to the output target. */
public Builder setAllDisplayTargets(List<DisplayResolveInfo> targets) {
- mAllDisplayTargets = targets;
+ mAllDisplayTargets = immutableCopyOrEmpty(targets);
return this;
}
@@ -246,28 +293,27 @@ public final class ImmutableTargetInfo implements TargetInfo {
return this;
}
- Builder setLegacyType(LegacyTargetType legacyType) {
+ Builder setLegacyType(@NonNull LegacyTargetType legacyType) {
mLegacyType = legacyType;
return this;
}
- /**
- * Construct an {@code ImmutableTargetInfo} with the current builder data, where the
- * provided intent is used to fill in missing values from the resolved intent before the
- * target is (potentially) ever launched.
- *
- * @see android.content.Intent#fillIn(Intent, int)
- */
- public ImmutableTargetInfo buildWithFillInIntent(
- @Nullable Intent fillInIntent, int fillInFlags) {
- Intent baseIntentToSend = mResolvedIntent;
- if (baseIntentToSend == null) {
- Log.w(TAG, "No base intent to send");
- } else {
+ /** Construct an {@code ImmutableTargetInfo} with the current builder data. */
+ public ImmutableTargetInfo build() {
+ List<Intent> sourceIntents = new ArrayList<>();
+ if (mResolvedIntent != null) {
+ sourceIntents.add(mResolvedIntent);
+ }
+ if (mAlternateSourceIntents != null) {
+ sourceIntents.addAll(mAlternateSourceIntents);
+ }
+
+ Intent baseIntentToSend = mBaseIntentToSend;
+ if ((baseIntentToSend == null) && !sourceIntents.isEmpty()) {
+ baseIntentToSend = sourceIntents.get(0);
+ }
+ if (baseIntentToSend != null) {
baseIntentToSend = new Intent(baseIntentToSend);
- if (fillInIntent != null) {
- baseIntentToSend.fillIn(fillInIntent, fillInFlags);
- }
if (mReferrerFillInIntent != null) {
baseIntentToSend.fillIn(mReferrerFillInIntent, 0);
}
@@ -275,7 +321,7 @@ public final class ImmutableTargetInfo implements TargetInfo {
return new ImmutableTargetInfo(
baseIntentToSend,
- mResolvedIntent,
+ ImmutableList.copyOf(sourceIntents),
mTargetIntent,
mReferrerFillInIntent,
mResolvedComponentName,
@@ -285,7 +331,6 @@ public final class ImmutableTargetInfo implements TargetInfo {
mDisplayLabel,
mExtendedInfo,
mDisplayIconHolder,
- mSourceIntents,
mAllDisplayTargets,
mIsSuspended,
mIsPinned,
@@ -296,11 +341,6 @@ public final class ImmutableTargetInfo implements TargetInfo {
mHashProvider,
mLegacyType);
}
-
- /** Construct an {@code ImmutableTargetInfo} with the current builder data. */
- public ImmutableTargetInfo build() {
- return buildWithFillInIntent(null, 0);
- }
}
@Nullable
@@ -325,14 +365,13 @@ public final class ImmutableTargetInfo implements TargetInfo {
private final TargetHashProvider mHashProvider;
private final Intent mBaseIntentToSend;
- private final Intent mResolvedIntent;
+ private final ImmutableList<Intent> mSourceIntents;
private final Intent mTargetIntent;
private final TargetActivityStarter mActivityStarter;
private final ResolveInfo mResolveInfo;
private final CharSequence mDisplayLabel;
private final CharSequence mExtendedInfo;
private final IconHolder mDisplayIconHolder;
- private final ImmutableList<Intent> mSourceIntents;
private final ImmutableList<DisplayResolveInfo> mAllDisplayTargets;
private final boolean mIsSuspended;
private final boolean mIsPinned;
@@ -347,6 +386,7 @@ public final class ImmutableTargetInfo implements TargetInfo {
/** Construct a {@link Builder} pre-initialized to match this target. */
public Builder toBuilder() {
return newBuilder()
+ .setBaseIntentToSend(getBaseIntentToSend())
.setResolvedIntent(getResolvedIntent())
.setTargetIntent(getTargetIntent())
.setReferrerFillInIntent(getReferrerFillInIntent())
@@ -375,13 +415,26 @@ public final class ImmutableTargetInfo implements TargetInfo {
}
@Override
- public ImmutableTargetInfo cloneFilledIn(Intent fillInIntent, int flags) {
- return toBuilder().buildWithFillInIntent(fillInIntent, flags);
+ @Nullable
+ public ImmutableTargetInfo tryToCloneWithAppliedRefinement(Intent proposedRefinement) {
+ Intent matchingBase =
+ getAllSourceIntents()
+ .stream()
+ .filter(i -> i.filterEquals(proposedRefinement))
+ .findFirst()
+ .orElse(null);
+ if (matchingBase == null) {
+ return null;
+ }
+
+ Intent merged = new Intent(matchingBase);
+ merged.fillIn(proposedRefinement, 0);
+ return toBuilder().setBaseIntentToSend(merged).build();
}
@Override
public Intent getResolvedIntent() {
- return mResolvedIntent;
+ return (mSourceIntents.isEmpty() ? null : mSourceIntents.get(0));
}
@Override
@@ -408,11 +461,13 @@ public final class ImmutableTargetInfo implements TargetInfo {
@Override
public boolean startAsCaller(Activity activity, Bundle options, int userId) {
+ // TODO: make sure that the component name is set in all cases
return mActivityStarter.startAsCaller(this, activity, options, userId);
}
@Override
public boolean startAsUser(Activity activity, Bundle options, UserHandle user) {
+ // TODO: make sure that the component name is set in all cases
return mActivityStarter.startAsUser(this, activity, options, user);
}
@@ -531,7 +586,7 @@ public final class ImmutableTargetInfo implements TargetInfo {
private ImmutableTargetInfo(
Intent baseIntentToSend,
- Intent resolvedIntent,
+ ImmutableList<Intent> sourceIntents,
Intent targetIntent,
@Nullable Intent referrerFillInIntent,
@Nullable ComponentName resolvedComponentName,
@@ -541,8 +596,7 @@ public final class ImmutableTargetInfo implements TargetInfo {
CharSequence displayLabel,
CharSequence extendedInfo,
IconHolder iconHolder,
- @Nullable List<Intent> sourceIntents,
- @Nullable List<DisplayResolveInfo> allDisplayTargets,
+ ImmutableList<DisplayResolveInfo> allDisplayTargets,
boolean isSuspended,
boolean isPinned,
float modifiedScore,
@@ -552,7 +606,7 @@ public final class ImmutableTargetInfo implements TargetInfo {
@Nullable TargetHashProvider hashProvider,
LegacyTargetType legacyType) {
mBaseIntentToSend = baseIntentToSend;
- mResolvedIntent = resolvedIntent;
+ mSourceIntents = sourceIntents;
mTargetIntent = targetIntent;
mReferrerFillInIntent = referrerFillInIntent;
mResolvedComponentName = resolvedComponentName;
@@ -562,8 +616,7 @@ public final class ImmutableTargetInfo implements TargetInfo {
mDisplayLabel = displayLabel;
mExtendedInfo = extendedInfo;
mDisplayIconHolder = iconHolder;
- mSourceIntents = immutableCopyOrEmpty(sourceIntents);
- mAllDisplayTargets = immutableCopyOrEmpty(allDisplayTargets);
+ mAllDisplayTargets = allDisplayTargets;
mIsSuspended = isSuspended;
mIsPinned = isPinned;
mModifiedScore = modifiedScore;
diff --git a/java/src/com/android/intentresolver/chooser/MultiDisplayResolveInfo.java b/java/src/com/android/intentresolver/chooser/MultiDisplayResolveInfo.java
index 0938c55e..b97e6b45 100644
--- a/java/src/com/android/intentresolver/chooser/MultiDisplayResolveInfo.java
+++ b/java/src/com/android/intentresolver/chooser/MultiDisplayResolveInfo.java
@@ -21,7 +21,10 @@ import android.content.Intent;
import android.os.Bundle;
import android.os.UserHandle;
+import androidx.annotation.Nullable;
+
import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
/**
@@ -93,10 +96,19 @@ public class MultiDisplayResolveInfo extends DisplayResolveInfo {
}
@Override
- public TargetInfo cloneFilledIn(Intent fillInIntent, int flags) {
- ArrayList<DisplayResolveInfo> targetInfos = new ArrayList<>(mTargetInfos.size());
- for (int i = 0, size = mTargetInfos.size(); i < size; i++) {
- targetInfos.add(mTargetInfos.get(i).cloneFilledInInternal(fillInIntent, flags));
+ @Nullable
+ public MultiDisplayResolveInfo tryToCloneWithAppliedRefinement(Intent proposedRefinement) {
+ final int size = mTargetInfos.size();
+ ArrayList<DisplayResolveInfo> targetInfos = new ArrayList<>(size);
+ for (int i = 0; i < size; i++) {
+ DisplayResolveInfo target = mTargetInfos.get(i);
+ DisplayResolveInfo targetClone = (i == mSelected)
+ ? target.tryToCloneWithAppliedRefinement(proposedRefinement)
+ : new DisplayResolveInfo(target);
+ if (targetClone == null) {
+ return null;
+ }
+ targetInfos.add(targetClone);
}
MultiDisplayResolveInfo clone = new MultiDisplayResolveInfo(targetInfos);
clone.mSelected = mSelected;
@@ -117,4 +129,11 @@ public class MultiDisplayResolveInfo extends DisplayResolveInfo {
public Intent getTargetIntent() {
return mTargetInfos.get(mSelected).getTargetIntent();
}
+
+ @Override
+ public List<Intent> getAllSourceIntents() {
+ return hasSelected()
+ ? mTargetInfos.get(mSelected).getAllSourceIntents()
+ : Collections.emptyList();
+ }
}
diff --git a/java/src/com/android/intentresolver/chooser/SelectableTargetInfo.java b/java/src/com/android/intentresolver/chooser/SelectableTargetInfo.java
index df27c2b0..1fbe2da7 100644
--- a/java/src/com/android/intentresolver/chooser/SelectableTargetInfo.java
+++ b/java/src/com/android/intentresolver/chooser/SelectableTargetInfo.java
@@ -78,7 +78,6 @@ public final class SelectableTargetInfo extends ChooserTargetInfo {
private final CharSequence mChooserTargetUnsanitizedTitle;
private final Icon mChooserTargetIcon;
private final Bundle mChooserTargetIntentExtras;
- private final int mFillInFlags;
private final boolean mIsPinned;
private final float mModifiedScore;
private final boolean mIsSuspended;
@@ -91,12 +90,6 @@ public final class SelectableTargetInfo extends ChooserTargetInfo {
private final TargetActivityStarter mActivityStarter;
/**
- * A refinement intent from the caller, if any (see
- * {@link Intent#EXTRA_CHOOSER_REFINEMENT_INTENT_SENDER})
- */
- private final Intent mFillInIntent;
-
- /**
* An intent containing referrer URI (see {@link Activity#getReferrer()} (possibly {@code null})
* in its extended data under the key {@link Intent#EXTRA_REFERRER}.
*/
@@ -159,6 +152,7 @@ public final class SelectableTargetInfo extends ChooserTargetInfo {
sourceInfo,
backupResolveInfo,
resolvedIntent,
+ null,
chooserTargetComponentName,
chooserTargetUnsanitizedTitle,
chooserTargetIcon,
@@ -166,15 +160,14 @@ public final class SelectableTargetInfo extends ChooserTargetInfo {
modifiedScore,
shortcutInfo,
appTarget,
- referrerFillInIntent,
- /* fillInIntent = */ null,
- /* fillInFlags = */ 0);
+ referrerFillInIntent);
}
private SelectableTargetInfo(
@Nullable DisplayResolveInfo sourceInfo,
@Nullable ResolveInfo backupResolveInfo,
Intent resolvedIntent,
+ @Nullable Intent baseIntentToSend,
ComponentName chooserTargetComponentName,
CharSequence chooserTargetUnsanitizedTitle,
Icon chooserTargetIcon,
@@ -182,9 +175,7 @@ public final class SelectableTargetInfo extends ChooserTargetInfo {
float modifiedScore,
@Nullable ShortcutInfo shortcutInfo,
@Nullable AppTarget appTarget,
- Intent referrerFillInIntent,
- @Nullable Intent fillInIntent,
- int fillInFlags) {
+ Intent referrerFillInIntent) {
mSourceInfo = sourceInfo;
mBackupResolveInfo = backupResolveInfo;
mResolvedIntent = resolvedIntent;
@@ -192,8 +183,6 @@ public final class SelectableTargetInfo extends ChooserTargetInfo {
mShortcutInfo = shortcutInfo;
mAppTarget = appTarget;
mReferrerFillInIntent = referrerFillInIntent;
- mFillInIntent = fillInIntent;
- mFillInFlags = fillInFlags;
mChooserTargetComponentName = chooserTargetComponentName;
mChooserTargetUnsanitizedTitle = chooserTargetUnsanitizedTitle;
mChooserTargetIcon = chooserTargetIcon;
@@ -209,9 +198,8 @@ public final class SelectableTargetInfo extends ChooserTargetInfo {
mAllSourceIntents = getAllSourceIntents(sourceInfo);
mBaseIntentToSend = getBaseIntentToSend(
+ baseIntentToSend,
mResolvedIntent,
- mFillInIntent,
- mFillInFlags,
mReferrerFillInIntent);
mHashProvider = context -> {
@@ -262,11 +250,12 @@ public final class SelectableTargetInfo extends ChooserTargetInfo {
};
}
- private SelectableTargetInfo(SelectableTargetInfo other, Intent fillInIntent, int flags) {
+ private SelectableTargetInfo(SelectableTargetInfo other, Intent baseIntentToSend) {
this(
other.mSourceInfo,
other.mBackupResolveInfo,
other.mResolvedIntent,
+ baseIntentToSend,
other.mChooserTargetComponentName,
other.mChooserTargetUnsanitizedTitle,
other.mChooserTargetIcon,
@@ -274,14 +263,25 @@ public final class SelectableTargetInfo extends ChooserTargetInfo {
other.mModifiedScore,
other.mShortcutInfo,
other.mAppTarget,
- other.mReferrerFillInIntent,
- fillInIntent,
- flags);
+ other.mReferrerFillInIntent);
}
@Override
- public TargetInfo cloneFilledIn(Intent fillInIntent, int flags) {
- return new SelectableTargetInfo(this, fillInIntent, flags);
+ @Nullable
+ public TargetInfo tryToCloneWithAppliedRefinement(Intent proposedRefinement) {
+ Intent matchingBase =
+ getAllSourceIntents()
+ .stream()
+ .filter(i -> i.filterEquals(proposedRefinement))
+ .findFirst()
+ .orElse(null);
+ if (matchingBase == null) {
+ return null;
+ }
+
+ Intent merged = new Intent(matchingBase);
+ merged.fillIn(proposedRefinement, 0);
+ return new SelectableTargetInfo(this, merged);
}
@Override
@@ -418,18 +418,14 @@ public final class SelectableTargetInfo extends ChooserTargetInfo {
@Nullable
private static Intent getBaseIntentToSend(
- @Nullable Intent resolvedIntent,
- Intent fillInIntent,
- int fillInFlags,
+ @Nullable Intent providedBase,
+ @Nullable Intent fallbackBase,
Intent referrerFillInIntent) {
- Intent result = resolvedIntent;
+ Intent result = (providedBase != null) ? providedBase : fallbackBase;
if (result == null) {
Log.e(TAG, "ChooserTargetInfo: no base intent available to send");
} else {
result = new Intent(result);
- if (fillInIntent != null) {
- result.fillIn(fillInIntent, fillInFlags);
- }
result.fillIn(referrerFillInIntent, 0);
}
return result;
diff --git a/java/src/com/android/intentresolver/chooser/TargetInfo.java b/java/src/com/android/intentresolver/chooser/TargetInfo.java
index 69f58a7b..2f48704c 100644
--- a/java/src/com/android/intentresolver/chooser/TargetInfo.java
+++ b/java/src/com/android/intentresolver/chooser/TargetInfo.java
@@ -182,10 +182,25 @@ public interface TargetInfo {
default boolean hasDisplayIcon() {
return getDisplayIconHolder().getDisplayIcon() != null;
}
+
/**
- * Clone this target with the given fill-in information.
+ * Attempt to apply a {@code proposedRefinement} that the {@link ChooserRefinementManager}
+ * received from the caller's refinement flow. This may succeed only if the target has a source
+ * intent that matches the filtering parameters of the proposed refinement (according to
+ * {@link Intent#filterEquals()}). Then the first such match is the "base intent," and the
+ * proposed refinement is merged into that base (via {@link Intent#fillIn()}; this can never
+ * result in a change to the {@link Intent#filterEquals()} status of the base, but may e.g. add
+ * new "extras" that weren't previously given in the base intent).
+ *
+ * @return a copy of this {@link TargetInfo} where the "base intent to send" is the result of
+ * merging the refinement into the best-matching source intent, if possible. If there is no
+ * suitable match for the proposed refinement, or if merging fails for any other reason, this
+ * returns null.
+ *
+ * @see android.content.Intent#fillIn(Intent, int)
*/
- TargetInfo cloneFilledIn(Intent fillInIntent, int flags);
+ @Nullable
+ TargetInfo tryToCloneWithAppliedRefinement(Intent proposedRefinement);
/**
* @return the list of supported source intents deduped against this single target