summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--api/current.txt7
-rw-r--r--api/system-current.txt7
-rw-r--r--core/java/android/service/chooser/ChooserTarget.java128
-rw-r--r--core/java/android/service/chooser/ChooserTargetService.java5
-rw-r--r--core/java/android/service/chooser/IChooserTargetResult.aidl2
-rw-r--r--core/java/com/android/internal/app/ChooserActivity.java57
6 files changed, 86 insertions, 120 deletions
diff --git a/api/current.txt b/api/current.txt
index ea33eaf40fb9..f4f91a72f6fe 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -28534,14 +28534,13 @@ package android.service.carrier {
package android.service.chooser {
public final class ChooserTarget implements android.os.Parcelable {
- ctor public ChooserTarget(java.lang.CharSequence, android.graphics.drawable.Icon, float, android.app.PendingIntent);
- ctor public ChooserTarget(java.lang.CharSequence, android.graphics.drawable.Icon, float, android.content.IntentSender);
+ ctor public ChooserTarget(java.lang.CharSequence, android.graphics.drawable.Icon, float, android.content.ComponentName, android.os.Bundle);
method public int describeContents();
+ method public android.content.ComponentName getComponentName();
method public android.graphics.drawable.Icon getIcon();
- method public android.content.IntentSender getIntentSender();
+ method public android.os.Bundle getIntentExtras();
method public float getScore();
method public java.lang.CharSequence getTitle();
- method public boolean sendIntent(android.content.Context, android.content.Intent);
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.service.chooser.ChooserTarget> CREATOR;
}
diff --git a/api/system-current.txt b/api/system-current.txt
index d1e19fbe6b65..4da118a5c9ca 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -30594,14 +30594,13 @@ package android.service.carrier {
package android.service.chooser {
public final class ChooserTarget implements android.os.Parcelable {
- ctor public ChooserTarget(java.lang.CharSequence, android.graphics.drawable.Icon, float, android.app.PendingIntent);
- ctor public ChooserTarget(java.lang.CharSequence, android.graphics.drawable.Icon, float, android.content.IntentSender);
+ ctor public ChooserTarget(java.lang.CharSequence, android.graphics.drawable.Icon, float, android.content.ComponentName, android.os.Bundle);
method public int describeContents();
+ method public android.content.ComponentName getComponentName();
method public android.graphics.drawable.Icon getIcon();
- method public android.content.IntentSender getIntentSender();
+ method public android.os.Bundle getIntentExtras();
method public float getScore();
method public java.lang.CharSequence getTitle();
- method public boolean sendIntent(android.content.Context, android.content.Intent);
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.service.chooser.ChooserTarget> CREATOR;
}
diff --git a/core/java/android/service/chooser/ChooserTarget.java b/core/java/android/service/chooser/ChooserTarget.java
index 50c435a90d1c..c2f70cc02f05 100644
--- a/core/java/android/service/chooser/ChooserTarget.java
+++ b/core/java/android/service/chooser/ChooserTarget.java
@@ -17,20 +17,14 @@
package android.service.chooser;
-import android.app.Activity;
-import android.app.PendingIntent;
+import android.annotation.Nullable;
import android.content.ComponentName;
-import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
-import android.content.IntentSender;
-import android.graphics.Bitmap;
import android.graphics.drawable.Icon;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
-import android.os.UserHandle;
-import android.util.Log;
/**
* A ChooserTarget represents a deep-link into an application as returned by a
@@ -62,52 +56,21 @@ public final class ChooserTarget implements Parcelable {
private Icon mIcon;
/**
- * The IntentSender that will be used to deliver the intent to the target.
- * It will be {@link android.content.Intent#fillIn(android.content.Intent, int)} filled in}
- * by the real intent sent by the application.
+ * The ComponentName of the Activity to be invoked. Must be part of the target creator's
+ * own package or an Activity exported by its package.
*/
- private IntentSender mIntentSender;
+ private ComponentName mComponentName;
/**
- * The score given to this item. It can be normalized.
+ * A Bundle to merge with the extras of the intent sent to this target.
+ * Any extras here will override the extras from the original intent.
*/
- private float mScore;
+ private Bundle mIntentExtras;
/**
- * Construct a deep link target for presentation by a chooser UI.
- *
- * <p>A target is composed of a title and an icon for presentation to the user.
- * The UI presenting this target may truncate the title if it is too long to be presented
- * in the available space, as well as crop, resize or overlay the supplied icon.</p>
- *
- * <p>The creator of a target may supply a ranking score. This score is assumed to be relative
- * to the other targets supplied by the same
- * {@link ChooserTargetService#onGetChooserTargets(ComponentName, IntentFilter) query}.
- * Scores should be in the range from 0.0f (unlikely match) to 1.0f (very relevant match).
- * Scores for a set of targets do not need to sum to 1.</p>
- *
- * <p>Before being sent, the PendingIntent supplied will be
- * {@link Intent#fillIn(Intent, int) filled in} by the Intent originally supplied
- * to the chooser. When constructing a PendingIntent for use in a ChooserTarget, make sure
- * that you permit the relevant fields to be filled in using the appropriate flags such as
- * {@link Intent#FILL_IN_ACTION}, {@link Intent#FILL_IN_CATEGORIES},
- * {@link Intent#FILL_IN_DATA} and {@link Intent#FILL_IN_CLIP_DATA}. Note that
- * {@link Intent#FILL_IN_CLIP_DATA} is required to appropriately receive URI permission grants
- * for {@link Intent#ACTION_SEND} intents.</p>
- *
- * <p>Take care not to place custom {@link android.os.Parcelable} types into
- * the PendingIntent as extras, as the system will not be able to unparcel it to merge
- * additional extras.</p>
- *
- * @param title title of this target that will be shown to a user
- * @param icon icon to represent this target
- * @param score ranking score for this target between 0.0f and 1.0f, inclusive
- * @param pendingIntent PendingIntent to fill in and send if the user chooses this target
+ * The score given to this item. It can be normalized.
*/
- public ChooserTarget(CharSequence title, Icon icon, float score,
- PendingIntent pendingIntent) {
- this(title, icon, score, pendingIntent.getIntentSender());
- }
+ private float mScore;
/**
* Construct a deep link target for presentation by a chooser UI.
@@ -122,25 +85,23 @@ public final class ChooserTarget implements Parcelable {
* Scores should be in the range from 0.0f (unlikely match) to 1.0f (very relevant match).
* Scores for a set of targets do not need to sum to 1.</p>
*
- * <p>Before being sent, the IntentSender supplied will be
- * {@link Intent#fillIn(Intent, int) filled in} by the Intent originally supplied
- * to the chooser. When constructing an IntentSender for use in a ChooserTarget, make sure
- * that you permit the relevant fields to be filled in using the appropriate flags such as
- * {@link Intent#FILL_IN_ACTION}, {@link Intent#FILL_IN_CATEGORIES},
- * {@link Intent#FILL_IN_DATA} and {@link Intent#FILL_IN_CLIP_DATA}. Note that
- * {@link Intent#FILL_IN_CLIP_DATA} is required to appropriately receive URI permission grants
- * for {@link Intent#ACTION_SEND} intents.</p>
+ * <p>The ComponentName must be the name of an Activity component in the creator's own
+ * package, or an exported component from any other package. You may provide an optional
+ * Bundle of extras that will be merged into the final intent before it is sent to the
+ * target Activity; use this to add any additional data about the deep link that the target
+ * activity will read. e.g. conversation IDs, email addresses, etc.</p>
*
* <p>Take care not to place custom {@link android.os.Parcelable} types into
- * the IntentSender as extras, as the system will not be able to unparcel it to merge
- * additional extras.</p>
+ * the extras bundle, as the system will not be able to unparcel them to merge them.</p>
*
* @param title title of this target that will be shown to a user
* @param icon icon to represent this target
* @param score ranking score for this target between 0.0f and 1.0f, inclusive
- * @param intentSender IntentSender to fill in and send if the user chooses this target
+ * @param componentName Name of the component to be launched if this target is chosen
+ * @param intentExtras Bundle of extras to merge with the extras of the launched intent
*/
- public ChooserTarget(CharSequence title, Icon icon, float score, IntentSender intentSender) {
+ public ChooserTarget(CharSequence title, Icon icon, float score,
+ ComponentName componentName, @Nullable Bundle intentExtras) {
mTitle = title;
mIcon = icon;
if (score > 1.f || score < 0.f) {
@@ -148,7 +109,8 @@ public final class ChooserTarget implements Parcelable {
+ "must be between 0.0f and 1.0f");
}
mScore = score;
- mIntentSender = intentSender;
+ mComponentName = componentName;
+ mIntentExtras = intentExtras;
}
ChooserTarget(Parcel in) {
@@ -159,7 +121,8 @@ public final class ChooserTarget implements Parcelable {
mIcon = null;
}
mScore = in.readFloat();
- mIntentSender = IntentSender.readIntentSenderOrNullFromParcel(in);
+ mComponentName = ComponentName.readFromParcel(in);
+ mIntentExtras = in.readBundle();
}
/**
@@ -194,49 +157,29 @@ public final class ChooserTarget implements Parcelable {
}
/**
- * Returns the raw IntentSender supplied by the ChooserTarget's creator.
- * This may be null if the creator specified a regular Intent instead.
- *
- * <p>To fill in and send the intent, see {@link #sendIntent(Context, Intent)}.</p>
+ * Returns the ComponentName of the Activity that should be launched for this ChooserTarget.
*
- * @return the IntentSender supplied by the ChooserTarget's creator
+ * @return the name of the target Activity to launch
*/
- public IntentSender getIntentSender() {
- return mIntentSender;
+ public ComponentName getComponentName() {
+ return mComponentName;
}
/**
- * Fill in the IntentSender supplied by the ChooserTarget's creator and send it.
+ * Returns the Bundle of extras to be added to an intent launched to this target.
*
- * @param context the sending Context; generally the Activity presenting the chooser UI
- * @param fillInIntent the Intent provided to the Chooser to be sent to a selected target
- * @return true if sending the Intent was successful
+ * @return the extras to merge with the extras of the intent being launched
*/
- public boolean sendIntent(Context context, Intent fillInIntent) {
- if (fillInIntent != null) {
- fillInIntent.migrateExtraStreamToClipData();
- fillInIntent.prepareToLeaveProcess();
- }
- if (mIntentSender != null) {
- try {
- mIntentSender.sendIntent(context, 0, fillInIntent, null, null);
- return true;
- } catch (IntentSender.SendIntentException e) {
- Log.e(TAG, "sendIntent " + this + " failed", e);
- return false;
- }
- } else {
- Log.e(TAG, "sendIntent " + this + " failed - no IntentSender to send");
- return false;
- }
+ public Bundle getIntentExtras() {
+ return mIntentExtras;
}
@Override
public String toString() {
return "ChooserTarget{"
- + (mIntentSender != null ? mIntentSender.getCreatorPackage() : null)
- + ", "
- + "'" + mTitle
+ + mComponentName
+ + ", " + mIntentExtras
+ + ", '" + mTitle
+ "', " + mScore + "}";
}
@@ -255,7 +198,8 @@ public final class ChooserTarget implements Parcelable {
dest.writeInt(0);
}
dest.writeFloat(mScore);
- IntentSender.writeIntentSenderOrNullToParcel(mIntentSender, dest);
+ ComponentName.writeToParcel(mComponentName, dest);
+ dest.writeBundle(mIntentExtras);
}
public static final Creator<ChooserTarget> CREATOR
diff --git a/core/java/android/service/chooser/ChooserTargetService.java b/core/java/android/service/chooser/ChooserTargetService.java
index a3bfeced361c..e0541855bbab 100644
--- a/core/java/android/service/chooser/ChooserTargetService.java
+++ b/core/java/android/service/chooser/ChooserTargetService.java
@@ -105,9 +105,8 @@ public abstract class ChooserTargetService extends Service {
* can handle an intent.
*
* <p>The returned list should be sorted such that the most relevant targets appear first.
- * Any PendingIntents used to construct the resulting ChooserTargets should always be prepared
- * to have the relevant data fields filled in by the sender. See
- * {@link ChooserTarget#ChooserTarget(CharSequence, android.graphics.drawable.Icon, float, android.app.PendingIntent) ChooserTarget}.</p>
+ * The score for each ChooserTarget will be combined with the system's score for the original
+ * target Activity to sort and filter targets presented to the user.</p>
*
* <p><em>Important:</em> Calls to this method from other applications will occur on
* a binder thread, not on your app's main thread. Make sure that access to relevant data
diff --git a/core/java/android/service/chooser/IChooserTargetResult.aidl b/core/java/android/service/chooser/IChooserTargetResult.aidl
index dbd7cbd23af2..6c648a24ddfc 100644
--- a/core/java/android/service/chooser/IChooserTargetResult.aidl
+++ b/core/java/android/service/chooser/IChooserTargetResult.aidl
@@ -21,7 +21,7 @@ import android.service.chooser.ChooserTarget;
/**
* @hide
*/
-interface IChooserTargetResult
+oneway interface IChooserTargetResult
{
void sendResult(in List<ChooserTarget> targets);
}
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index c4f57c7c38bf..6af2e8bf5765 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -471,6 +471,36 @@ public class ChooserActivity extends ResolverActivity {
return false;
}
+ void filterServiceTargets(String packageName, List<ChooserTarget> targets) {
+ if (targets == null) {
+ return;
+ }
+
+ final PackageManager pm = getPackageManager();
+ for (int i = targets.size() - 1; i >= 0; i--) {
+ final ChooserTarget target = targets.get(i);
+ final ComponentName targetName = target.getComponentName();
+ if (packageName != null && packageName.equals(targetName.getPackageName())) {
+ // Anything from the original target's package is fine.
+ continue;
+ }
+
+ boolean remove;
+ try {
+ final ActivityInfo ai = pm.getActivityInfo(targetName, 0);
+ remove = !ai.exported || ai.permission != null;
+ } catch (NameNotFoundException e) {
+ Log.e(TAG, "Target " + target + " returned by " + packageName
+ + " component not found");
+ remove = true;
+ }
+
+ if (remove) {
+ targets.remove(i);
+ }
+ }
+ }
+
@Override
ResolveListAdapter createAdapter(Context context, List<Intent> payloadIntents,
Intent[] initialIntents, List<ResolveInfo> rList, int launchedFromUid,
@@ -554,11 +584,11 @@ public class ChooserActivity extends ResolverActivity {
return null;
}
- private Intent getFillInIntent() {
+ private Intent getBaseIntentToSend() {
Intent result = mSourceInfo != null
? mSourceInfo.getResolvedIntent() : getTargetIntent();
if (result == null) {
- Log.e(TAG, "ChooserTargetInfo#getFillInIntent: no fillIn intent available");
+ Log.e(TAG, "ChooserTargetInfo: no base intent available to send");
} else {
result = new Intent(result);
if (mFillInIntent != null) {
@@ -571,31 +601,24 @@ public class ChooserActivity extends ResolverActivity {
@Override
public boolean start(Activity activity, Bundle options) {
- final Intent intent = getFillInIntent();
- if (intent == null) {
- return false;
- }
- return mChooserTarget.sendIntent(activity, intent);
+ throw new RuntimeException("ChooserTargets should be started as caller.");
}
@Override
public boolean startAsCaller(Activity activity, Bundle options, int userId) {
- final Intent intent = getFillInIntent();
+ final Intent intent = getBaseIntentToSend();
if (intent == null) {
return false;
}
- // ChooserTargets will launch with their IntentSender's identity
- return mChooserTarget.sendIntent(activity, intent);
+ intent.setComponent(mChooserTarget.getComponentName());
+ intent.putExtras(mChooserTarget.getIntentExtras());
+ activity.startActivityAsCaller(intent, options, true, userId);
+ return true;
}
@Override
public boolean startAsUser(Activity activity, Bundle options, UserHandle user) {
- final Intent intent = getFillInIntent();
- if (intent == null) {
- return false;
- }
- // ChooserTargets will launch with their IntentSender's identity
- return mChooserTarget.sendIntent(activity, intent);
+ throw new RuntimeException("ChooserTargets should be started as caller.");
}
@Override
@@ -998,6 +1021,8 @@ public class ChooserActivity extends ResolverActivity {
private final IChooserTargetResult mChooserTargetResult = new IChooserTargetResult.Stub() {
@Override
public void sendResult(List<ChooserTarget> targets) throws RemoteException {
+ filterServiceTargets(mOriginalTarget.getResolveInfo().activityInfo.packageName,
+ targets);
final Message msg = Message.obtain();
msg.what = CHOOSER_TARGET_SERVICE_RESULT;
msg.obj = new ServiceResultInfo(mOriginalTarget, targets,