summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAdam Powell <adamp@google.com>2015-04-14 00:01:45 +0000
committerAndroid (Google) Code Review <android-gerrit@google.com>2015-04-14 00:01:47 +0000
commitcc8b2afbaaabb3d120c1edc5ead9a67c5361762a (patch)
treedd1b23f09f3045e3fb10654c91714a182df74161
parent7d8f2c25df8d017c5fb57cfe844500e3aeb8f321 (diff)
parent2442841819f9554f9b5c8b9c147a51b04e50de4d (diff)
downloadframeworks_base-cc8b2afbaaabb3d120c1edc5ead9a67c5361762a.zip
frameworks_base-cc8b2afbaaabb3d120c1edc5ead9a67c5361762a.tar.gz
frameworks_base-cc8b2afbaaabb3d120c1edc5ead9a67c5361762a.tar.bz2
Merge "Implement ChooserTargetService querying for ChooserActivity"
-rw-r--r--api/current.txt5
-rw-r--r--api/system-current.txt5
-rw-r--r--core/java/android/content/Intent.java8
-rw-r--r--core/java/android/service/chooser/ChooserTarget.java139
-rw-r--r--core/java/android/service/chooser/ChooserTargetService.java25
-rw-r--r--core/java/com/android/internal/app/ChooserActivity.java392
-rw-r--r--core/java/com/android/internal/app/ResolverActivity.java469
-rw-r--r--core/res/res/layout/chooser_grid.xml107
-rw-r--r--core/res/res/layout/resolve_grid_item.xml60
-rw-r--r--core/res/res/values-sw360dp/dimens.xml21
-rw-r--r--core/res/res/values/dimens.xml1
-rwxr-xr-xcore/res/res/values/symbols.xml3
-rw-r--r--packages/SystemUI/src/com/android/systemui/usb/UsbResolverActivity.java5
13 files changed, 1113 insertions, 127 deletions
diff --git a/api/current.txt b/api/current.txt
index a96c3a2..87cd2d6 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -8158,6 +8158,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_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";
field public static final java.lang.String EXTRA_DATA_REMOVED = "android.intent.extra.DATA_REMOVED";
@@ -28384,8 +28385,10 @@ package android.service.chooser {
public final class ChooserTarget implements android.os.Parcelable {
ctor public ChooserTarget(java.lang.CharSequence, android.graphics.Bitmap, float, android.app.PendingIntent);
ctor public ChooserTarget(java.lang.CharSequence, android.graphics.Bitmap, float, android.content.IntentSender);
+ ctor public ChooserTarget(java.lang.CharSequence, android.graphics.Bitmap, float, android.content.Intent);
method public int describeContents();
method public android.graphics.Bitmap getIcon();
+ method public android.content.Intent getIntent();
method public android.content.IntentSender getIntentSender();
method public float getScore();
method public java.lang.CharSequence getTitle();
@@ -28398,6 +28401,8 @@ package android.service.chooser {
ctor public ChooserTargetService();
method public android.os.IBinder onBind(android.content.Intent);
method public abstract java.util.List<android.service.chooser.ChooserTarget> onGetChooserTargets(android.content.ComponentName, android.content.IntentFilter);
+ field public static final java.lang.String BIND_PERMISSION = "android.permission.BIND_CHOOSER_TARGET_SERVICE";
+ field public static final java.lang.String META_DATA_NAME = "android.service.chooser.chooser_target_service";
field public static final java.lang.String SERVICE_INTERFACE = "android.service.chooser.ChooserTargetService";
}
diff --git a/api/system-current.txt b/api/system-current.txt
index 9021029..9e635bf 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -8384,6 +8384,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_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";
field public static final java.lang.String EXTRA_DATA_REMOVED = "android.intent.extra.DATA_REMOVED";
@@ -30383,8 +30384,10 @@ package android.service.chooser {
public final class ChooserTarget implements android.os.Parcelable {
ctor public ChooserTarget(java.lang.CharSequence, android.graphics.Bitmap, float, android.app.PendingIntent);
ctor public ChooserTarget(java.lang.CharSequence, android.graphics.Bitmap, float, android.content.IntentSender);
+ ctor public ChooserTarget(java.lang.CharSequence, android.graphics.Bitmap, float, android.content.Intent);
method public int describeContents();
method public android.graphics.Bitmap getIcon();
+ method public android.content.Intent getIntent();
method public android.content.IntentSender getIntentSender();
method public float getScore();
method public java.lang.CharSequence getTitle();
@@ -30397,6 +30400,8 @@ package android.service.chooser {
ctor public ChooserTargetService();
method public android.os.IBinder onBind(android.content.Intent);
method public abstract java.util.List<android.service.chooser.ChooserTarget> onGetChooserTargets(android.content.ComponentName, android.content.IntentFilter);
+ field public static final java.lang.String BIND_PERMISSION = "android.permission.BIND_CHOOSER_TARGET_SERVICE";
+ field public static final java.lang.String META_DATA_NAME = "android.service.chooser.chooser_target_service";
field public static final java.lang.String SERVICE_INTERFACE = "android.service.chooser.ChooserTargetService";
}
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index eea47b7..54fe786 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -3311,6 +3311,14 @@ public class Intent implements Parcelable, Cloneable {
public static final String EXTRA_INITIAL_INTENTS = "android.intent.extra.INITIAL_INTENTS";
/**
+ * A Parcelable[] of {@link android.service.chooser.ChooserTarget ChooserTarget} objects
+ * as set with {@link #putExtra(String, Parcelable[])} representing additional app-specific
+ * targets to place at the front of the list of choices. Shown to the user with
+ * {@link #ACTION_CHOOSER}.
+ */
+ public static final String EXTRA_CHOOSER_TARGETS = "android.intent.extra.CHOOSER_TARGETS";
+
+ /**
* A Bundle forming a mapping of potential target package names to different extras Bundles
* to add to the default intent extras in {@link #EXTRA_INTENT} when used with
* {@link #ACTION_CHOOSER}. Each key should be a package name. The package need not
diff --git a/core/java/android/service/chooser/ChooserTarget.java b/core/java/android/service/chooser/ChooserTarget.java
index 7fd1d10..d21cc3c 100644
--- a/core/java/android/service/chooser/ChooserTarget.java
+++ b/core/java/android/service/chooser/ChooserTarget.java
@@ -17,6 +17,7 @@
package android.service.chooser;
+import android.app.Activity;
import android.app.PendingIntent;
import android.content.ComponentName;
import android.content.Context;
@@ -24,8 +25,10 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.content.IntentSender;
import android.graphics.Bitmap;
+import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
+import android.os.UserHandle;
import android.util.Log;
/**
@@ -55,6 +58,12 @@ public final class ChooserTarget implements Parcelable {
private IntentSender mIntentSender;
/**
+ * A raw intent provided in lieu of an IntentSender. Will be filled in and sent
+ * by {@link #sendIntent(Context, Intent)}.
+ */
+ private Intent mIntent;
+
+ /**
* The score given to this item. It can be normalized.
*/
private float mScore;
@@ -135,6 +144,17 @@ public final class ChooserTarget implements Parcelable {
mIntentSender = intentSender;
}
+ public ChooserTarget(CharSequence title, Bitmap icon, float score, Intent intent) {
+ mTitle = title;
+ mIcon = icon;
+ if (score > 1.f || score < 0.f) {
+ throw new IllegalArgumentException("Score " + score + " out of range; "
+ + "must be between 0.0f and 1.0f");
+ }
+ mScore = score;
+ mIntent = intent;
+ }
+
ChooserTarget(Parcel in) {
mTitle = in.readCharSequence();
if (in.readInt() != 0) {
@@ -144,6 +164,9 @@ public final class ChooserTarget implements Parcelable {
}
mScore = in.readFloat();
mIntentSender = IntentSender.readIntentSenderOrNullFromParcel(in);
+ if (in.readInt() != 0) {
+ mIntent = Intent.CREATOR.createFromParcel(in);
+ }
}
/**
@@ -179,6 +202,7 @@ 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>
*
@@ -189,6 +213,18 @@ public final class ChooserTarget implements Parcelable {
}
/**
+ * Returns the Intent supplied by the ChooserTarget's creator.
+ * This may be null if the creator specified an IntentSender or PendingIntent instead.
+ *
+ * <p>To fill in and send the intent, see {@link #sendIntent(Context, Intent)}.</p>
+ *
+ * @return the Intent supplied by the ChooserTarget's creator
+ */
+ public Intent getIntent() {
+ return mIntent;
+ }
+
+ /**
* Fill in the IntentSender supplied by the ChooserTarget's creator and send it.
*
* @param context the sending Context; generally the Activity presenting the chooser UI
@@ -200,18 +236,109 @@ public final class ChooserTarget implements Parcelable {
fillInIntent.migrateExtraStreamToClipData();
fillInIntent.prepareToLeaveProcess();
}
- try {
- mIntentSender.sendIntent(context, 0, fillInIntent, null, null);
- return true;
- } catch (IntentSender.SendIntentException e) {
- Log.e(TAG, "sendIntent " + this + " failed", e);
+ 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 if (mIntent != null) {
+ try {
+ final Intent toSend = new Intent(mIntent);
+ toSend.fillIn(fillInIntent, 0);
+ context.startActivity(toSend);
+ return true;
+ } catch (Exception e) {
+ Log.e(TAG, "sendIntent " + this + " failed", e);
+ return false;
+ }
+ } else {
+ Log.e(TAG, "sendIntent " + this + " failed - no IntentSender or Intent to send");
+ return false;
+ }
+ }
+
+ /**
+ * Same as {@link #sendIntent(Context, Intent)}, but offers a userId field to use
+ * for launching the {@link #getIntent() intent} using
+ * {@link Activity#startActivityAsCaller(Intent, Bundle, int)} if the
+ * {@link #getIntentSender() IntentSender} is not present. If the IntentSender is present,
+ * it will be invoked as usual with its own calling identity.
+ *
+ * @hide internal use only.
+ */
+ public boolean sendIntentAsCaller(Activity context, Intent fillInIntent, int userId) {
+ 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 if (mIntent != null) {
+ try {
+ final Intent toSend = new Intent(mIntent);
+ toSend.fillIn(fillInIntent, 0);
+ context.startActivityAsCaller(toSend, null, userId);
+ return true;
+ } catch (Exception e) {
+ Log.e(TAG, "sendIntent " + this + " failed", e);
+ return false;
+ }
+ } else {
+ Log.e(TAG, "sendIntent " + this + " failed - no IntentSender or Intent to send");
+ return false;
+ }
+ }
+
+ /**
+ * The UserHandle is only used if we're launching a raw intent. The IntentSender will be
+ * launched with its associated identity.
+ *
+ * @hide Internal use only
+ */
+ public boolean sendIntentAsUser(Activity context, Intent fillInIntent, UserHandle user) {
+ 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 if (mIntent != null) {
+ try {
+ final Intent toSend = new Intent(mIntent);
+ toSend.fillIn(fillInIntent, 0);
+ context.startActivityAsUser(toSend, user);
+ return true;
+ } catch (Exception e) {
+ Log.e(TAG, "sendIntent " + this + " failed", e);
+ return false;
+ }
+ } else {
+ Log.e(TAG, "sendIntent " + this + " failed - no IntentSender or Intent to send");
return false;
}
}
@Override
public String toString() {
- return "ChooserTarget{" + mIntentSender.getCreatorPackage() + "'" + mTitle
+ return "ChooserTarget{"
+ + (mIntentSender != null ? mIntentSender.getCreatorPackage() : mIntent)
+ + ", "
+ + "'" + mTitle
+ "', " + mScore + "}";
}
diff --git a/core/java/android/service/chooser/ChooserTargetService.java b/core/java/android/service/chooser/ChooserTargetService.java
index 9188806..699bd0a 100644
--- a/core/java/android/service/chooser/ChooserTargetService.java
+++ b/core/java/android/service/chooser/ChooserTargetService.java
@@ -24,6 +24,7 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.os.IBinder;
import android.os.RemoteException;
+import android.util.Log;
import java.util.List;
@@ -77,9 +78,26 @@ public abstract class ChooserTargetService extends Service {
private final String TAG = ChooserTargetService.class.getSimpleName()
+ '[' + getClass().getSimpleName() + ']';
+ private static final boolean DEBUG = false;
+
+ /**
+ * The Intent action that a ChooserTargetService must respond to
+ */
@SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION)
public static final String SERVICE_INTERFACE = "android.service.chooser.ChooserTargetService";
+ /**
+ * The name of the <code>meta-data</code> element that must be present on an
+ * <code>activity</code> element in a manifest to link it to a ChooserTargetService
+ */
+ public static final String META_DATA_NAME = "android.service.chooser.chooser_target_service";
+
+ /**
+ * The permission that a ChooserTargetService must require in order to bind to it.
+ * If this permission is not enforced the system will skip that ChooserTargetService.
+ */
+ public static final String BIND_PERMISSION = "android.permission.BIND_CHOOSER_TARGET_SERVICE";
+
private IChooserTargetServiceWrapper mWrapper = null;
/**
@@ -105,7 +123,9 @@ public abstract class ChooserTargetService extends Service {
@Override
public IBinder onBind(Intent intent) {
+ if (DEBUG) Log.d(TAG, "onBind " + intent);
if (!SERVICE_INTERFACE.equals(intent.getAction())) {
+ if (DEBUG) Log.d(TAG, "bad intent action " + intent.getAction() + "; returning null");
return null;
}
@@ -121,9 +141,14 @@ public abstract class ChooserTargetService extends Service {
IntentFilter matchedFilter, IChooserTargetResult result) throws RemoteException {
List<ChooserTarget> targets = null;
try {
+ if (DEBUG) {
+ Log.d(TAG, "getChooserTargets calling onGetChooserTargets; "
+ + targetComponentName + " filter: " + matchedFilter);
+ }
targets = onGetChooserTargets(targetComponentName, matchedFilter);
} finally {
result.sendResult(targets);
+ if (DEBUG) Log.d(TAG, "Sent results");
}
}
}
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index 64bd6b6..8403e77 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -18,20 +18,87 @@ package com.android.internal.app;
import android.app.Activity;
import android.content.ComponentName;
+import android.content.Context;
import android.content.Intent;
import android.content.IntentSender;
+import android.content.ServiceConnection;
import android.content.pm.ActivityInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.ResolveInfo;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Message;
import android.os.Parcelable;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.service.chooser.ChooserTarget;
+import android.service.chooser.ChooserTargetService;
+import android.service.chooser.IChooserTargetResult;
+import android.service.chooser.IChooserTargetService;
+import android.text.TextUtils;
import android.util.Log;
import android.util.Slog;
+import android.view.View;
+import android.view.ViewGroup;
+
+import java.util.ArrayList;
+import java.util.List;
public class ChooserActivity extends ResolverActivity {
private static final String TAG = "ChooserActivity";
+ private static final boolean DEBUG = false;
+
+ private static final int QUERY_TARGET_LIMIT = 5;
+ private static final int WATCHDOG_TIMEOUT_MILLIS = 5000;
+
private Bundle mReplacementExtras;
private IntentSender mChosenComponentSender;
+ private ChooserTarget[] mCallerChooserTargets;
+
+ private final List<ChooserTargetServiceConnection> mServiceConnections = new ArrayList<>();
+
+ private static final int CHOOSER_TARGET_SERVICE_RESULT = 1;
+ private static final int CHOOSER_TARGET_SERVICE_WATCHDOG_TIMEOUT = 2;
+
+ private Handler mTargetResultHandler = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case CHOOSER_TARGET_SERVICE_RESULT:
+ if (DEBUG) Log.d(TAG, "CHOOSER_TARGET_SERVICE_RESULT");
+ if (isDestroyed()) break;
+ final ServiceResultInfo sri = (ServiceResultInfo) msg.obj;
+ if (!mServiceConnections.contains(sri.connection)) {
+ Log.w(TAG, "ChooserTargetServiceConnection " + sri.connection
+ + " returned after being removed from active connections."
+ + " Have you considered returning results faster?");
+ break;
+ }
+ final ChooserListAdapter cla = (ChooserListAdapter) getAdapter();
+ cla.addServiceResults(sri.originalTarget, sri.resultTargets);
+ unbindService(sri.connection);
+ mServiceConnections.remove(sri.connection);
+ break;
+
+ case CHOOSER_TARGET_SERVICE_WATCHDOG_TIMEOUT:
+ if (DEBUG) {
+ Log.d(TAG, "CHOOSER_TARGET_SERVICE_WATCHDOG_TIMEOUT; unbinding services");
+ }
+ unbindRemainingServices();
+ break;
+
+ default:
+ super.handleMessage(msg);
+ }
+ }
+ };
+
@Override
protected void onCreate(Bundle savedInstanceState) {
Intent intent = getIntent();
@@ -42,7 +109,7 @@ public class ChooserActivity extends ResolverActivity {
super.onCreate(null);
return;
}
- Intent target = (Intent)targetParcelable;
+ Intent target = (Intent) targetParcelable;
if (target != null) {
modifyTargetIntent(target);
}
@@ -68,6 +135,22 @@ public class ChooserActivity extends ResolverActivity {
initialIntents[i] = in;
}
}
+
+ pa = intent.getParcelableArrayExtra(Intent.EXTRA_CHOOSER_TARGETS);
+ if (pa != null) {
+ 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]);
+ finish();
+ super.onCreate(null);
+ return;
+ }
+ targets[i] = (ChooserTarget) pa[i];
+ }
+ mCallerChooserTargets = targets;
+ }
mChosenComponentSender = intent.getParcelableExtra(
Intent.EXTRA_CHOSEN_COMPONENT_INTENT_SENDER);
setSafeForwardingMode(true);
@@ -94,9 +177,9 @@ public class ChooserActivity extends ResolverActivity {
}
@Override
- public void onActivityStarted(Intent intent) {
+ void onActivityStarted(TargetInfo cti) {
if (mChosenComponentSender != null) {
- final ComponentName target = intent.getComponent();
+ final ComponentName target = cti.getResolvedComponentName();
if (target != null) {
final Intent fillIn = new Intent().putExtra(Intent.EXTRA_CHOSEN_COMPONENT, target);
try {
@@ -109,6 +192,16 @@ public class ChooserActivity extends ResolverActivity {
}
}
+ @Override
+ int getLayoutResource() {
+ return com.android.internal.R.layout.chooser_grid;
+ }
+
+ @Override
+ boolean shouldGetActivityMetadata() {
+ return true;
+ }
+
private void modifyTargetIntent(Intent in) {
final String action = in.getAction();
if (Intent.ACTION_SEND.equals(action) ||
@@ -117,4 +210,297 @@ public class ChooserActivity extends ResolverActivity {
Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
}
}
+
+ void queryTargetServices(ChooserListAdapter adapter) {
+ final PackageManager pm = getPackageManager();
+ int targetsToQuery = 0;
+ for (int i = 0, N = adapter.getDisplayResolveInfoCount(); i < N; i++) {
+ final DisplayResolveInfo dri = adapter.getDisplayResolveInfo(i);
+ final ActivityInfo ai = dri.getResolveInfo().activityInfo;
+ final Bundle md = ai.metaData;
+ final String serviceName = md != null ? convertServiceName(ai.packageName,
+ md.getString(ChooserTargetService.META_DATA_NAME)) : null;
+ if (serviceName != null) {
+ final ComponentName serviceComponent = new ComponentName(
+ ai.packageName, serviceName);
+ final Intent serviceIntent = new Intent(ChooserTargetService.SERVICE_INTERFACE)
+ .setComponent(serviceComponent);
+
+ if (DEBUG) {
+ Log.d(TAG, "queryTargets found target with service " + serviceComponent);
+ }
+
+ try {
+ final String perm = pm.getServiceInfo(serviceComponent, 0).permission;
+ if (!ChooserTargetService.BIND_PERMISSION.equals(perm)) {
+ Log.w(TAG, "ChooserTargetService " + serviceComponent + " does not require"
+ + " permission " + ChooserTargetService.BIND_PERMISSION
+ + " - this service will not be queried for ChooserTargets."
+ + " add android:permission=\""
+ + ChooserTargetService.BIND_PERMISSION + "\""
+ + " to the <service> tag for " + serviceComponent
+ + " in the manifest.");
+ continue;
+ }
+ } catch (NameNotFoundException e) {
+ Log.e(TAG, "Could not look up service " + serviceComponent, e);
+ continue;
+ }
+
+ final ChooserTargetServiceConnection conn = new ChooserTargetServiceConnection(dri);
+ if (bindServiceAsUser(serviceIntent, conn, BIND_AUTO_CREATE | BIND_NOT_FOREGROUND,
+ UserHandle.CURRENT)) {
+ if (DEBUG) {
+ Log.d(TAG, "Binding service connection for target " + dri
+ + " intent " + serviceIntent);
+ }
+ mServiceConnections.add(conn);
+ targetsToQuery++;
+ }
+ }
+ if (targetsToQuery >= QUERY_TARGET_LIMIT) {
+ if (DEBUG) Log.d(TAG, "queryTargets hit query target limit " + QUERY_TARGET_LIMIT);
+ break;
+ }
+ }
+
+ if (!mServiceConnections.isEmpty()) {
+ if (DEBUG) Log.d(TAG, "queryTargets setting watchdog timer for "
+ + WATCHDOG_TIMEOUT_MILLIS + "ms");
+ mTargetResultHandler.sendEmptyMessageDelayed(CHOOSER_TARGET_SERVICE_WATCHDOG_TIMEOUT,
+ WATCHDOG_TIMEOUT_MILLIS);
+ }
+ }
+
+ private String convertServiceName(String packageName, String serviceName) {
+ if (TextUtils.isEmpty(serviceName)) {
+ return null;
+ }
+
+ final String fullName;
+ if (serviceName.startsWith(".")) {
+ // Relative to the app package. Prepend the app package name.
+ fullName = packageName + serviceName;
+ } else if (serviceName.indexOf('.') >= 0) {
+ // Fully qualified package name.
+ fullName = serviceName;
+ } else {
+ fullName = null;
+ }
+ return fullName;
+ }
+
+ void unbindRemainingServices() {
+ if (DEBUG) {
+ Log.d(TAG, "unbindRemainingServices, " + mServiceConnections.size() + " left");
+ }
+ for (int i = 0, N = mServiceConnections.size(); i < N; i++) {
+ final ChooserTargetServiceConnection conn = mServiceConnections.get(i);
+ if (DEBUG) Log.d(TAG, "unbinding " + conn);
+ unbindService(conn);
+ }
+ mServiceConnections.clear();
+ mTargetResultHandler.removeMessages(CHOOSER_TARGET_SERVICE_WATCHDOG_TIMEOUT);
+ }
+
+ @Override
+ ResolveListAdapter createAdapter(Context context, Intent[] initialIntents,
+ List<ResolveInfo> rList, int launchedFromUid, boolean filterLastUsed) {
+ final ChooserListAdapter adapter = new ChooserListAdapter(context, initialIntents, rList,
+ launchedFromUid, filterLastUsed);
+ if (DEBUG) Log.d(TAG, "Adapter created; querying services");
+ queryTargetServices(adapter);
+ return adapter;
+ }
+
+ class ChooserTargetInfo implements TargetInfo {
+ private final TargetInfo mSourceInfo;
+ private final ChooserTarget mChooserTarget;
+ private final Drawable mDisplayIcon;
+
+ public ChooserTargetInfo(TargetInfo sourceInfo, ChooserTarget chooserTarget) {
+ mSourceInfo = sourceInfo;
+ mChooserTarget = chooserTarget;
+ mDisplayIcon = new BitmapDrawable(getResources(), chooserTarget.getIcon());
+ }
+
+ @Override
+ public Intent getResolvedIntent() {
+ final Intent targetIntent = mChooserTarget.getIntent();
+ return targetIntent != null ? targetIntent : mSourceInfo.getResolvedIntent();
+ }
+
+ @Override
+ public ComponentName getResolvedComponentName() {
+ return mSourceInfo.getResolvedComponentName();
+ }
+
+ @Override
+ public boolean start(Activity activity, Bundle options) {
+ return mChooserTarget.sendIntent(activity, mSourceInfo.getResolvedIntent());
+ }
+
+ @Override
+ public boolean startAsCaller(Activity activity, Bundle options, int userId) {
+ return mChooserTarget.sendIntentAsCaller(activity, mSourceInfo.getResolvedIntent(),
+ userId);
+ }
+
+ @Override
+ public boolean startAsUser(Activity activity, Bundle options, UserHandle user) {
+ return mChooserTarget.sendIntentAsUser(activity, mSourceInfo.getResolvedIntent(), user);
+ }
+
+ @Override
+ public ResolveInfo getResolveInfo() {
+ return mSourceInfo.getResolveInfo();
+ }
+
+ @Override
+ public CharSequence getDisplayLabel() {
+ return mChooserTarget.getTitle();
+ }
+
+ @Override
+ public CharSequence getExtendedInfo() {
+ return mSourceInfo.getExtendedInfo();
+ }
+
+ @Override
+ public Drawable getDisplayIcon() {
+ return mDisplayIcon;
+ }
+ }
+
+ public class ChooserListAdapter extends ResolveListAdapter {
+ private final List<ChooserTargetInfo> mServiceTargets = new ArrayList<>();
+
+ public ChooserListAdapter(Context context, Intent[] initialIntents, List<ResolveInfo> rList,
+ int launchedFromUid, boolean filterLastUsed) {
+ super(context, initialIntents, rList, launchedFromUid, filterLastUsed);
+ }
+
+ @Override
+ public boolean showsExtendedInfo(TargetInfo info) {
+ // Reserve space to show extended info if any one of the items in the adapter has
+ // extended info. This keeps grid item sizes uniform.
+ return hasExtendedInfo();
+ }
+
+ @Override
+ public View createView(ViewGroup parent) {
+ return mInflater.inflate(
+ com.android.internal.R.layout.resolve_grid_item, parent, false);
+ }
+
+ @Override
+ public void onListRebuilt() {
+ if (mServiceTargets != null) {
+ pruneServiceTargets();
+ }
+ }
+
+ @Override
+ public int getCount() {
+ int count = super.getCount();
+ if (mServiceTargets != null) {
+ count += mServiceTargets.size();
+ }
+ return count;
+ }
+
+ @Override
+ public TargetInfo getItem(int position) {
+ int offset = 0;
+ if (mServiceTargets != null) {
+ final int serviceTargetCount = mServiceTargets.size();
+ if (position < serviceTargetCount) {
+ return mServiceTargets.get(position);
+ }
+ offset += serviceTargetCount;
+ }
+ return super.getItem(position - offset);
+ }
+
+ public void addServiceResults(DisplayResolveInfo origTarget, List<ChooserTarget> targets) {
+ if (DEBUG) Log.d(TAG, "addServiceResults " + origTarget + ", " + targets.size()
+ + " targets");
+ for (int i = 0, N = targets.size(); i < N; i++) {
+ mServiceTargets.add(new ChooserTargetInfo(origTarget, targets.get(i)));
+ }
+
+ // TODO: Maintain sort by ranking scores.
+
+ notifyDataSetChanged();
+ }
+
+ private void pruneServiceTargets() {
+ if (DEBUG) Log.d(TAG, "pruneServiceTargets");
+ for (int i = mServiceTargets.size() - 1; i >= 0; i--) {
+ final ChooserTargetInfo cti = mServiceTargets.get(i);
+ if (!hasResolvedTarget(cti.getResolveInfo())) {
+ if (DEBUG) Log.d(TAG, " => " + i + " " + cti);
+ mServiceTargets.remove(i);
+ }
+ }
+ }
+ }
+
+ class ChooserTargetServiceConnection implements ServiceConnection {
+ private final DisplayResolveInfo mOriginalTarget;
+
+ private final IChooserTargetResult mChooserTargetResult = new IChooserTargetResult.Stub() {
+ @Override
+ public void sendResult(List<ChooserTarget> targets) throws RemoteException {
+ final Message msg = Message.obtain();
+ msg.what = CHOOSER_TARGET_SERVICE_RESULT;
+ msg.obj = new ServiceResultInfo(mOriginalTarget, targets,
+ ChooserTargetServiceConnection.this);
+ mTargetResultHandler.sendMessage(msg);
+ }
+ };
+
+ public ChooserTargetServiceConnection(DisplayResolveInfo dri) {
+ mOriginalTarget = dri;
+ }
+
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ if (DEBUG) Log.d(TAG, "onServiceConnected: " + name);
+ final IChooserTargetService icts = IChooserTargetService.Stub.asInterface(service);
+ try {
+ icts.getChooserTargets(mOriginalTarget.getResolvedComponentName(),
+ mOriginalTarget.getResolveInfo().filter, mChooserTargetResult);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Querying ChooserTargetService " + name + " failed.", e);
+ unbindService(this);
+ mServiceConnections.remove(this);
+ }
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName name) {
+ if (DEBUG) Log.d(TAG, "onServiceDisconnected: " + name);
+ unbindService(this);
+ mServiceConnections.remove(this);
+ }
+
+ @Override
+ public String toString() {
+ return mOriginalTarget.getResolveInfo().activityInfo.toString();
+ }
+ }
+
+ static class ServiceResultInfo {
+ public final DisplayResolveInfo originalTarget;
+ public final List<ChooserTarget> resultTargets;
+ public final ChooserTargetServiceConnection connection;
+
+ public ServiceResultInfo(DisplayResolveInfo ot, List<ChooserTarget> rt,
+ ChooserTargetServiceConnection c) {
+ originalTarget = ot;
+ resultTargets = rt;
+ connection = c;
+ }
+ }
}
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index 6b35f3f..3cd69a1 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -25,6 +25,7 @@ import android.provider.Settings;
import android.text.TextUtils;
import android.util.Slog;
import android.widget.AbsListView;
+import android.widget.GridView;
import com.android.internal.R;
import com.android.internal.content.PackageMonitor;
@@ -91,15 +92,14 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic
private PackageManager mPm;
private boolean mSafeForwardingMode;
private boolean mAlwaysUseOption;
- private boolean mShowExtended;
+ private AbsListView mAdapterView;
private ListView mListView;
+ private GridView mGridView;
private Button mAlwaysButton;
private Button mOnceButton;
private View mProfileView;
private int mIconDpi;
- private int mIconSize;
- private int mMaxColumns;
- private int mLastSelected = ListView.INVALID_POSITION;
+ private int mLastSelected = AbsListView.INVALID_POSITION;
private boolean mResolvingHome = false;
private int mProfileSwitchMessageId = -1;
private Intent mIntent;
@@ -192,7 +192,7 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic
}
/**
- * Compatibility version for other bundled services that use this ocerload without
+ * Compatibility version for other bundled services that use this overload without
* a default title resource
*/
protected void onCreate(Bundle savedInstanceState, Intent intent,
@@ -223,18 +223,14 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic
final long sinceTime = System.currentTimeMillis() - USAGE_STATS_PERIOD;
mStats = mUsm.queryAndAggregateUsageStats(sinceTime, System.currentTimeMillis());
- mMaxColumns = getResources().getInteger(R.integer.config_maxResolverActivityColumns);
-
mPackageMonitor.register(this, getMainLooper(), false);
mRegistered = true;
final ActivityManager am = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
mIconDpi = am.getLauncherLargeIconDensity();
- mIconSize = am.getLauncherLargeIconSize();
mIntent = new Intent(intent);
- mAdapter = new ResolveListAdapter(this, initialIntents, rList,
- mLaunchedFromUid, alwaysUseOption);
+ mAdapter = createAdapter(this, initialIntents, rList, mLaunchedFromUid, alwaysUseOption);
final int layoutId;
final boolean useHeader;
@@ -244,7 +240,7 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic
useHeader = true;
} else {
useHeader = false;
- layoutId = R.layout.resolver_list;
+ layoutId = getLayoutResource();
}
mAlwaysUseOption = alwaysUseOption;
@@ -257,21 +253,30 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic
int count = mAdapter.mList.size();
if (count > 1 || (count == 1 && mAdapter.getOtherProfile() != null)) {
setContentView(layoutId);
- mListView = (ListView) findViewById(R.id.resolver_list);
- mListView.setAdapter(mAdapter);
- mListView.setOnItemClickListener(this);
- mListView.setOnItemLongClickListener(new ItemLongClickListener());
+ mAdapterView = (AbsListView) findViewById(R.id.resolver_list);
+ mAdapterView.setAdapter(mAdapter);
+ mAdapterView.setOnItemClickListener(this);
+ mAdapterView.setOnItemLongClickListener(new ItemLongClickListener());
+
+ // Initialize the different types of collection views we may have. Depending
+ // on which ones are initialized later we'll configure different properties.
+ if (mAdapterView instanceof ListView) {
+ mListView = (ListView) mAdapterView;
+ }
+ if (mAdapterView instanceof GridView) {
+ mGridView = (GridView) mAdapterView;
+ }
if (alwaysUseOption) {
- mListView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
+ mAdapterView.setChoiceMode(AbsListView.CHOICE_MODE_SINGLE);
}
- if (useHeader) {
+ if (useHeader && mListView != null) {
mListView.addHeaderView(LayoutInflater.from(this).inflate(
R.layout.resolver_different_item_header, mListView, false));
}
} else if (count == 1) {
- safelyStartActivity(mAdapter.intentForPosition(0, false));
+ safelyStartActivity(mAdapter.targetInfoForPosition(0, false));
mPackageMonitor.unregister();
mRegistered = false;
finish();
@@ -282,8 +287,8 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic
final TextView empty = (TextView) findViewById(R.id.empty);
empty.setVisibility(View.VISIBLE);
- mListView = (ListView) findViewById(R.id.resolver_list);
- mListView.setVisibility(View.GONE);
+ mAdapterView = (AbsListView) findViewById(R.id.resolver_list);
+ mAdapterView.setVisibility(View.GONE);
}
// Prevent the Resolver window from becoming the top fullscreen window and thus from taking
// control of the system bars.
@@ -308,12 +313,30 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic
titleView.setText(title);
}
setTitle(title);
+
+ // Try to initialize the title icon if we have a view for it and a title to match
+ final ImageView titleIcon = (ImageView) findViewById(R.id.title_icon);
+ if (titleIcon != null) {
+ final String referrerPackage = getReferrerPackageName();
+ ApplicationInfo ai = null;
+ try {
+ if (!TextUtils.isEmpty(referrerPackage)) {
+ ai = mPm.getApplicationInfo(referrerPackage, 0);
+ }
+ } catch (NameNotFoundException e) {
+ Log.e(TAG, "Could not find referrer package " + referrerPackage);
+ }
+
+ if (ai != null) {
+ titleIcon.setImageDrawable(ai.loadIcon(mPm));
+ }
+ }
}
final ImageView iconView = (ImageView) findViewById(R.id.icon);
final DisplayResolveInfo iconInfo = mAdapter.getFilteredItem();
if (iconView != null && iconInfo != null) {
- new LoadIconIntoViewTask(iconView).execute(iconInfo);
+ new LoadIconIntoViewTask(iconInfo, iconView).execute();
}
if (alwaysUseOption || mAdapter.hasFilteredItem()) {
@@ -345,8 +368,7 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic
// Do not show the profile switch message anymore.
mProfileSwitchMessageId = -1;
- final Intent intent = intentForDisplayResolveInfo(dri);
- onIntentSelected(dri.ri, intent, false);
+ onTargetSelected(dri, false);
finish();
}
});
@@ -354,17 +376,29 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic
}
}
+ private String getReferrerPackageName() {
+ final Uri referrer = getReferrer();
+ if (referrer != null && "android-app".equals(referrer.getScheme())) {
+ return referrer.getHost();
+ }
+ return null;
+ }
+
+ int getLayoutResource() {
+ return R.layout.resolver_list;
+ }
+
void bindProfileView() {
final DisplayResolveInfo dri = mAdapter.getOtherProfile();
if (dri != null) {
mProfileView.setVisibility(View.VISIBLE);
final ImageView icon = (ImageView) mProfileView.findViewById(R.id.icon);
final TextView text = (TextView) mProfileView.findViewById(R.id.text1);
- if (dri.displayIcon == null) {
- new LoadIconTask().execute(dri);
+ if (!dri.hasDisplayIcon()) {
+ new LoadIconIntoViewTask(dri, icon).execute();
}
- icon.setImageDrawable(dri.displayIcon);
- text.setText(dri.displayLabel);
+ icon.setImageDrawable(dri.getDisplayIcon());
+ text.setText(dri.getDisplayLabel());
} else {
mProfileView.setVisibility(View.GONE);
}
@@ -408,8 +442,9 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic
if (title == ActionTitle.DEFAULT && defaultTitleRes != 0) {
return getString(defaultTitleRes);
} else {
- return named ? getString(title.namedTitleRes, mAdapter.getFilteredItem().displayLabel) :
- getString(title.titleRes);
+ return named
+ ? getString(title.namedTitleRes, mAdapter.getFilteredItem().getDisplayLabel())
+ : getString(title.titleRes);
}
}
@@ -490,31 +525,33 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
if (mAlwaysUseOption) {
- final int checkedPos = mListView.getCheckedItemPosition();
+ final int checkedPos = mAdapterView.getCheckedItemPosition();
final boolean hasValidSelection = checkedPos != ListView.INVALID_POSITION;
mLastSelected = checkedPos;
setAlwaysButtonEnabled(hasValidSelection, checkedPos, true);
mOnceButton.setEnabled(hasValidSelection);
if (hasValidSelection) {
- mListView.setSelection(checkedPos);
+ mAdapterView.setSelection(checkedPos);
}
}
}
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
- position -= mListView.getHeaderViewsCount();
+ if (mListView != null) {
+ position -= mListView.getHeaderViewsCount();
+ }
if (position < 0) {
// Header views don't count.
return;
}
- final int checkedPos = mListView.getCheckedItemPosition();
+ final int checkedPos = mAdapterView.getCheckedItemPosition();
final boolean hasValidSelection = checkedPos != ListView.INVALID_POSITION;
if (mAlwaysUseOption && (!hasValidSelection || mLastSelected != checkedPos)) {
setAlwaysButtonEnabled(hasValidSelection, checkedPos, true);
mOnceButton.setEnabled(hasValidSelection);
if (hasValidSelection) {
- mListView.smoothScrollToPosition(checkedPos);
+ mAdapterView.smoothScrollToPosition(checkedPos);
}
mLastSelected = checkedPos;
} else {
@@ -570,7 +607,7 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic
public void onButtonClick(View v) {
final int id = v.getId();
startSelected(mAlwaysUseOption ?
- mListView.getCheckedItemPosition() : mAdapter.getFilteredPosition(),
+ mAdapterView.getCheckedItemPosition() : mAdapter.getFilteredPosition(),
id == R.id.button_always,
mAlwaysUseOption);
}
@@ -588,8 +625,8 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic
return;
}
- Intent intent = mAdapter.intentForPosition(which, filtered);
- onIntentSelected(ri, intent, always);
+ TargetInfo target = mAdapter.targetInfoForPosition(which, filtered);
+ onTargetSelected(target, always);
finish();
}
@@ -600,8 +637,12 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic
return defIntent;
}
- protected void onIntentSelected(ResolveInfo ri, Intent intent, boolean alwaysCheck) {
- if ((mAlwaysUseOption || mAdapter.hasFilteredItem()) && mAdapter.mOrigResolveList != null) {
+ protected void onTargetSelected(TargetInfo target, boolean alwaysCheck) {
+ final ResolveInfo ri = target.getResolveInfo();
+ final Intent intent = target != null ? target.getResolvedIntent() : null;
+
+ if (intent != null && (mAlwaysUseOption || mAdapter.hasFilteredItem())
+ && mAdapter.mOrigResolveList != null) {
// Build a reasonable intent filter, based on what matched.
IntentFilter filter = new IntentFilter();
String action = intent.getAction();
@@ -617,7 +658,7 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic
}
filter.addCategory(Intent.CATEGORY_DEFAULT);
- int cat = ri.match&IntentFilter.MATCH_CATEGORY_MASK;
+ int cat = ri.match & IntentFilter.MATCH_CATEGORY_MASK;
Uri data = intent.getData();
if (cat == IntentFilter.MATCH_CATEGORY_TYPE) {
String mimeType = intent.resolveType(this);
@@ -726,25 +767,27 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic
}
}
- if (intent != null) {
- safelyStartActivity(intent);
+ if (target != null) {
+ safelyStartActivity(target);
}
}
- public void safelyStartActivity(Intent intent) {
+ void safelyStartActivity(TargetInfo cti) {
// If needed, show that intent is forwarded
// from managed profile to owner or other way around.
if (mProfileSwitchMessageId != -1) {
Toast.makeText(this, getString(mProfileSwitchMessageId), Toast.LENGTH_LONG).show();
}
if (!mSafeForwardingMode) {
- startActivity(intent);
- onActivityStarted(intent);
+ if (cti.start(this, null)) {
+ onActivityStarted(cti);
+ }
return;
}
try {
- startActivityAsCaller(intent, null, UserHandle.USER_NULL);
- onActivityStarted(intent);
+ if (cti.startAsCaller(this, null, UserHandle.USER_NULL)) {
+ onActivityStarted(cti);
+ }
} catch (RuntimeException e) {
String launchedFromPackage;
try {
@@ -759,51 +802,197 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic
}
}
- public void onActivityStarted(Intent intent) {
+ void onActivityStarted(TargetInfo cti) {
// Do nothing
}
+ boolean shouldGetActivityMetadata() {
+ return false;
+ }
+
void showAppDetails(ResolveInfo ri) {
Intent in = new Intent().setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
.setData(Uri.fromParts("package", ri.activityInfo.packageName, null))
- .addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
+ .addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT);
startActivity(in);
}
- Intent intentForDisplayResolveInfo(DisplayResolveInfo dri) {
- Intent intent = new Intent(dri.origIntent != null ? dri.origIntent :
- getReplacementIntent(dri.ri.activityInfo, mIntent));
- intent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT
- |Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP);
- ActivityInfo ai = dri.ri.activityInfo;
- intent.setComponent(new ComponentName(
- ai.applicationInfo.packageName, ai.name));
- return intent;
+ ResolveListAdapter createAdapter(Context context, Intent[] initialIntents,
+ List<ResolveInfo> rList, int launchedFromUid, boolean filterLastUsed) {
+ return new ResolveListAdapter(context, initialIntents, rList, launchedFromUid,
+ filterLastUsed);
+ }
+
+ ResolveListAdapter getAdapter() {
+ return mAdapter;
}
- private final class DisplayResolveInfo {
- ResolveInfo ri;
- CharSequence displayLabel;
- Drawable displayIcon;
- CharSequence extendedInfo;
- Intent origIntent;
+ final class DisplayResolveInfo implements TargetInfo {
+ private final ResolveInfo mResolveInfo;
+ private final CharSequence mDisplayLabel;
+ private Drawable mDisplayIcon;
+ private final CharSequence mExtendedInfo;
+ private final Intent mResolvedIntent;
DisplayResolveInfo(ResolveInfo pri, CharSequence pLabel,
CharSequence pInfo, Intent pOrigIntent) {
- ri = pri;
- displayLabel = pLabel;
- extendedInfo = pInfo;
- origIntent = pOrigIntent;
+ mResolveInfo = pri;
+ mDisplayLabel = pLabel;
+ mExtendedInfo = pInfo;
+
+ final Intent intent = new Intent(pOrigIntent != null ? pOrigIntent :
+ getReplacementIntent(pri.activityInfo, mIntent));
+ intent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT
+ | Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP);
+ final ActivityInfo ai = mResolveInfo.activityInfo;
+ intent.setComponent(new ComponentName(ai.applicationInfo.packageName, ai.name));
+
+ mResolvedIntent = intent;
+ }
+
+ public ResolveInfo getResolveInfo() {
+ return mResolveInfo;
+ }
+
+ public CharSequence getDisplayLabel() {
+ return mDisplayLabel;
+ }
+
+ public Drawable getDisplayIcon() {
+ return mDisplayIcon;
+ }
+
+ public void setDisplayIcon(Drawable icon) {
+ mDisplayIcon = icon;
+ }
+
+ public boolean hasDisplayIcon() {
+ return mDisplayIcon != null;
+ }
+
+ public CharSequence getExtendedInfo() {
+ return mExtendedInfo;
+ }
+
+ public Intent getResolvedIntent() {
+ return mResolvedIntent;
+ }
+
+ @Override
+ public ComponentName getResolvedComponentName() {
+ return new ComponentName(mResolveInfo.activityInfo.packageName,
+ mResolveInfo.activityInfo.name);
+ }
+
+ @Override
+ public boolean start(Activity activity, Bundle options) {
+ activity.startActivity(mResolvedIntent, options);
+ return true;
}
+
+ @Override
+ public boolean startAsCaller(Activity activity, Bundle options, int userId) {
+ activity.startActivityAsCaller(mResolvedIntent, options, userId);
+ return true;
+ }
+
+ @Override
+ public boolean startAsUser(Activity activity, Bundle options, UserHandle user) {
+ activity.startActivityAsUser(mResolvedIntent, options, user);
+ return false;
+ }
+ }
+
+ /**
+ * A single target as represented in the chooser.
+ */
+ public interface TargetInfo {
+ /**
+ * Get the resolved intent that represents this target. Note that this may not be the
+ * intent that will be launched by calling one of the <code>start</code> methods provided;
+ * this is the intent that will be credited with the launch.
+ *
+ * @return the resolved intent for this target
+ */
+ public Intent getResolvedIntent();
+
+ /**
+ * Get the resolved component name that represents this target. Note that this may not
+ * be the component that will be directly launched by calling one of the <code>start</code>
+ * methods provided; this is the component that will be credited with the launch.
+ *
+ * @return the resolved ComponentName for this target
+ */
+ public ComponentName getResolvedComponentName();
+
+ /**
+ * Start the activity referenced by this target.
+ *
+ * @param activity calling Activity performing the launch
+ * @param options ActivityOptions bundle
+ * @return true if the start completed successfully
+ */
+ public boolean start(Activity activity, Bundle options);
+
+ /**
+ * Start the activity referenced by this target as if the ResolverActivity's caller
+ * was performing the start operation.
+ *
+ * @param activity calling Activity (actually) performing the launch
+ * @param options ActivityOptions bundle
+ * @param userId userId to start as or {@link UserHandle#USER_NULL} for activity's caller
+ * @return true if the start completed successfully
+ */
+ public boolean startAsCaller(Activity activity, Bundle options, int userId);
+
+ /**
+ * Start the activity referenced by this target as a given user.
+ *
+ * @param activity calling activity performing the launch
+ * @param options ActivityOptions bundle
+ * @param user handle for the user to start the activity as
+ * @return true if the start completed successfully
+ */
+ public boolean startAsUser(Activity activity, Bundle options, UserHandle user);
+
+ /**
+ * Return the ResolveInfo about how and why this target matched the original query
+ * for available targets.
+ *
+ * @return ResolveInfo representing this target's match
+ */
+ public ResolveInfo getResolveInfo();
+
+ /**
+ * Return the human-readable text label for this target.
+ *
+ * @return user-visible target label
+ */
+ public CharSequence getDisplayLabel();
+
+ /**
+ * Return any extended info for this target. This may be used to disambiguate
+ * otherwise identical targets.
+ *
+ * @return human-readable disambig string or null if none present
+ */
+ public CharSequence getExtendedInfo();
+
+ /**
+ * @return The drawable that should be used to represent this target
+ */
+ public Drawable getDisplayIcon();
}
- private final class ResolveListAdapter extends BaseAdapter {
+ class ResolveListAdapter extends BaseAdapter {
private final Intent[] mInitialIntents;
private final List<ResolveInfo> mBaseResolveList;
private ResolveInfo mLastChosen;
private DisplayResolveInfo mOtherProfile;
private final int mLaunchedFromUid;
- private final LayoutInflater mInflater;
+ private boolean mHasExtendedInfo;
+
+ protected final LayoutInflater mInflater;
List<DisplayResolveInfo> mList;
List<ResolveInfo> mOrigResolveList;
@@ -817,7 +1006,7 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic
mBaseResolveList = rList;
mLaunchedFromUid = launchedFromUid;
mInflater = LayoutInflater.from(context);
- mList = new ArrayList<DisplayResolveInfo>();
+ mList = new ArrayList<>();
mFilterLastUsed = filterLastUsed;
rebuildList();
}
@@ -871,9 +1060,11 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic
if (mBaseResolveList != null) {
currentResolveList = mOrigResolveList = mBaseResolveList;
} else {
- currentResolveList = mOrigResolveList = mPm.queryIntentActivities(
- mIntent, PackageManager.MATCH_DEFAULT_ONLY
- | (mFilterLastUsed ? PackageManager.GET_RESOLVED_FILTER : 0));
+ currentResolveList = mOrigResolveList = mPm.queryIntentActivities(mIntent,
+ PackageManager.MATCH_DEFAULT_ONLY
+ | (mFilterLastUsed ? PackageManager.GET_RESOLVED_FILTER : 0)
+ | (shouldGetActivityMetadata() ? PackageManager.GET_META_DATA : 0)
+ );
// 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
@@ -961,7 +1152,7 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic
r0 = currentResolveList.get(0);
int start = 0;
CharSequence r0Label = r0.loadLabel(mPm);
- mShowExtended = false;
+ mHasExtendedInfo = false;
for (int i = 1; i < N; i++) {
if (r0Label == null) {
r0Label = r0.activityInfo.packageName;
@@ -989,6 +1180,12 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic
mLastChosenPosition = -1;
mFilterLastUsed = false;
}
+
+ onListRebuilt();
+ }
+
+ public void onListRebuilt() {
+ // This space for rent
}
private void processGroup(List<ResolveInfo> rList, int start, int end, ResolveInfo ro,
@@ -1000,7 +1197,7 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic
addResolveInfo(new DisplayResolveInfo(ro, roLabel, null, null));
updateLastChosenPosition(ro);
} else {
- mShowExtended = true;
+ mHasExtendedInfo = true;
boolean usePkg = false;
CharSequence startApp = ro.activityInfo.applicationInfo.loadLabel(mPm);
if (startApp == null) {
@@ -1049,7 +1246,7 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic
}
private void addResolveInfo(DisplayResolveInfo dri) {
- if (dri.ri.targetUserId != UserHandle.USER_CURRENT && mOtherProfile == null) {
+ if (dri.mResolveInfo.targetUserId != UserHandle.USER_CURRENT && mOtherProfile == null) {
// So far we only support a single other profile at a time.
// The first one we see gets special treatment.
mOtherProfile = dri;
@@ -1059,12 +1256,11 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic
}
public ResolveInfo resolveInfoForPosition(int position, boolean filtered) {
- return (filtered ? getItem(position) : mList.get(position)).ri;
+ return (filtered ? getItem(position) : mList.get(position)).getResolveInfo();
}
- public Intent intentForPosition(int position, boolean filtered) {
- DisplayResolveInfo dri = filtered ? getItem(position) : mList.get(position);
- return intentForDisplayResolveInfo(dri);
+ public TargetInfo targetInfoForPosition(int position, boolean filtered) {
+ return filtered ? getItem(position) : mList.get(position);
}
public int getCount() {
@@ -1075,7 +1271,7 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic
return result;
}
- public DisplayResolveInfo getItem(int position) {
+ public TargetInfo getItem(int position) {
if (mFilterLastUsed && mLastChosenPosition >= 0 && position >= mLastChosenPosition) {
position++;
}
@@ -1086,11 +1282,31 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic
return position;
}
- public View getView(int position, View convertView, ViewGroup parent) {
+ public boolean hasExtendedInfo() {
+ return mHasExtendedInfo;
+ }
+
+ public boolean hasResolvedTarget(ResolveInfo info) {
+ for (int i = 0, N = mList.size(); i < N; i++) {
+ if (info.equals(mList.get(i).getResolveInfo())) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ protected int getDisplayResolveInfoCount() {
+ return mList.size();
+ }
+
+ protected DisplayResolveInfo getDisplayResolveInfo(int index) {
+ return mList.get(index);
+ }
+
+ public final View getView(int position, View convertView, ViewGroup parent) {
View view = convertView;
if (view == null) {
- view = mInflater.inflate(
- com.android.internal.R.layout.resolve_list_item, parent, false);
+ view = createView(parent);
final ViewHolder holder = new ViewHolder(view);
view.setTag(holder);
@@ -1099,19 +1315,29 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic
return view;
}
- private final void bindView(View view, DisplayResolveInfo info) {
+ public View createView(ViewGroup parent) {
+ return mInflater.inflate(
+ com.android.internal.R.layout.resolve_list_item, parent, false);
+ }
+
+ public boolean showsExtendedInfo(TargetInfo info) {
+ return !TextUtils.isEmpty(info.getExtendedInfo());
+ }
+
+ private final void bindView(View view, TargetInfo info) {
final ViewHolder holder = (ViewHolder) view.getTag();
- holder.text.setText(info.displayLabel);
- if (mShowExtended) {
+ holder.text.setText(info.getDisplayLabel());
+ if (showsExtendedInfo(info)) {
holder.text2.setVisibility(View.VISIBLE);
- holder.text2.setText(info.extendedInfo);
+ holder.text2.setText(info.getExtendedInfo());
} else {
holder.text2.setVisibility(View.GONE);
}
- if (info.displayIcon == null) {
- new LoadIconTask().execute(info);
+ if (info instanceof DisplayResolveInfo
+ && !((DisplayResolveInfo) info).hasDisplayIcon()) {
+ new LoadAdapterIconTask((DisplayResolveInfo) info).execute();
}
- holder.icon.setImageDrawable(info.displayIcon);
+ holder.icon.setImageDrawable(info.getDisplayIcon());
}
}
@@ -1131,7 +1357,9 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic
@Override
public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
- position -= mListView.getHeaderViewsCount();
+ if (mListView != null) {
+ position -= mListView.getHeaderViewsCount();
+ }
if (position < 0) {
// Header views don't count.
return false;
@@ -1143,44 +1371,53 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic
}
- class LoadIconTask extends AsyncTask<DisplayResolveInfo, Void, DisplayResolveInfo> {
+ abstract class LoadIconTask extends AsyncTask<Void, Void, Drawable> {
+ protected final DisplayResolveInfo mDisplayResolveInfo;
+ private final ResolveInfo mResolveInfo;
+
+ public LoadIconTask(DisplayResolveInfo dri) {
+ mDisplayResolveInfo = dri;
+ mResolveInfo = dri.getResolveInfo();
+ }
+
@Override
- protected DisplayResolveInfo doInBackground(DisplayResolveInfo... params) {
- final DisplayResolveInfo info = params[0];
- if (info.displayIcon == null) {
- info.displayIcon = loadIconForResolveInfo(info.ri);
- }
- return info;
+ protected Drawable doInBackground(Void... params) {
+ return loadIconForResolveInfo(mResolveInfo);
+ }
+
+ @Override
+ protected void onPostExecute(Drawable d) {
+ mDisplayResolveInfo.setDisplayIcon(d);
+ }
+ }
+
+ class LoadAdapterIconTask extends LoadIconTask {
+ public LoadAdapterIconTask(DisplayResolveInfo dri) {
+ super(dri);
}
@Override
- protected void onPostExecute(DisplayResolveInfo info) {
- if (mProfileView != null && mAdapter.getOtherProfile() == info) {
+ protected void onPostExecute(Drawable d) {
+ super.onPostExecute(d);
+ if (mProfileView != null && mAdapter.getOtherProfile() == mDisplayResolveInfo) {
bindProfileView();
}
mAdapter.notifyDataSetChanged();
}
}
- class LoadIconIntoViewTask extends AsyncTask<DisplayResolveInfo, Void, DisplayResolveInfo> {
- final ImageView mTargetView;
+ class LoadIconIntoViewTask extends LoadIconTask {
+ private final ImageView mTargetView;
- public LoadIconIntoViewTask(ImageView target) {
+ public LoadIconIntoViewTask(DisplayResolveInfo dri, ImageView target) {
+ super(dri);
mTargetView = target;
}
@Override
- protected DisplayResolveInfo doInBackground(DisplayResolveInfo... params) {
- final DisplayResolveInfo info = params[0];
- if (info.displayIcon == null) {
- info.displayIcon = loadIconForResolveInfo(info.ri);
- }
- return info;
- }
-
- @Override
- protected void onPostExecute(DisplayResolveInfo info) {
- mTargetView.setImageDrawable(info.displayIcon);
+ protected void onPostExecute(Drawable d) {
+ super.onPostExecute(d);
+ mTargetView.setImageDrawable(d);
}
}
diff --git a/core/res/res/layout/chooser_grid.xml b/core/res/res/layout/chooser_grid.xml
new file mode 100644
index 0000000..0fa82eb
--- /dev/null
+++ b/core/res/res/layout/chooser_grid.xml
@@ -0,0 +1,107 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+* Copyright 2015, The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+-->
+<com.android.internal.widget.ResolverDrawerLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:maxWidth="@dimen/resolver_max_width"
+ android:maxCollapsedHeight="256dp"
+ android:maxCollapsedHeightSmall="56dp"
+ android:id="@id/contentPanel">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_alwaysShow="true"
+ android:elevation="8dp"
+ android:paddingStart="?attr/dialogPreferredPadding"
+ android:background="@color/white" >
+ <ImageView android:id="@+id/title_icon"
+ android:layout_width="24dp"
+ android:layout_height="24dp"
+ android:layout_gravity="start|center_vertical"
+ android:layout_marginEnd="16dp"
+ android:scaleType="fitCenter" />
+ <TextView android:id="@+id/title"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:minHeight="56dp"
+ android:textAppearance="?attr/textAppearanceMedium"
+ android:gravity="start|center_vertical"
+ android:paddingEnd="?attr/dialogPreferredPadding"
+ android:paddingTop="8dp"
+ android:paddingBottom="8dp" />
+ <LinearLayout android:id="@+id/profile_button"
+ android:layout_width="wrap_content"
+ android:layout_height="48dp"
+ android:layout_marginTop="4dp"
+ android:layout_marginEnd="4dp"
+ android:paddingStart="8dp"
+ android:paddingEnd="8dp"
+ android:paddingTop="4dp"
+ android:paddingBottom="4dp"
+ android:focusable="true"
+ android:visibility="gone"
+ style="?attr/borderlessButtonStyle">
+ <ImageView android:id="@+id/icon"
+ android:layout_width="24dp"
+ android:layout_height="24dp"
+ android:layout_gravity="start|center_vertical"
+ android:layout_marginStart="4dp"
+ android:layout_marginEnd="16dp"
+ android:layout_marginTop="12dp"
+ android:layout_marginBottom="12dp"
+ android:scaleType="fitCenter" />
+ <TextView android:id="@id/text1"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="start|center_vertical"
+ android:layout_marginEnd="16dp"
+ android:textAppearance="?attr/textAppearanceButton"
+ android:textColor="?attr/textColorPrimary"
+ android:minLines="1"
+ android:maxLines="1"
+ android:ellipsize="marquee" />
+ </LinearLayout>
+ </LinearLayout>
+
+ <GridView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:id="@+id/resolver_list"
+ android:clipToPadding="false"
+ android:paddingStart="@dimen/chooser_grid_padding"
+ android:paddingEnd="@dimen/chooser_grid_padding"
+ android:scrollbarStyle="outsideOverlay"
+ android:background="@color/white"
+ android:elevation="8dp"
+ android:numColumns="4"
+ android:nestedScrollingEnabled="true" />
+
+ <TextView android:id="@+id/empty"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_alwaysShow="true"
+ android:text="@string/noApplications"
+ android:padding="32dp"
+ android:gravity="center"
+ android:visibility="gone" />
+
+</com.android.internal.widget.ResolverDrawerLayout>
diff --git a/core/res/res/layout/resolve_grid_item.xml b/core/res/res/layout/resolve_grid_item.xml
new file mode 100644
index 0000000..664b02f
--- /dev/null
+++ b/core/res/res/layout/resolve_grid_item.xml
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="match_parent" android:layout_height="wrap_content"
+ android:minWidth="80dp"
+ android:gravity="center"
+ android:paddingTop="8dp"
+ android:paddingBottom="8dp"
+ android:background="?attr/activatedBackgroundIndicator">
+
+ <!-- Activity icon when presenting dialog -->
+ <ImageView android:id="@+id/icon"
+ android:layout_width="48dp"
+ android:layout_height="48dp"
+ android:scaleType="fitCenter" />
+
+ <!-- Activity name -->
+ <TextView android:id="@android:id/text1"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="8dp"
+ android:layout_marginLeft="4dp"
+ android:layout_marginRight="4dp"
+ android:textAppearance="?attr/textAppearanceSmall"
+ android:textColor="?attr/textColorPrimary"
+ android:fontFamily="sans-serif-condensed"
+ android:gravity="center"
+ android:minLines="2"
+ android:maxLines="2"
+ android:ellipsize="marquee" />
+ <!-- Extended activity info to distinguish between duplicate activity names -->
+ <TextView android:id="@android:id/text2"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="4dp"
+ android:layout_marginRight="4dp"
+ android:minLines="2"
+ android:maxLines="2"
+ android:gravity="center"
+ android:ellipsize="marquee" />
+</LinearLayout>
+
diff --git a/core/res/res/values-sw360dp/dimens.xml b/core/res/res/values-sw360dp/dimens.xml
new file mode 100644
index 0000000..4c74264
--- /dev/null
+++ b/core/res/res/values-sw360dp/dimens.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+<resources>
+ <dimen name="chooser_grid_padding">16dp</dimen>
+</resources>
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 2654a25..100b161 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -394,4 +394,5 @@
<dimen name="floating_toolbar_minimum_overflow_height">192dp</dimen>
<dimen name="floating_toolbar_overflow_width">130dp</dimen>
<dimen name="floating_toolbar_margin">2dp</dimen>
+ <dimen name="chooser_grid_padding">0dp</dimen>
</resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 42d187d..36a736a 100755
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2232,4 +2232,7 @@
<java-symbol type="layout" name="date_picker_month_item_material" />
<java-symbol type="id" name="month_view" />
<java-symbol type="integer" name="config_zen_repeat_callers_threshold" />
+ <java-symbol type="layout" name="chooser_grid" />
+ <java-symbol type="layout" name="resolve_grid_item" />
+ <java-symbol type="id" name="title_icon" />
</resources>
diff --git a/packages/SystemUI/src/com/android/systemui/usb/UsbResolverActivity.java b/packages/SystemUI/src/com/android/systemui/usb/UsbResolverActivity.java
index 9928f7f..23a65e8 100644
--- a/packages/SystemUI/src/com/android/systemui/usb/UsbResolverActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/usb/UsbResolverActivity.java
@@ -93,7 +93,8 @@ public class UsbResolverActivity extends ResolverActivity {
}
@Override
- protected void onIntentSelected(ResolveInfo ri, Intent intent, boolean alwaysCheck) {
+ protected void onTargetSelected(TargetInfo target, boolean alwaysCheck) {
+ final ResolveInfo ri = target.getResolveInfo();
try {
IBinder b = ServiceManager.getService(USB_SERVICE);
IUsbManager service = IUsbManager.Stub.asInterface(b);
@@ -121,7 +122,7 @@ public class UsbResolverActivity extends ResolverActivity {
}
try {
- startActivityAsUser(intent, new UserHandle(userId));
+ target.startAsUser(this, null, new UserHandle(userId));
} catch (ActivityNotFoundException e) {
Log.e(TAG, "startActivity failed", e);
}