Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2ed547e5 authored by Adam Powell's avatar Adam Powell
Browse files

Add alternate intents and refinement callbacks to ChooserActivity

Allow a calling app to supply an array of additional Intents to the
system ChooserActivity.

The chooser will present a merged list of targets that can handle any
of the Intents supplied, including both the standard EXTRA_INTENT as
well as any of the intents supplied in EXTRA_ALTERNATE_INTENTS. These are
treated as ordered; EXTRA_INTENT is considered the first/primary
Intent and EXTRA_ALTERNATE_INTENTS are sorted most important first.

Targets are queried for all supplied Intents. If the same component is
returned for more than one Intent, the target is associated with the
most important Intent that matched.

This allows calling apps to supply several different payloads for an
action depending on what the intended targets are able to support. For
example, an app performing ACTION_SEND may supply image/jpeg data to
compatible targets or a hosted web link to targets that only support
text/plain. The user will have the opportunity to pick from a single
merged list of choices using the best available payload, and will not
be bothered with the implementation details of how the payload will be
delivered to the recipient.

If the calling app wishes to provide further disambiguation or
refinement after the user makes a choice, for example to let the user
choose which of the source intents to send from the primary or
alternates, show a progress dialog as a full-resolution version of a
photo is downloaded from the server before being sent along or while
reticulating splines, the caller can supply an IntentSender to
ACTION_CHOOSER including the extra EXTRA_REFINEMENT_INTENT_SENDER.
This should be the IntentSender obtained from a PendingIntent pointing
at an activity to launch to perform the refinement.

The refinement activity should report that it is finished by obtaining
the ResultReceiver from EXTRA_RESULT_RECEIVER. Available intents to
send to the selected target will be contained in EXTRA_INTENT and
EXTRA_ALTERNATE_INTENTS.

To complete the refinement and send the result along to the chosen
target, the refinement activity should select one of the supplied
intents and send it to the ResultReceiver in a Bundle with the key
EXTRA_INTENT and the result code RESULT_OK. To cancel the refinement,
and let the user select another choice, send RESULT_CANCEL.

While refinement activities cannot modify the filterEquals-affecting
fields of the Intent they return, they may modify extras to provide
additional or altered details to the final recipient. These extras
will be filled into the Intent sent to the final target.

