Merge "Add alternate intents and refinement callbacks to ChooserActivity" into mnc-dev
This commit is contained in:
@@ -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";
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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}.
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -102,7 +102,7 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic
|
||||
private int mLastSelected = AbsListView.INVALID_POSITION;
|
||||
private boolean mResolvingHome = false;
|
||||
private int mProfileSwitchMessageId = -1;
|
||||
private Intent mIntent;
|
||||
private final ArrayList<Intent> mIntents = new ArrayList<>();
|
||||
|
||||
private UsageStatsManager mUsm;
|
||||
private Map<String, UsageStats> mStats;
|
||||
@@ -229,7 +229,7 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic
|
||||
final ActivityManager am = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
|
||||
mIconDpi = am.getLauncherLargeIconDensity();
|
||||
|
||||
mIntent = new Intent(intent);
|
||||
mIntents.add(0, new Intent(intent));
|
||||
mAdapter = createAdapter(this, initialIntents, rList, mLaunchedFromUid, alwaysUseOption);
|
||||
|
||||
final int layoutId;
|
||||
@@ -250,7 +250,7 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic
|
||||
return;
|
||||
}
|
||||
|
||||
int count = mAdapter.mList.size();
|
||||
int count = mAdapter.mDisplayList.size();
|
||||
if (count > 1 || (count == 1 && mAdapter.getOtherProfile() != null)) {
|
||||
setContentView(layoutId);
|
||||
mAdapterView = (AbsListView) findViewById(R.id.resolver_list);
|
||||
@@ -376,8 +376,16 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic
|
||||
}
|
||||
}
|
||||
|
||||
protected final void setAdditionalTargets(Intent[] intents) {
|
||||
if (intents != null) {
|
||||
for (Intent intent : intents) {
|
||||
mIntents.add(intent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Intent getTargetIntent() {
|
||||
return mIntent;
|
||||
return mIntents.isEmpty() ? null : mIntents.get(0);
|
||||
}
|
||||
|
||||
private String getReferrerPackageName() {
|
||||
@@ -630,8 +638,9 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic
|
||||
}
|
||||
|
||||
TargetInfo target = mAdapter.targetInfoForPosition(which, filtered);
|
||||
onTargetSelected(target, always);
|
||||
finish();
|
||||
if (onTargetSelected(target, always)) {
|
||||
finish();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -641,7 +650,7 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic
|
||||
return defIntent;
|
||||
}
|
||||
|
||||
protected void onTargetSelected(TargetInfo target, boolean alwaysCheck) {
|
||||
protected boolean onTargetSelected(TargetInfo target, boolean alwaysCheck) {
|
||||
final ResolveInfo ri = target.getResolveInfo();
|
||||
final Intent intent = target != null ? target.getResolvedIntent() : null;
|
||||
|
||||
@@ -728,7 +737,7 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic
|
||||
ComponentName[] set = new ComponentName[N];
|
||||
int bestMatch = 0;
|
||||
for (int i=0; i<N; i++) {
|
||||
ResolveInfo r = mAdapter.mOrigResolveList.get(i);
|
||||
ResolveInfo r = mAdapter.mOrigResolveList.get(i).getResolveInfoAt(0);
|
||||
set[i] = new ComponentName(r.activityInfo.packageName,
|
||||
r.activityInfo.name);
|
||||
if (r.match > bestMatch) bestMatch = r.match;
|
||||
@@ -774,6 +783,7 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic
|
||||
if (target != null) {
|
||||
safelyStartActivity(target);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void safelyStartActivity(TargetInfo cti) {
|
||||
@@ -837,15 +847,17 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic
|
||||
private Drawable mDisplayIcon;
|
||||
private final CharSequence mExtendedInfo;
|
||||
private final Intent mResolvedIntent;
|
||||
private final List<Intent> mSourceIntents = new ArrayList<>();
|
||||
|
||||
DisplayResolveInfo(ResolveInfo pri, CharSequence pLabel,
|
||||
DisplayResolveInfo(Intent originalIntent, ResolveInfo pri, CharSequence pLabel,
|
||||
CharSequence pInfo, Intent pOrigIntent) {
|
||||
mSourceIntents.add(originalIntent);
|
||||
mResolveInfo = pri;
|
||||
mDisplayLabel = pLabel;
|
||||
mExtendedInfo = pInfo;
|
||||
|
||||
final Intent intent = new Intent(pOrigIntent != null ? pOrigIntent :
|
||||
getReplacementIntent(pri.activityInfo, mIntent));
|
||||
getReplacementIntent(pri.activityInfo, getTargetIntent()));
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT
|
||||
| Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP);
|
||||
final ActivityInfo ai = mResolveInfo.activityInfo;
|
||||
@@ -854,6 +866,16 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic
|
||||
mResolvedIntent = intent;
|
||||
}
|
||||
|
||||
private DisplayResolveInfo(DisplayResolveInfo other, Intent fillInIntent, int flags) {
|
||||
mSourceIntents.addAll(other.getAllSourceIntents());
|
||||
mResolveInfo = other.mResolveInfo;
|
||||
mDisplayLabel = other.mDisplayLabel;
|
||||
mDisplayIcon = other.mDisplayIcon;
|
||||
mExtendedInfo = other.mExtendedInfo;
|
||||
mResolvedIntent = new Intent(other.mResolvedIntent);
|
||||
mResolvedIntent.fillIn(fillInIntent, flags);
|
||||
}
|
||||
|
||||
public ResolveInfo getResolveInfo() {
|
||||
return mResolveInfo;
|
||||
}
|
||||
@@ -866,6 +888,20 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic
|
||||
return mDisplayIcon;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TargetInfo cloneFilledIn(Intent fillInIntent, int flags) {
|
||||
return new DisplayResolveInfo(this, fillInIntent, flags);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Intent> getAllSourceIntents() {
|
||||
return mSourceIntents;
|
||||
}
|
||||
|
||||
public void addAlternateSourceIntent(Intent alt) {
|
||||
mSourceIntents.add(alt);
|
||||
}
|
||||
|
||||
public void setDisplayIcon(Drawable icon) {
|
||||
mDisplayIcon = icon;
|
||||
}
|
||||
@@ -986,6 +1022,16 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic
|
||||
* @return The drawable that should be used to represent this target
|
||||
*/
|
||||
public Drawable getDisplayIcon();
|
||||
|
||||
/**
|
||||
* Clone this target with the given fill-in information.
|
||||
*/
|
||||
public TargetInfo cloneFilledIn(Intent fillInIntent, int flags);
|
||||
|
||||
/**
|
||||
* @return the list of supported source intents deduped against this single target
|
||||
*/
|
||||
public List<Intent> getAllSourceIntents();
|
||||
}
|
||||
|
||||
class ResolveListAdapter extends BaseAdapter {
|
||||
@@ -998,8 +1044,8 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic
|
||||
|
||||
protected final LayoutInflater mInflater;
|
||||
|
||||
List<DisplayResolveInfo> mList;
|
||||
List<ResolveInfo> mOrigResolveList;
|
||||
List<DisplayResolveInfo> mDisplayList;
|
||||
List<ResolvedComponentInfo> mOrigResolveList;
|
||||
|
||||
private int mLastChosenPosition = -1;
|
||||
private boolean mFilterLastUsed;
|
||||
@@ -1010,7 +1056,7 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic
|
||||
mBaseResolveList = rList;
|
||||
mLaunchedFromUid = launchedFromUid;
|
||||
mInflater = LayoutInflater.from(context);
|
||||
mList = new ArrayList<>();
|
||||
mDisplayList = new ArrayList<>();
|
||||
mFilterLastUsed = filterLastUsed;
|
||||
rebuildList();
|
||||
}
|
||||
@@ -1027,7 +1073,7 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic
|
||||
public DisplayResolveInfo getFilteredItem() {
|
||||
if (mFilterLastUsed && mLastChosenPosition >= 0) {
|
||||
// Not using getItem since it offsets to dodge this position for the list
|
||||
return mList.get(mLastChosenPosition);
|
||||
return mDisplayList.get(mLastChosenPosition);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -1048,11 +1094,12 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic
|
||||
}
|
||||
|
||||
private void rebuildList() {
|
||||
List<ResolveInfo> currentResolveList;
|
||||
List<ResolvedComponentInfo> currentResolveList = null;
|
||||
|
||||
try {
|
||||
final Intent primaryIntent = getTargetIntent();
|
||||
mLastChosen = AppGlobals.getPackageManager().getLastChosenActivity(
|
||||
mIntent, mIntent.resolveTypeIfNeeded(getContentResolver()),
|
||||
primaryIntent, primaryIntent.resolveTypeIfNeeded(getContentResolver()),
|
||||
PackageManager.MATCH_DEFAULT_ONLY);
|
||||
} catch (RemoteException re) {
|
||||
Log.d(TAG, "Error calling setLastChosenActivity\n" + re);
|
||||
@@ -1060,15 +1107,27 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic
|
||||
|
||||
// Clear the value of mOtherProfile from previous call.
|
||||
mOtherProfile = null;
|
||||
mList.clear();
|
||||
mDisplayList.clear();
|
||||
if (mBaseResolveList != null) {
|
||||
currentResolveList = mOrigResolveList = mBaseResolveList;
|
||||
currentResolveList = mOrigResolveList = new ArrayList<>();
|
||||
addResolveListDedupe(currentResolveList, getTargetIntent(), mBaseResolveList);
|
||||
} else {
|
||||
currentResolveList = mOrigResolveList = mPm.queryIntentActivities(mIntent,
|
||||
PackageManager.MATCH_DEFAULT_ONLY
|
||||
| (shouldGetResolvedFilter() ? PackageManager.GET_RESOLVED_FILTER : 0)
|
||||
| (shouldGetActivityMetadata() ? PackageManager.GET_META_DATA : 0)
|
||||
);
|
||||
final boolean shouldGetResolvedFilter = shouldGetResolvedFilter();
|
||||
final boolean shouldGetActivityMetadata = shouldGetActivityMetadata();
|
||||
for (int i = 0, N = mIntents.size(); i < N; i++) {
|
||||
final Intent intent = mIntents.get(i);
|
||||
final List<ResolveInfo> infos = mPm.queryIntentActivities(intent,
|
||||
PackageManager.MATCH_DEFAULT_ONLY
|
||||
| (shouldGetResolvedFilter ? PackageManager.GET_RESOLVED_FILTER : 0)
|
||||
| (shouldGetActivityMetadata ? PackageManager.GET_META_DATA : 0));
|
||||
if (infos != null) {
|
||||
if (currentResolveList == null) {
|
||||
currentResolveList = mOrigResolveList = new ArrayList<>();
|
||||
}
|
||||
addResolveListDedupe(currentResolveList, intent, infos);
|
||||
}
|
||||
}
|
||||
|
||||
// Filter out any activities that the launched uid does not
|
||||
// have permission for. We don't do this when we have an explicit
|
||||
// list of resolved activities, because that only happens when
|
||||
@@ -1076,14 +1135,15 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic
|
||||
// they gave us.
|
||||
if (currentResolveList != null) {
|
||||
for (int i=currentResolveList.size()-1; i >= 0; i--) {
|
||||
ActivityInfo ai = currentResolveList.get(i).activityInfo;
|
||||
ActivityInfo ai = currentResolveList.get(i)
|
||||
.getResolveInfoAt(0).activityInfo;
|
||||
int granted = ActivityManager.checkComponentPermission(
|
||||
ai.permission, mLaunchedFromUid,
|
||||
ai.applicationInfo.uid, ai.exported);
|
||||
if (granted != PackageManager.PERMISSION_GRANTED) {
|
||||
// Access not allowed!
|
||||
if (mOrigResolveList == currentResolveList) {
|
||||
mOrigResolveList = new ArrayList<ResolveInfo>(mOrigResolveList);
|
||||
mOrigResolveList = new ArrayList<>(mOrigResolveList);
|
||||
}
|
||||
currentResolveList.remove(i);
|
||||
}
|
||||
@@ -1094,9 +1154,10 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic
|
||||
if ((currentResolveList != null) && ((N = currentResolveList.size()) > 0)) {
|
||||
// Only display the first matches that are either of equal
|
||||
// priority or have asked to be default options.
|
||||
ResolveInfo r0 = currentResolveList.get(0);
|
||||
ResolvedComponentInfo rci0 = currentResolveList.get(0);
|
||||
ResolveInfo r0 = rci0.getResolveInfoAt(0);
|
||||
for (int i=1; i<N; i++) {
|
||||
ResolveInfo ri = currentResolveList.get(i);
|
||||
ResolveInfo ri = currentResolveList.get(i).getResolveInfoAt(0);
|
||||
if (DEBUG) Log.v(
|
||||
TAG,
|
||||
r0.activityInfo.name + "=" +
|
||||
@@ -1107,7 +1168,7 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic
|
||||
r0.isDefault != ri.isDefault) {
|
||||
while (i < N) {
|
||||
if (mOrigResolveList == currentResolveList) {
|
||||
mOrigResolveList = new ArrayList<ResolveInfo>(mOrigResolveList);
|
||||
mOrigResolveList = new ArrayList<>(mOrigResolveList);
|
||||
}
|
||||
currentResolveList.remove(i);
|
||||
N--;
|
||||
@@ -1115,9 +1176,8 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic
|
||||
}
|
||||
}
|
||||
if (N > 1) {
|
||||
Comparator<ResolveInfo> rComparator =
|
||||
new ResolverComparator(ResolverActivity.this, mIntent);
|
||||
Collections.sort(currentResolveList, rComparator);
|
||||
Collections.sort(currentResolveList,
|
||||
new ResolverComparator(ResolverActivity.this, getTargetIntent()));
|
||||
}
|
||||
// First put the initial items at the top.
|
||||
if (mInitialIntents != null) {
|
||||
@@ -1146,14 +1206,15 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic
|
||||
ri.nonLocalizedLabel = li.getNonLocalizedLabel();
|
||||
ri.icon = li.getIconResource();
|
||||
}
|
||||
addResolveInfo(new DisplayResolveInfo(ri,
|
||||
addResolveInfo(new DisplayResolveInfo(ii, ri,
|
||||
ri.loadLabel(getPackageManager()), null, ii));
|
||||
}
|
||||
}
|
||||
|
||||
// Check for applications with same name and use application name or
|
||||
// package name if necessary
|
||||
r0 = currentResolveList.get(0);
|
||||
rci0 = currentResolveList.get(0);
|
||||
r0 = rci0.getResolveInfoAt(0);
|
||||
int start = 0;
|
||||
CharSequence r0Label = r0.loadLabel(mPm);
|
||||
mHasExtendedInfo = false;
|
||||
@@ -1161,7 +1222,8 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic
|
||||
if (r0Label == null) {
|
||||
r0Label = r0.activityInfo.packageName;
|
||||
}
|
||||
ResolveInfo ri = currentResolveList.get(i);
|
||||
ResolvedComponentInfo rci = currentResolveList.get(i);
|
||||
ResolveInfo ri = rci.getResolveInfoAt(0);
|
||||
CharSequence riLabel = ri.loadLabel(mPm);
|
||||
if (riLabel == null) {
|
||||
riLabel = ri.activityInfo.packageName;
|
||||
@@ -1169,13 +1231,14 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic
|
||||
if (riLabel.equals(r0Label)) {
|
||||
continue;
|
||||
}
|
||||
processGroup(currentResolveList, start, (i-1), r0, r0Label);
|
||||
processGroup(currentResolveList, start, (i-1), rci0, r0Label);
|
||||
rci0 = rci;
|
||||
r0 = ri;
|
||||
r0Label = riLabel;
|
||||
start = i;
|
||||
}
|
||||
// Process last group
|
||||
processGroup(currentResolveList, start, (N-1), r0, r0Label);
|
||||
processGroup(currentResolveList, start, (N-1), rci0, r0Label);
|
||||
}
|
||||
|
||||
// Layout doesn't handle both profile button and last chosen
|
||||
@@ -1188,6 +1251,36 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic
|
||||
onListRebuilt();
|
||||
}
|
||||
|
||||
private void addResolveListDedupe(List<ResolvedComponentInfo> into, Intent intent,
|
||||
List<ResolveInfo> from) {
|
||||
final int fromCount = from.size();
|
||||
final int intoCount = into.size();
|
||||
for (int i = 0; i < fromCount; i++) {
|
||||
final ResolveInfo newInfo = from.get(i);
|
||||
boolean found = false;
|
||||
// Only loop to the end of into as it was before we started; no dupes in from.
|
||||
for (int j = 0; j < intoCount; j++) {
|
||||
final ResolvedComponentInfo rci = into.get(i);
|
||||
if (isSameResolvedComponent(newInfo, rci)) {
|
||||
found = true;
|
||||
rci.add(intent, newInfo);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
into.add(new ResolvedComponentInfo(new ComponentName(
|
||||
newInfo.activityInfo.packageName, newInfo.activityInfo.name),
|
||||
intent, newInfo));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isSameResolvedComponent(ResolveInfo a, ResolvedComponentInfo b) {
|
||||
final ActivityInfo ai = a.activityInfo;
|
||||
return ai.packageName.equals(b.name.getPackageName())
|
||||
&& ai.name.equals(b.name.getClassName());
|
||||
}
|
||||
|
||||
public void onListRebuilt() {
|
||||
// This space for rent
|
||||
}
|
||||
@@ -1196,18 +1289,18 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic
|
||||
return mFilterLastUsed;
|
||||
}
|
||||
|
||||
private void processGroup(List<ResolveInfo> rList, int start, int end, ResolveInfo ro,
|
||||
CharSequence roLabel) {
|
||||
private void processGroup(List<ResolvedComponentInfo> rList, int start, int end,
|
||||
ResolvedComponentInfo ro, CharSequence roLabel) {
|
||||
// Process labels from start to i
|
||||
int num = end - start+1;
|
||||
if (num == 1) {
|
||||
// No duplicate labels. Use label for entry at start
|
||||
addResolveInfo(new DisplayResolveInfo(ro, roLabel, null, null));
|
||||
updateLastChosenPosition(ro);
|
||||
addResolveInfoWithAlternates(ro, null, roLabel);
|
||||
} else {
|
||||
mHasExtendedInfo = true;
|
||||
boolean usePkg = false;
|
||||
CharSequence startApp = ro.activityInfo.applicationInfo.loadLabel(mPm);
|
||||
CharSequence startApp = ro.getResolveInfoAt(0).activityInfo.applicationInfo
|
||||
.loadLabel(mPm);
|
||||
if (startApp == null) {
|
||||
usePkg = true;
|
||||
}
|
||||
@@ -1217,7 +1310,7 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic
|
||||
new HashSet<CharSequence>();
|
||||
duplicates.add(startApp);
|
||||
for (int j = start+1; j <= end ; j++) {
|
||||
ResolveInfo jRi = rList.get(j);
|
||||
ResolveInfo jRi = rList.get(j).getResolveInfoAt(0);
|
||||
CharSequence jApp = jRi.activityInfo.applicationInfo.loadLabel(mPm);
|
||||
if ( (jApp == null) || (duplicates.contains(jApp))) {
|
||||
usePkg = true;
|
||||
@@ -1230,26 +1323,46 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic
|
||||
duplicates.clear();
|
||||
}
|
||||
for (int k = start; k <= end; k++) {
|
||||
ResolveInfo add = rList.get(k);
|
||||
final ResolvedComponentInfo rci = rList.get(k);
|
||||
final ResolveInfo add = rci.getResolveInfoAt(0);
|
||||
final CharSequence extraInfo;
|
||||
if (usePkg) {
|
||||
// Use application name for all entries from start to end-1
|
||||
addResolveInfo(new DisplayResolveInfo(add, roLabel,
|
||||
add.activityInfo.packageName, null));
|
||||
} else {
|
||||
// Use package name for all entries from start to end-1
|
||||
addResolveInfo(new DisplayResolveInfo(add, roLabel,
|
||||
add.activityInfo.applicationInfo.loadLabel(mPm), null));
|
||||
extraInfo = add.activityInfo.packageName;
|
||||
} else {
|
||||
// Use application name for all entries from start to end-1
|
||||
extraInfo = add.activityInfo.applicationInfo.loadLabel(mPm);
|
||||
}
|
||||
updateLastChosenPosition(add);
|
||||
addResolveInfoWithAlternates(rci, extraInfo, roLabel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void addResolveInfoWithAlternates(ResolvedComponentInfo rci,
|
||||
CharSequence extraInfo, CharSequence roLabel) {
|
||||
final int count = rci.getCount();
|
||||
final Intent intent = rci.getIntentAt(0);
|
||||
final ResolveInfo add = rci.getResolveInfoAt(0);
|
||||
final Intent replaceIntent = getReplacementIntent(add.activityInfo, intent);
|
||||
final DisplayResolveInfo dri = new DisplayResolveInfo(intent, add, roLabel,
|
||||
extraInfo, replaceIntent);
|
||||
addResolveInfo(dri);
|
||||
if (replaceIntent == intent) {
|
||||
// Only add alternates if we didn't get a specific replacement from
|
||||
// the caller. If we have one it trumps potential alternates.
|
||||
for (int i = 1, N = count; i < N; i++) {
|
||||
final Intent altIntent = rci.getIntentAt(i);
|
||||
dri.addAlternateSourceIntent(altIntent);
|
||||
}
|
||||
}
|
||||
updateLastChosenPosition(add);
|
||||
}
|
||||
|
||||
private void updateLastChosenPosition(ResolveInfo info) {
|
||||
if (mLastChosen != null
|
||||
&& mLastChosen.activityInfo.packageName.equals(info.activityInfo.packageName)
|
||||
&& mLastChosen.activityInfo.name.equals(info.activityInfo.name)) {
|
||||
mLastChosenPosition = mList.size() - 1;
|
||||
mLastChosenPosition = mDisplayList.size() - 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1259,20 +1372,21 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic
|
||||
// The first one we see gets special treatment.
|
||||
mOtherProfile = dri;
|
||||
} else {
|
||||
mList.add(dri);
|
||||
mDisplayList.add(dri);
|
||||
}
|
||||
}
|
||||
|
||||
public ResolveInfo resolveInfoForPosition(int position, boolean filtered) {
|
||||
return (filtered ? getItem(position) : mList.get(position)).getResolveInfo();
|
||||
return (filtered ? getItem(position) : mDisplayList.get(position))
|
||||
.getResolveInfo();
|
||||
}
|
||||
|
||||
public TargetInfo targetInfoForPosition(int position, boolean filtered) {
|
||||
return filtered ? getItem(position) : mList.get(position);
|
||||
return filtered ? getItem(position) : mDisplayList.get(position);
|
||||
}
|
||||
|
||||
public int getCount() {
|
||||
int result = mList.size();
|
||||
int result = mDisplayList.size();
|
||||
if (mFilterLastUsed && mLastChosenPosition >= 0) {
|
||||
result--;
|
||||
}
|
||||
@@ -1283,7 +1397,7 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic
|
||||
if (mFilterLastUsed && mLastChosenPosition >= 0 && position >= mLastChosenPosition) {
|
||||
position++;
|
||||
}
|
||||
return mList.get(position);
|
||||
return mDisplayList.get(position);
|
||||
}
|
||||
|
||||
public long getItemId(int position) {
|
||||
@@ -1295,8 +1409,8 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic
|
||||
}
|
||||
|
||||
public boolean hasResolvedTarget(ResolveInfo info) {
|
||||
for (int i = 0, N = mList.size(); i < N; i++) {
|
||||
if (info.equals(mList.get(i).getResolveInfo())) {
|
||||
for (int i = 0, N = mDisplayList.size(); i < N; i++) {
|
||||
if (info.equals(mDisplayList.get(i).getResolveInfo())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -1304,11 +1418,12 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic
|
||||
}
|
||||
|
||||
protected int getDisplayResolveInfoCount() {
|
||||
return mList.size();
|
||||
return mDisplayList.size();
|
||||
}
|
||||
|
||||
protected DisplayResolveInfo getDisplayResolveInfo(int index) {
|
||||
return mList.get(index);
|
||||
// Used to query services. We only query services for primary targets, not alternates.
|
||||
return mDisplayList.get(index);
|
||||
}
|
||||
|
||||
public final View getView(int position, View convertView, ViewGroup parent) {
|
||||
@@ -1349,6 +1464,52 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic
|
||||
}
|
||||
}
|
||||
|
||||
static final class ResolvedComponentInfo {
|
||||
public final ComponentName name;
|
||||
private final List<Intent> mIntents = new ArrayList<>();
|
||||
private final List<ResolveInfo> mResolveInfos = new ArrayList<>();
|
||||
|
||||
public ResolvedComponentInfo(ComponentName name, Intent intent, ResolveInfo info) {
|
||||
this.name = name;
|
||||
add(intent, info);
|
||||
}
|
||||
|
||||
public void add(Intent intent, ResolveInfo info) {
|
||||
mIntents.add(intent);
|
||||
mResolveInfos.add(info);
|
||||
}
|
||||
|
||||
public int getCount() {
|
||||
return mIntents.size();
|
||||
}
|
||||
|
||||
public Intent getIntentAt(int index) {
|
||||
return index >= 0 ? mIntents.get(index) : null;
|
||||
}
|
||||
|
||||
public ResolveInfo getResolveInfoAt(int index) {
|
||||
return index >= 0 ? mResolveInfos.get(index) : null;
|
||||
}
|
||||
|
||||
public int findIntent(Intent intent) {
|
||||
for (int i = 0, N = mIntents.size(); i < N; i++) {
|
||||
if (intent.equals(mIntents.get(i))) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public int findResolveInfo(ResolveInfo info) {
|
||||
for (int i = 0, N = mResolveInfos.size(); i < N; i++) {
|
||||
if (info.equals(mResolveInfos.get(i))) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static class ViewHolder {
|
||||
public TextView text;
|
||||
public TextView text2;
|
||||
@@ -1435,7 +1596,7 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic
|
||||
&& match <= IntentFilter.MATCH_CATEGORY_PATH;
|
||||
}
|
||||
|
||||
class ResolverComparator implements Comparator<ResolveInfo> {
|
||||
class ResolverComparator implements Comparator<ResolvedComponentInfo> {
|
||||
private final Collator mCollator;
|
||||
private final boolean mHttp;
|
||||
|
||||
@@ -1446,7 +1607,10 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compare(ResolveInfo lhs, ResolveInfo rhs) {
|
||||
public int compare(ResolvedComponentInfo lhsp, ResolvedComponentInfo rhsp) {
|
||||
final ResolveInfo lhs = lhsp.getResolveInfoAt(0);
|
||||
final ResolveInfo rhs = rhsp.getResolveInfoAt(0);
|
||||
|
||||
// We want to put the one targeted to another user at the end of the dialog.
|
||||
if (lhs.targetUserId != UserHandle.USER_CURRENT) {
|
||||
return 1;
|
||||
@@ -1487,7 +1651,6 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic
|
||||
if (stats != null) {
|
||||
return stats.getTotalTimeInForeground();
|
||||
}
|
||||
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -93,7 +93,7 @@ public class UsbResolverActivity extends ResolverActivity {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onTargetSelected(TargetInfo target, boolean alwaysCheck) {
|
||||
protected boolean onTargetSelected(TargetInfo target, boolean alwaysCheck) {
|
||||
final ResolveInfo ri = target.getResolveInfo();
|
||||
try {
|
||||
IBinder b = ServiceManager.getService(USB_SERVICE);
|
||||
@@ -129,5 +129,6 @@ public class UsbResolverActivity extends ResolverActivity {
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "onIntentSelected failed", e);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user