diff options
author | 2023-03-03 01:34:25 +0000 | |
---|---|---|
committer | 2023-03-03 01:34:25 +0000 | |
commit | 30b80f61506b61a1182c03e696f1327dbb1540bc (patch) | |
tree | b130179b70809c4d5871ccbd4eecca64b3a7601c /java/src | |
parent | b15f2315544c33d1792bfc53bf87dd2576a800ef (diff) | |
parent | 8a081608bb679f5f922e101d8971220c21ac5d07 (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')
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 |