Change-Id: I7ad4739eadd1a0e307675847ccf47ea948918a3a
parent 6223ec12
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -8282,6 +8282,7 @@ package android.content {
    field public static final java.lang.String EXTRA_ALARM_COUNT = "android.intent.extra.ALARM_COUNT";
    field public static final java.lang.String EXTRA_ALLOW_MULTIPLE = "android.intent.extra.ALLOW_MULTIPLE";
    field public static final deprecated java.lang.String EXTRA_ALLOW_REPLACE = "android.intent.extra.ALLOW_REPLACE";
    field public static final java.lang.String EXTRA_ALTERNATE_INTENTS = "android.intent.extra.ALTERNATE_INTENTS";
    field public static final java.lang.String EXTRA_ASSIST_CONTEXT = "android.intent.extra.ASSIST_CONTEXT";
    field public static final java.lang.String EXTRA_ASSIST_INPUT_HINT_KEYBOARD = "android.intent.extra.ASSIST_INPUT_HINT_KEYBOARD";
    field public static final java.lang.String EXTRA_ASSIST_PACKAGE = "android.intent.extra.ASSIST_PACKAGE";
@@ -8293,6 +8294,7 @@ package android.content {
    field public static final java.lang.String EXTRA_CHANGED_COMPONENT_NAME_LIST = "android.intent.extra.changed_component_name_list";
    field public static final java.lang.String EXTRA_CHANGED_PACKAGE_LIST = "android.intent.extra.changed_package_list";
    field public static final java.lang.String EXTRA_CHANGED_UID_LIST = "android.intent.extra.changed_uid_list";
    field public static final java.lang.String EXTRA_CHOOSER_REFINEMENT_INTENT_SENDER = "android.intent.extra.CHOOSER_REFINEMENT_INTENT_SENDER";
    field public static final java.lang.String EXTRA_CHOOSER_TARGETS = "android.intent.extra.CHOOSER_TARGETS";
    field public static final java.lang.String EXTRA_CHOSEN_COMPONENT = "android.intent.extra.CHOSEN_COMPONENT";
    field public static final java.lang.String EXTRA_CHOSEN_COMPONENT_INTENT_SENDER = "android.intent.extra.CHOSEN_COMPONENT_INTENT_SENDER";
@@ -8325,6 +8327,7 @@ package android.content {
    field public static final java.lang.String EXTRA_RESTRICTIONS_BUNDLE = "android.intent.extra.restrictions_bundle";
    field public static final java.lang.String EXTRA_RESTRICTIONS_INTENT = "android.intent.extra.restrictions_intent";
    field public static final java.lang.String EXTRA_RESTRICTIONS_LIST = "android.intent.extra.restrictions_list";
    field public static final java.lang.String EXTRA_RESULT_RECEIVER = "android.intent.extra.RESULT_RECEIVER";
    field public static final java.lang.String EXTRA_RETURN_RESULT = "android.intent.extra.RETURN_RESULT";
    field public static final java.lang.String EXTRA_SHORTCUT_ICON = "android.intent.extra.shortcut.ICON";
    field public static final java.lang.String EXTRA_SHORTCUT_ICON_RESOURCE = "android.intent.extra.shortcut.ICON_RESOURCE";
+3 −0
Original line number Diff line number Diff line
@@ -8508,6 +8508,7 @@ package android.content {
    field public static final java.lang.String EXTRA_ALARM_COUNT = "android.intent.extra.ALARM_COUNT";
    field public static final java.lang.String EXTRA_ALLOW_MULTIPLE = "android.intent.extra.ALLOW_MULTIPLE";
    field public static final deprecated java.lang.String EXTRA_ALLOW_REPLACE = "android.intent.extra.ALLOW_REPLACE";
    field public static final java.lang.String EXTRA_ALTERNATE_INTENTS = "android.intent.extra.ALTERNATE_INTENTS";
    field public static final java.lang.String EXTRA_ASSIST_CONTEXT = "android.intent.extra.ASSIST_CONTEXT";
    field public static final java.lang.String EXTRA_ASSIST_INPUT_HINT_KEYBOARD = "android.intent.extra.ASSIST_INPUT_HINT_KEYBOARD";
    field public static final java.lang.String EXTRA_ASSIST_PACKAGE = "android.intent.extra.ASSIST_PACKAGE";
@@ -8519,6 +8520,7 @@ package android.content {
    field public static final java.lang.String EXTRA_CHANGED_COMPONENT_NAME_LIST = "android.intent.extra.changed_component_name_list";
    field public static final java.lang.String EXTRA_CHANGED_PACKAGE_LIST = "android.intent.extra.changed_package_list";
    field public static final java.lang.String EXTRA_CHANGED_UID_LIST = "android.intent.extra.changed_uid_list";
    field public static final java.lang.String EXTRA_CHOOSER_REFINEMENT_INTENT_SENDER = "android.intent.extra.CHOOSER_REFINEMENT_INTENT_SENDER";
    field public static final java.lang.String EXTRA_CHOOSER_TARGETS = "android.intent.extra.CHOOSER_TARGETS";
    field public static final java.lang.String EXTRA_CHOSEN_COMPONENT = "android.intent.extra.CHOSEN_COMPONENT";
    field public static final java.lang.String EXTRA_CHOSEN_COMPONENT_INTENT_SENDER = "android.intent.extra.CHOSEN_COMPONENT_INTENT_SENDER";
@@ -8554,6 +8556,7 @@ package android.content {
    field public static final java.lang.String EXTRA_RESTRICTIONS_BUNDLE = "android.intent.extra.restrictions_bundle";
    field public static final java.lang.String EXTRA_RESTRICTIONS_INTENT = "android.intent.extra.restrictions_intent";
    field public static final java.lang.String EXTRA_RESTRICTIONS_LIST = "android.intent.extra.restrictions_list";
    field public static final java.lang.String EXTRA_RESULT_RECEIVER = "android.intent.extra.RESULT_RECEIVER";
    field public static final java.lang.String EXTRA_RETURN_RESULT = "android.intent.extra.RETURN_RESULT";
    field public static final java.lang.String EXTRA_SHORTCUT_ICON = "android.intent.extra.shortcut.ICON";
    field public static final java.lang.String EXTRA_SHORTCUT_ICON_RESOURCE = "android.intent.extra.shortcut.ICON_RESOURCE";
+70 −1
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package android.content;

import android.content.pm.ApplicationInfo;
import android.os.ResultReceiver;
import android.provider.MediaStore;
import android.util.ArraySet;

@@ -3291,10 +3292,78 @@ public class Intent implements Parcelable, Cloneable {

    /**
     * An Intent describing the choices you would like shown with
     * {@link #ACTION_PICK_ACTIVITY}.
     * {@link #ACTION_PICK_ACTIVITY} or {@link #ACTION_CHOOSER}.
     */
    public static final String EXTRA_INTENT = "android.intent.extra.INTENT";

    /**
     * An Intent[] describing additional, alternate choices you would like shown with
     * {@link #ACTION_CHOOSER}.
     *
     * <p>An app may be capable of providing several different payload types to complete a
     * user's intended action. For example, an app invoking {@link #ACTION_SEND} to share photos
     * with another app may use EXTRA_ALTERNATE_INTENTS to have the chooser transparently offer
     * several different supported sending mechanisms for sharing, such as the actual "image/*"
     * photo data or a hosted link where the photos can be viewed.</p>
     *
     * <p>The intent present in {@link #EXTRA_INTENT} will be treated as the
     * first/primary/preferred intent in the set. Additional intents specified in
     * this extra are ordered; by default intents that appear earlier in the array will be
     * preferred over intents that appear later in the array as matches for the same
     * target component. To alter this preference, a calling app may also supply
     * {@link #EXTRA_CHOOSER_REFINEMENT_INTENT_SENDER}.</p>
     */
    public static final String EXTRA_ALTERNATE_INTENTS = "android.intent.extra.ALTERNATE_INTENTS";

    /**
     * An {@link IntentSender} for an Activity that will be invoked when the user makes a selection
     * from the chooser activity presented by {@link #ACTION_CHOOSER}.
     *
     * <p>An app preparing an action for another app to complete may wish to allow the user to
     * disambiguate between several options for completing the action based on the chosen target
     * or otherwise refine the action before it is invoked.
     * </p>
     *
     * <p>When sent, this IntentSender may be filled in with the following extras:</p>
     * <ul>
     *     <li>{@link #EXTRA_INTENT} The first intent that matched the user's chosen target</li>
     *     <li>{@link #EXTRA_ALTERNATE_INTENTS} Any additional intents that also matched the user's
     *     chosen target beyond the first</li>
     *     <li>{@link #EXTRA_RESULT_RECEIVER} A {@link ResultReceiver} that the refinement activity
     *     should fill in and send once the disambiguation is complete</li>
     * </ul>
     */
    public static final String EXTRA_CHOOSER_REFINEMENT_INTENT_SENDER
            = "android.intent.extra.CHOOSER_REFINEMENT_INTENT_SENDER";

    /**
     * A {@link ResultReceiver} used to return data back to the sender.
     *
     * <p>Used to complete an app-specific
     * {@link #EXTRA_CHOOSER_REFINEMENT_INTENT_SENDER refinement} for {@link #ACTION_CHOOSER}.</p>
     *
     * <p>If {@link #EXTRA_CHOOSER_REFINEMENT_INTENT_SENDER} is present in the intent
     * used to start a {@link #ACTION_CHOOSER} activity this extra will be
     * {@link #fillIn(Intent, int) filled in} to that {@link IntentSender} and sent
     * when the user selects a target component from the chooser. It is up to the recipient
     * to send a result to this ResultReceiver to signal that disambiguation is complete
     * and that the chooser should invoke the user's choice.</p>
     *
     * <p>The disambiguator should provide a Bundle to the ResultReceiver with an intent
     * assigned to the key {@link #EXTRA_INTENT}. This supplied intent will be used by the chooser
     * to match and fill in the final Intent or ChooserTarget before starting it.
     * The supplied intent must {@link #filterEquals(Intent) match} one of the intents from
     * {@link #EXTRA_INTENT} or {@link #EXTRA_ALTERNATE_INTENTS} passed to
     * {@link #EXTRA_CHOOSER_REFINEMENT_INTENT_SENDER} to be accepted.</p>
     *
     * <p>The result code passed to the ResultReceiver should be
     * {@link android.app.Activity#RESULT_OK} if the refinement succeeded and the supplied intent's
     * target in the chooser should be started, or {@link android.app.Activity#RESULT_CANCELED} if
     * the chooser should finish without starting a target.</p>
     */
    public static final String EXTRA_RESULT_RECEIVER
            = "android.intent.extra.RESULT_RECEIVER";

    /**
     * A CharSequence dialog title to provide to the user when used with a
     * {@link #ACTION_CHOOSER}.
+220 −13
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentSender;
import android.content.IntentSender.SendIntentException;
import android.content.ServiceConnection;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
@@ -34,6 +35,7 @@ import android.os.IBinder;
import android.os.Message;
import android.os.Parcelable;
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.UserHandle;
import android.service.chooser.ChooserTarget;
import android.service.chooser.ChooserTargetService;
@@ -53,11 +55,13 @@ public class ChooserActivity extends ResolverActivity {

    private static final boolean DEBUG = false;

    private static final int QUERY_TARGET_LIMIT = 5;
    private static final int QUERY_TARGET_SERVICE_LIMIT = 5;
    private static final int WATCHDOG_TIMEOUT_MILLIS = 5000;

    private Bundle mReplacementExtras;
    private IntentSender mChosenComponentSender;
    private IntentSender mRefinementIntentSender;
    private RefinementResultReceiver mRefinementResultReceiver;

    private ChooserTarget[] mCallerChooserTargets;

@@ -113,6 +117,32 @@ public class ChooserActivity extends ResolverActivity {
        if (target != null) {
            modifyTargetIntent(target);
        }
        Parcelable[] targetsParcelable
                = intent.getParcelableArrayExtra(Intent.EXTRA_ALTERNATE_INTENTS);
        if (targetsParcelable != null) {
            final boolean offset = target == null;
            Intent[] additionalTargets =
                    new Intent[offset ? targetsParcelable.length - 1 : targetsParcelable.length];
            for (int i = 0; i < targetsParcelable.length; i++) {
                if (!(targetsParcelable[i] instanceof Intent)) {
                    Log.w(TAG, "EXTRA_ALTERNATE_INTENTS array entry #" + i + " is not an Intent: "
                            + targetsParcelable[i]);
                    finish();
                    super.onCreate(null);
                    return;
                }
                final Intent additionalTarget = (Intent) targetsParcelable[i];
                if (i == 0 && target == null) {
                    target = additionalTarget;
                    modifyTargetIntent(target);
                } else {
                    additionalTargets[offset ? i - 1 : i] = additionalTarget;
                    modifyTargetIntent(additionalTarget);
                }
            }
            setAdditionalTargets(additionalTargets);
        }

        mReplacementExtras = intent.getBundleExtra(Intent.EXTRA_REPLACEMENT_EXTRAS);
        CharSequence title = intent.getCharSequenceExtra(Intent.EXTRA_TITLE);
        int defaultTitleRes = 0;
@@ -125,7 +155,7 @@ public class ChooserActivity extends ResolverActivity {
            initialIntents = new Intent[pa.length];
            for (int i=0; i<pa.length; i++) {
                if (!(pa[i] instanceof Intent)) {
                    Log.w("ChooserActivity", "Initial intent #" + i + " not an Intent: " + pa[i]);
                    Log.w(TAG, "Initial intent #" + i + " not an Intent: " + pa[i]);
                    finish();
                    super.onCreate(null);
                    return;
@@ -141,8 +171,7 @@ public class ChooserActivity extends ResolverActivity {
            final ChooserTarget[] targets = new ChooserTarget[pa.length];
            for (int i = 0; i < pa.length; i++) {
                if (!(pa[i] instanceof ChooserTarget)) {
                    Log.w("ChooserActivity", "Chooser target #" + i + " is not a ChooserTarget: " +
                            pa[i]);
                    Log.w(TAG, "Chooser target #" + i + " is not a ChooserTarget: " + pa[i]);
                    finish();
                    super.onCreate(null);
                    return;
@@ -153,11 +182,22 @@ public class ChooserActivity extends ResolverActivity {
        }
        mChosenComponentSender = intent.getParcelableExtra(
                Intent.EXTRA_CHOSEN_COMPONENT_INTENT_SENDER);
        mRefinementIntentSender = intent.getParcelableExtra(
                Intent.EXTRA_CHOOSER_REFINEMENT_INTENT_SENDER);
        setSafeForwardingMode(true);
        super.onCreate(savedInstanceState, target, title, defaultTitleRes, initialIntents,
                null, false);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (mRefinementResultReceiver != null) {
            mRefinementResultReceiver.destroy();
            mRefinementResultReceiver = null;
        }
    }

    @Override
    public Intent getReplacementIntent(ActivityInfo aInfo, Intent defIntent) {
        Intent result = defIntent;
@@ -211,6 +251,37 @@ public class ChooserActivity extends ResolverActivity {
        }
    }

    @Override
    protected boolean onTargetSelected(TargetInfo target, boolean alwaysCheck) {
        if (mRefinementIntentSender != null) {
            final Intent fillIn = new Intent();
            final List<Intent> sourceIntents = target.getAllSourceIntents();
            if (!sourceIntents.isEmpty()) {
                fillIn.putExtra(Intent.EXTRA_INTENT, sourceIntents.get(0));
                if (sourceIntents.size() > 1) {
                    final Intent[] alts = new Intent[sourceIntents.size() - 1];
                    for (int i = 1, N = sourceIntents.size(); i < N; i++) {
                        alts[i - 1] = sourceIntents.get(i);
                    }
                    fillIn.putExtra(Intent.EXTRA_ALTERNATE_INTENTS, alts);
                }
                if (mRefinementResultReceiver != null) {
                    mRefinementResultReceiver.destroy();
                }
                mRefinementResultReceiver = new RefinementResultReceiver(this, target, null);
                fillIn.putExtra(Intent.EXTRA_RESULT_RECEIVER,
                        mRefinementResultReceiver);
                try {
                    mRefinementIntentSender.sendIntent(this, 0, fillIn, null, null);
                    return false;
                } catch (SendIntentException e) {
                    Log.e(TAG, "Refinement IntentSender failed to send", e);
                }
            }
        }
        return super.onTargetSelected(target, alwaysCheck);
    }

    void queryTargetServices(ChooserListAdapter adapter) {
        final PackageManager pm = getPackageManager();
        int targetsToQuery = 0;
@@ -258,8 +329,9 @@ public class ChooserActivity extends ResolverActivity {
                    targetsToQuery++;
                }
            }
            if (targetsToQuery >= QUERY_TARGET_LIMIT) {
                if (DEBUG) Log.d(TAG, "queryTargets hit query target limit " + QUERY_TARGET_LIMIT);
            if (targetsToQuery >= QUERY_TARGET_SERVICE_LIMIT) {
                if (DEBUG) Log.d(TAG, "queryTargets hit query target limit "
                        + QUERY_TARGET_SERVICE_LIMIT);
                break;
            }
        }
@@ -303,6 +375,43 @@ public class ChooserActivity extends ResolverActivity {
        mTargetResultHandler.removeMessages(CHOOSER_TARGET_SERVICE_WATCHDOG_TIMEOUT);
    }

    void onRefinementResult(TargetInfo selectedTarget, Intent matchingIntent) {
        if (mRefinementResultReceiver != null) {
            mRefinementResultReceiver.destroy();
            mRefinementResultReceiver = null;
        }

        if (selectedTarget == null) {
            Log.e(TAG, "Refinement result intent did not match any known targets; canceling");
        } else if (!checkTargetSourceIntent(selectedTarget, matchingIntent)) {
            Log.e(TAG, "onRefinementResult: Selected target " + selectedTarget
                    + " cannot match refined source intent " + matchingIntent);
        } else if (super.onTargetSelected(selectedTarget.cloneFilledIn(matchingIntent, 0), false)) {
            finish();
            return;
        }
        onRefinementCanceled();
    }

    void onRefinementCanceled() {
        if (mRefinementResultReceiver != null) {
            mRefinementResultReceiver.destroy();
            mRefinementResultReceiver = null;
        }
        finish();
    }

    boolean checkTargetSourceIntent(TargetInfo target, Intent matchingIntent) {
        final List<Intent> targetIntents = target.getAllSourceIntents();
        for (int i = 0, N = targetIntents.size(); i < N; i++) {
            final Intent targetIntent = targetIntents.get(i);
            if (targetIntent.filterEquals(matchingIntent)) {
                return true;
            }
        }
        return false;
    }

    @Override
    ResolveListAdapter createAdapter(Context context, Intent[] initialIntents,
            List<ResolveInfo> rList, int launchedFromUid, boolean filterLastUsed) {
@@ -313,17 +422,19 @@ public class ChooserActivity extends ResolverActivity {
        return adapter;
    }

    class ChooserTargetInfo implements TargetInfo {
        private final TargetInfo mSourceInfo;
    final class ChooserTargetInfo implements TargetInfo {
        private final DisplayResolveInfo mSourceInfo;
        private final ResolveInfo mBackupResolveInfo;
        private final ChooserTarget mChooserTarget;
        private final Drawable mDisplayIcon;
        private final Intent mFillInIntent;
        private final int mFillInFlags;

        public ChooserTargetInfo(ChooserTarget target) {
            this(null, target);
        }

        public ChooserTargetInfo(TargetInfo sourceInfo, ChooserTarget chooserTarget) {
        public ChooserTargetInfo(DisplayResolveInfo sourceInfo, ChooserTarget chooserTarget) {
            mSourceInfo = sourceInfo;
            mChooserTarget = chooserTarget;
            mDisplayIcon = new BitmapDrawable(getResources(), chooserTarget.getIcon());
@@ -333,6 +444,18 @@ public class ChooserActivity extends ResolverActivity {
            } else {
                mBackupResolveInfo = getPackageManager().resolveActivity(getResolvedIntent(), 0);
            }

            mFillInIntent = null;
            mFillInFlags = 0;
        }

        private ChooserTargetInfo(ChooserTargetInfo other, Intent fillInIntent, int flags) {
            mSourceInfo = other.mSourceInfo;
            mBackupResolveInfo = other.mBackupResolveInfo;
            mChooserTarget = other.mChooserTarget;
            mDisplayIcon = other.mDisplayIcon;
            mFillInIntent = fillInIntent;
            mFillInFlags = flags;
        }

        @Override
@@ -358,22 +481,42 @@ public class ChooserActivity extends ResolverActivity {
        }

        private Intent getFillInIntent() {
            return mSourceInfo != null ? mSourceInfo.getResolvedIntent() : getTargetIntent();
            Intent result = mSourceInfo != null
                    ? mSourceInfo.getResolvedIntent() : getTargetIntent();
            if (result == null) {
                Log.e(TAG, "ChooserTargetInfo#getFillInIntent: no fillIn intent available");
            } else if (mFillInIntent != null) {
                result = new Intent(result);
                result.fillIn(mFillInIntent, mFillInFlags);
            }
            return result;
        }

        @Override
        public boolean start(Activity activity, Bundle options) {
            return mChooserTarget.sendIntent(activity, getFillInIntent());
            final Intent intent = getFillInIntent();
            if (intent == null) {
                return false;
            }
            return mChooserTarget.sendIntent(activity, intent);
        }

        @Override
        public boolean startAsCaller(Activity activity, Bundle options, int userId) {
            return mChooserTarget.sendIntentAsCaller(activity, getFillInIntent(), userId);
            final Intent intent = getFillInIntent();
            if (intent == null) {
                return false;
            }
            return mChooserTarget.sendIntentAsCaller(activity, intent, userId);
        }

        @Override
        public boolean startAsUser(Activity activity, Bundle options, UserHandle user) {
            return mChooserTarget.sendIntentAsUser(activity, getFillInIntent(), user);
            final Intent intent = getFillInIntent();
            if (intent == null) {
                return false;
            }
            return mChooserTarget.sendIntentAsUser(activity, intent, user);
        }

        @Override
@@ -395,6 +538,21 @@ public class ChooserActivity extends ResolverActivity {
        public Drawable getDisplayIcon() {
            return mDisplayIcon;
        }

        @Override
        public TargetInfo cloneFilledIn(Intent fillInIntent, int flags) {
            return new ChooserTargetInfo(this, fillInIntent, flags);
        }

        @Override
        public List<Intent> getAllSourceIntents() {
            final List<Intent> results = new ArrayList<>();
            if (mSourceInfo != null) {
                // We only queried the service for the first one in our sourceinfo.
                results.add(mSourceInfo.getAllSourceIntents().get(0));
            }
            return results;
        }
    }

    public class ChooserListAdapter extends ResolveListAdapter {
@@ -542,4 +700,53 @@ public class ChooserActivity extends ResolverActivity {
            connection = c;
        }
    }

    static class RefinementResultReceiver extends ResultReceiver {
        private ChooserActivity mChooserActivity;
        private TargetInfo mSelectedTarget;

        public RefinementResultReceiver(ChooserActivity host, TargetInfo target,
                Handler handler) {
            super(handler);
            mChooserActivity = host;
            mSelectedTarget = target;
        }

        @Override
        protected void onReceiveResult(int resultCode, Bundle resultData) {
            if (mChooserActivity == null) {
                Log.e(TAG, "Destroyed RefinementResultReceiver received a result");
                return;
            }
            if (resultData == null) {
                Log.e(TAG, "RefinementResultReceiver received null resultData");
                return;
            }

            switch (resultCode) {
                case RESULT_CANCELED:
                    mChooserActivity.onRefinementCanceled();
                    break;
                case RESULT_OK:
                    Parcelable intentParcelable = resultData.getParcelable(Intent.EXTRA_INTENT);
                    if (intentParcelable instanceof Intent) {
                        mChooserActivity.onRefinementResult(mSelectedTarget,
                                (Intent) intentParcelable);
                    } else {
                        Log.e(TAG, "RefinementResultReceiver received RESULT_OK but no Intent"
                                + " in resultData with key Intent.EXTRA_INTENT");
                    }
                    break;
                default:
                    Log.w(TAG, "Unknown result code " + resultCode
                            + " sent to RefinementResultReceiver");
                    break;
            }
        }

        public void destroy() {
            mChooserActivity = null;
            mSelectedTarget = null;
        }
    }
}
+226 −63

File changed.

Preview size limit exceeded, changes collapsed.

Loading