Bringing new Chooser UI closer to spec
Separate the chooser targets into rows by type. Remove some API that was redundant with LabeledIntent, simplifying ChooserTarget. Change-Id: I90de471825f05d85e6ffbe72a32fb597be824a30
This commit is contained in:
@@ -8294,7 +8294,6 @@ package android.content {
|
||||
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";
|
||||
field public static final java.lang.String EXTRA_DATA_REMOVED = "android.intent.extra.DATA_REMOVED";
|
||||
@@ -28730,10 +28729,8 @@ 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();
|
||||
|
||||
@@ -8520,7 +8520,6 @@ package android.content {
|
||||
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";
|
||||
field public static final java.lang.String EXTRA_DATA_REMOVED = "android.intent.extra.DATA_REMOVED";
|
||||
@@ -30744,10 +30743,8 @@ 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();
|
||||
|
||||
@@ -3364,14 +3364,6 @@ 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
|
||||
|
||||
@@ -57,12 +57,6 @@ 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.
|
||||
*/
|
||||
@@ -146,43 +140,6 @@ public final class ChooserTarget implements Parcelable {
|
||||
mIntentSender = intentSender;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 Intent supplied will be
|
||||
* {@link Intent#fillIn(Intent, int) filled in} by the Intent originally supplied
|
||||
* to the chooser.</p>
|
||||
*
|
||||
* <p>Take care not to place custom {@link android.os.Parcelable} types into
|
||||
* the Intent 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 intent Intent to fill in and send if the user chooses this target
|
||||
*/
|
||||
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) {
|
||||
@@ -192,9 +149,6 @@ public final class ChooserTarget implements Parcelable {
|
||||
}
|
||||
mScore = in.readFloat();
|
||||
mIntentSender = IntentSender.readIntentSenderOrNullFromParcel(in);
|
||||
if (in.readInt() != 0) {
|
||||
mIntent = Intent.CREATOR.createFromParcel(in);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -240,18 +194,6 @@ public final class ChooserTarget implements Parcelable {
|
||||
return mIntentSender;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
@@ -272,91 +214,8 @@ public final class ChooserTarget implements Parcelable {
|
||||
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");
|
||||
Log.e(TAG, "sendIntent " + this + " failed - no IntentSender to send");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -364,7 +223,7 @@ public final class ChooserTarget implements Parcelable {
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ChooserTarget{"
|
||||
+ (mIntentSender != null ? mIntentSender.getCreatorPackage() : mIntent)
|
||||
+ (mIntentSender != null ? mIntentSender.getCreatorPackage() : null)
|
||||
+ ", "
|
||||
+ "'" + mTitle
|
||||
+ "', " + mScore + "}";
|
||||
@@ -386,10 +245,6 @@ public final class ChooserTarget implements Parcelable {
|
||||
}
|
||||
dest.writeFloat(mScore);
|
||||
IntentSender.writeIntentSenderOrNullToParcel(mIntentSender, dest);
|
||||
dest.writeInt(mIntent != null ? 1 : 0);
|
||||
if (mIntent != null) {
|
||||
mIntent.writeToParcel(dest, 0);
|
||||
}
|
||||
}
|
||||
|
||||
public static final Creator<ChooserTarget> CREATOR
|
||||
|
||||
@@ -24,9 +24,11 @@ import android.content.IntentSender;
|
||||
import android.content.IntentSender.SendIntentException;
|
||||
import android.content.ServiceConnection;
|
||||
import android.content.pm.ActivityInfo;
|
||||
import android.content.pm.LabeledIntent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.PackageManager.NameNotFoundException;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.database.DataSetObserver;
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Bundle;
|
||||
@@ -37,6 +39,7 @@ import android.os.Parcelable;
|
||||
import android.os.RemoteException;
|
||||
import android.os.ResultReceiver;
|
||||
import android.os.UserHandle;
|
||||
import android.os.UserManager;
|
||||
import android.service.chooser.ChooserTarget;
|
||||
import android.service.chooser.ChooserTargetService;
|
||||
import android.service.chooser.IChooserTargetResult;
|
||||
@@ -44,8 +47,16 @@ import android.service.chooser.IChooserTargetService;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import android.util.Slog;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.View.OnClickListener;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.ViewGroup.LayoutParams;
|
||||
import android.widget.AbsListView;
|
||||
import android.widget.BaseAdapter;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.ListView;
|
||||
import com.android.internal.R;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@@ -63,7 +74,7 @@ public class ChooserActivity extends ResolverActivity {
|
||||
private IntentSender mRefinementIntentSender;
|
||||
private RefinementResultReceiver mRefinementResultReceiver;
|
||||
|
||||
private ChooserTarget[] mCallerChooserTargets;
|
||||
private ChooserListAdapter mChooserListAdapter;
|
||||
|
||||
private final List<ChooserTargetServiceConnection> mServiceConnections = new ArrayList<>();
|
||||
|
||||
@@ -84,8 +95,7 @@ public class ChooserActivity extends ResolverActivity {
|
||||
+ " Have you considered returning results faster?");
|
||||
break;
|
||||
}
|
||||
final ChooserListAdapter cla = (ChooserListAdapter) getAdapter();
|
||||
cla.addServiceResults(sri.originalTarget, sri.resultTargets);
|
||||
mChooserListAdapter.addServiceResults(sri.originalTarget, sri.resultTargets);
|
||||
unbindService(sri.connection);
|
||||
mServiceConnections.remove(sri.connection);
|
||||
break;
|
||||
@@ -166,20 +176,6 @@ public class ChooserActivity extends ResolverActivity {
|
||||
}
|
||||
}
|
||||
|
||||
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(TAG, "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);
|
||||
mRefinementIntentSender = intent.getParcelableExtra(
|
||||
@@ -232,9 +228,20 @@ public class ChooserActivity extends ResolverActivity {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
void onPrepareAdapterView(AbsListView adapterView, ResolveListAdapter adapter,
|
||||
boolean alwaysUseOption) {
|
||||
final ListView listView = adapterView instanceof ListView ? (ListView) adapterView : null;
|
||||
mChooserListAdapter = (ChooserListAdapter) adapter;
|
||||
adapterView.setAdapter(new ChooserRowAdapter(mChooserListAdapter));
|
||||
if (listView != null) {
|
||||
listView.setItemsCanFocus(true);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
int getLayoutResource() {
|
||||
return com.android.internal.R.layout.chooser_grid;
|
||||
return R.layout.chooser_grid;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -413,10 +420,11 @@ public class ChooserActivity extends ResolverActivity {
|
||||
}
|
||||
|
||||
@Override
|
||||
ResolveListAdapter createAdapter(Context context, Intent[] initialIntents,
|
||||
List<ResolveInfo> rList, int launchedFromUid, boolean filterLastUsed) {
|
||||
final ChooserListAdapter adapter = new ChooserListAdapter(context, initialIntents, rList,
|
||||
launchedFromUid, filterLastUsed, mCallerChooserTargets);
|
||||
ResolveListAdapter createAdapter(Context context, List<Intent> payloadIntents,
|
||||
Intent[] initialIntents, List<ResolveInfo> rList, int launchedFromUid,
|
||||
boolean filterLastUsed) {
|
||||
final ChooserListAdapter adapter = new ChooserListAdapter(context, payloadIntents,
|
||||
initialIntents, rList, launchedFromUid, filterLastUsed);
|
||||
if (DEBUG) Log.d(TAG, "Adapter created; querying services");
|
||||
queryTargetServices(adapter);
|
||||
return adapter;
|
||||
@@ -426,17 +434,23 @@ public class ChooserActivity extends ResolverActivity {
|
||||
private final DisplayResolveInfo mSourceInfo;
|
||||
private final ResolveInfo mBackupResolveInfo;
|
||||
private final ChooserTarget mChooserTarget;
|
||||
private Drawable mBadgeIcon = null;
|
||||
private final Drawable mDisplayIcon;
|
||||
private final Intent mFillInIntent;
|
||||
private final int mFillInFlags;
|
||||
|
||||
public ChooserTargetInfo(ChooserTarget target) {
|
||||
this(null, target);
|
||||
}
|
||||
|
||||
public ChooserTargetInfo(DisplayResolveInfo sourceInfo, ChooserTarget chooserTarget) {
|
||||
mSourceInfo = sourceInfo;
|
||||
mChooserTarget = chooserTarget;
|
||||
if (sourceInfo != null) {
|
||||
final ResolveInfo ri = sourceInfo.getResolveInfo();
|
||||
if (ri != null) {
|
||||
final ActivityInfo ai = ri.activityInfo;
|
||||
if (ai != null && ai.applicationInfo != null) {
|
||||
mBadgeIcon = getPackageManager().getApplicationIcon(ai.applicationInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
mDisplayIcon = new BitmapDrawable(getResources(), chooserTarget.getIcon());
|
||||
|
||||
if (sourceInfo != null) {
|
||||
@@ -453,6 +467,7 @@ public class ChooserActivity extends ResolverActivity {
|
||||
mSourceInfo = other.mSourceInfo;
|
||||
mBackupResolveInfo = other.mBackupResolveInfo;
|
||||
mChooserTarget = other.mChooserTarget;
|
||||
mBadgeIcon = other.mBadgeIcon;
|
||||
mDisplayIcon = other.mDisplayIcon;
|
||||
mFillInIntent = fillInIntent;
|
||||
mFillInFlags = flags;
|
||||
@@ -460,10 +475,7 @@ public class ChooserActivity extends ResolverActivity {
|
||||
|
||||
@Override
|
||||
public Intent getResolvedIntent() {
|
||||
final Intent targetIntent = mChooserTarget.getIntent();
|
||||
if (targetIntent != null) {
|
||||
return targetIntent;
|
||||
} else if (mSourceInfo != null) {
|
||||
if (mSourceInfo != null) {
|
||||
return mSourceInfo.getResolvedIntent();
|
||||
}
|
||||
return getTargetIntent();
|
||||
@@ -507,7 +519,8 @@ public class ChooserActivity extends ResolverActivity {
|
||||
if (intent == null) {
|
||||
return false;
|
||||
}
|
||||
return mChooserTarget.sendIntentAsCaller(activity, intent, userId);
|
||||
// ChooserTargets will launch with their IntentSender's identity
|
||||
return mChooserTarget.sendIntent(activity, intent);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -516,7 +529,8 @@ public class ChooserActivity extends ResolverActivity {
|
||||
if (intent == null) {
|
||||
return false;
|
||||
}
|
||||
return mChooserTarget.sendIntentAsUser(activity, intent, user);
|
||||
// ChooserTargets will launch with their IntentSender's identity
|
||||
return mChooserTarget.sendIntent(activity, intent);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -539,6 +553,11 @@ public class ChooserActivity extends ResolverActivity {
|
||||
return mDisplayIcon;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Drawable getBadgeIcon() {
|
||||
return mBadgeIcon;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TargetInfo cloneFilledIn(Intent fillInIntent, int flags) {
|
||||
return new ChooserTargetInfo(this, fillInIntent, flags);
|
||||
@@ -556,16 +575,49 @@ public class ChooserActivity extends ResolverActivity {
|
||||
}
|
||||
|
||||
public class ChooserListAdapter extends ResolveListAdapter {
|
||||
public static final int TARGET_BAD = -1;
|
||||
public static final int TARGET_CALLER = 0;
|
||||
public static final int TARGET_SERVICE = 1;
|
||||
public static final int TARGET_STANDARD = 2;
|
||||
|
||||
private final List<ChooserTargetInfo> mServiceTargets = new ArrayList<>();
|
||||
private final List<ChooserTargetInfo> mCallerTargets = new ArrayList<>();
|
||||
private final List<TargetInfo> mCallerTargets = new ArrayList<>();
|
||||
|
||||
public ChooserListAdapter(Context context, Intent[] initialIntents, List<ResolveInfo> rList,
|
||||
int launchedFromUid, boolean filterLastUsed, ChooserTarget[] callerChooserTargets) {
|
||||
super(context, initialIntents, rList, launchedFromUid, filterLastUsed);
|
||||
public ChooserListAdapter(Context context, List<Intent> payloadIntents,
|
||||
Intent[] initialIntents, List<ResolveInfo> rList, int launchedFromUid,
|
||||
boolean filterLastUsed) {
|
||||
// Don't send the initial intents through the shared ResolverActivity path,
|
||||
// we want to separate them into a different section.
|
||||
super(context, payloadIntents, null, rList, launchedFromUid, filterLastUsed);
|
||||
|
||||
if (callerChooserTargets != null) {
|
||||
for (ChooserTarget target : callerChooserTargets) {
|
||||
mCallerTargets.add(new ChooserTargetInfo(target));
|
||||
if (initialIntents != null) {
|
||||
final PackageManager pm = getPackageManager();
|
||||
for (int i = 0; i < initialIntents.length; i++) {
|
||||
final Intent ii = initialIntents[i];
|
||||
if (ii == null) {
|
||||
continue;
|
||||
}
|
||||
final ActivityInfo ai = ii.resolveActivityInfo(pm, 0);
|
||||
if (ai == null) {
|
||||
Log.w(TAG, "No activity found for " + ii);
|
||||
continue;
|
||||
}
|
||||
ResolveInfo ri = new ResolveInfo();
|
||||
ri.activityInfo = ai;
|
||||
UserManager userManager =
|
||||
(UserManager) getSystemService(Context.USER_SERVICE);
|
||||
if (userManager.isManagedProfile()) {
|
||||
ri.noResourceId = true;
|
||||
}
|
||||
if (ii instanceof LabeledIntent) {
|
||||
LabeledIntent li = (LabeledIntent)ii;
|
||||
ri.resolvePackageName = li.getSourcePackage();
|
||||
ri.labelRes = li.getLabelResource();
|
||||
ri.nonLocalizedLabel = li.getNonLocalizedLabel();
|
||||
ri.icon = li.getIconResource();
|
||||
}
|
||||
mCallerTargets.add(new DisplayResolveInfo(ii, ri,
|
||||
ri.loadLabel(pm), null, ii));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -578,7 +630,7 @@ public class ChooserActivity extends ResolverActivity {
|
||||
}
|
||||
|
||||
@Override
|
||||
public View createView(ViewGroup parent) {
|
||||
public View onCreateView(ViewGroup parent) {
|
||||
return mInflater.inflate(
|
||||
com.android.internal.R.layout.resolve_grid_item, parent, false);
|
||||
}
|
||||
@@ -600,6 +652,41 @@ public class ChooserActivity extends ResolverActivity {
|
||||
return super.getCount() + mServiceTargets.size() + mCallerTargets.size();
|
||||
}
|
||||
|
||||
public int getCallerTargetsCount() {
|
||||
return mCallerTargets.size();
|
||||
}
|
||||
|
||||
public int getServiceTargetsCount() {
|
||||
return mServiceTargets.size();
|
||||
}
|
||||
|
||||
public int getStandardTargetCount() {
|
||||
return super.getCount();
|
||||
}
|
||||
|
||||
public int getPositionTargetType(int position) {
|
||||
int offset = 0;
|
||||
|
||||
final int callerTargetCount = mCallerTargets.size();
|
||||
if (position < callerTargetCount) {
|
||||
return TARGET_CALLER;
|
||||
}
|
||||
offset += callerTargetCount;
|
||||
|
||||
final int serviceTargetCount = mServiceTargets.size();
|
||||
if (position - offset < serviceTargetCount) {
|
||||
return TARGET_SERVICE;
|
||||
}
|
||||
offset += serviceTargetCount;
|
||||
|
||||
final int standardTargetCount = super.getCount();
|
||||
if (position - offset < standardTargetCount) {
|
||||
return TARGET_STANDARD;
|
||||
}
|
||||
|
||||
return TARGET_BAD;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TargetInfo getItem(int position) {
|
||||
int offset = 0;
|
||||
@@ -643,6 +730,133 @@ public class ChooserActivity extends ResolverActivity {
|
||||
}
|
||||
}
|
||||
|
||||
class ChooserRowAdapter extends BaseAdapter {
|
||||
private ChooserListAdapter mChooserListAdapter;
|
||||
private final LayoutInflater mLayoutInflater;
|
||||
private final int mColumnCount = 4;
|
||||
|
||||
public ChooserRowAdapter(ChooserListAdapter wrappedAdapter) {
|
||||
mChooserListAdapter = wrappedAdapter;
|
||||
mLayoutInflater = LayoutInflater.from(ChooserActivity.this);
|
||||
|
||||
wrappedAdapter.registerDataSetObserver(new DataSetObserver() {
|
||||
@Override
|
||||
public void onChanged() {
|
||||
super.onChanged();
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onInvalidated() {
|
||||
super.onInvalidated();
|
||||
notifyDataSetInvalidated();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
return (int) (
|
||||
Math.ceil((float) mChooserListAdapter.getCallerTargetsCount() / mColumnCount)
|
||||
+ Math.ceil((float) mChooserListAdapter.getServiceTargetsCount() / mColumnCount)
|
||||
+ Math.ceil((float) mChooserListAdapter.getStandardTargetCount() / mColumnCount)
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getItem(int position) {
|
||||
// We have nothing useful to return here.
|
||||
return position;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getItemId(int position) {
|
||||
return position;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(int position, View convertView, ViewGroup parent) {
|
||||
final View[] holder;
|
||||
if (convertView == null) {
|
||||
holder = createViewHolder(parent);
|
||||
} else {
|
||||
holder = (View[]) convertView.getTag();
|
||||
}
|
||||
bindViewHolder(position, holder);
|
||||
|
||||
// We keep the actual list item view as the last item in the holder array
|
||||
return holder[mColumnCount];
|
||||
}
|
||||
|
||||
View[] createViewHolder(ViewGroup parent) {
|
||||
final View[] holder = new View[mColumnCount + 1];
|
||||
|
||||
final ViewGroup row = (ViewGroup) mLayoutInflater.inflate(R.layout.chooser_row,
|
||||
parent, false);
|
||||
for (int i = 0; i < mColumnCount; i++) {
|
||||
holder[i] = mChooserListAdapter.createView(row);
|
||||
row.addView(holder[i]);
|
||||
}
|
||||
row.setTag(holder);
|
||||
holder[mColumnCount] = row;
|
||||
return holder;
|
||||
}
|
||||
|
||||
void bindViewHolder(int rowPosition, View[] holder) {
|
||||
final int start = getFirstRowPosition(rowPosition);
|
||||
final int startType = mChooserListAdapter.getPositionTargetType(start);
|
||||
|
||||
int end = start + mColumnCount - 1;
|
||||
while (mChooserListAdapter.getPositionTargetType(end) != startType && end >= start) {
|
||||
end--;
|
||||
}
|
||||
|
||||
final ViewGroup row = (ViewGroup) holder[mColumnCount];
|
||||
|
||||
if (startType == ChooserListAdapter.TARGET_SERVICE) {
|
||||
row.setBackgroundColor(getColor(R.color.chooser_service_row_background_color));
|
||||
} else {
|
||||
row.setBackground(null);
|
||||
}
|
||||
|
||||
for (int i = 0; i < mColumnCount; i++) {
|
||||
final View v = holder[i];
|
||||
if (start + i <= end) {
|
||||
v.setVisibility(View.VISIBLE);
|
||||
final int itemIndex = start + i;
|
||||
mChooserListAdapter.bindView(itemIndex, v);
|
||||
v.setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
startSelected(itemIndex, false, true);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
v.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int getFirstRowPosition(int row) {
|
||||
final int callerCount = mChooserListAdapter.getCallerTargetsCount();
|
||||
final int callerRows = (int) Math.ceil((float) callerCount / mColumnCount);
|
||||
|
||||
if (row < callerRows) {
|
||||
return row * mColumnCount;
|
||||
}
|
||||
|
||||
final int serviceCount = mChooserListAdapter.getServiceTargetsCount();
|
||||
final int serviceRows = (int) Math.ceil((float) serviceCount / mColumnCount);
|
||||
|
||||
if (row < callerRows + serviceRows) {
|
||||
return callerCount + (row - callerRows) * mColumnCount;
|
||||
}
|
||||
|
||||
return callerCount + serviceCount
|
||||
+ (row - callerRows - serviceRows) * mColumnCount;
|
||||
}
|
||||
}
|
||||
|
||||
class ChooserTargetServiceConnection implements ServiceConnection {
|
||||
private final DisplayResolveInfo mOriginalTarget;
|
||||
|
||||
|
||||
@@ -25,7 +25,6 @@ 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;
|
||||
|
||||
@@ -83,7 +82,7 @@ import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
|
||||
* which there is more than one matching activity, allowing the user to decide
|
||||
* which to go to. It is not normally used directly by application developers.
|
||||
*/
|
||||
public class ResolverActivity extends Activity implements AdapterView.OnItemClickListener {
|
||||
public class ResolverActivity extends Activity {
|
||||
private static final String TAG = "ResolverActivity";
|
||||
private static final boolean DEBUG = false;
|
||||
|
||||
@@ -93,8 +92,6 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic
|
||||
private boolean mSafeForwardingMode;
|
||||
private boolean mAlwaysUseOption;
|
||||
private AbsListView mAdapterView;
|
||||
private ListView mListView;
|
||||
private GridView mGridView;
|
||||
private Button mAlwaysButton;
|
||||
private Button mOnceButton;
|
||||
private View mProfileView;
|
||||
@@ -217,6 +214,13 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic
|
||||
} catch (RemoteException e) {
|
||||
mLaunchedFromUid = -1;
|
||||
}
|
||||
|
||||
if (mLaunchedFromUid < 0 || UserHandle.isIsolated(mLaunchedFromUid)) {
|
||||
// Gulp!
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
|
||||
mPm = getPackageManager();
|
||||
mUsm = (UsageStatsManager) getSystemService(Context.USAGE_STATS_SERVICE);
|
||||
|
||||
@@ -229,67 +233,11 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic
|
||||
final ActivityManager am = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
|
||||
mIconDpi = am.getLauncherLargeIconDensity();
|
||||
|
||||
// Add our initial intent as the first item, regardless of what else has already been added.
|
||||
mIntents.add(0, new Intent(intent));
|
||||
mAdapter = createAdapter(this, initialIntents, rList, mLaunchedFromUid, alwaysUseOption);
|
||||
|
||||
final int layoutId;
|
||||
final boolean useHeader;
|
||||
if (mAdapter.hasFilteredItem()) {
|
||||
layoutId = R.layout.resolver_list_with_default;
|
||||
alwaysUseOption = false;
|
||||
useHeader = true;
|
||||
} else {
|
||||
useHeader = false;
|
||||
layoutId = getLayoutResource();
|
||||
}
|
||||
mAlwaysUseOption = alwaysUseOption;
|
||||
configureContentView(mIntents, initialIntents, rList, alwaysUseOption);
|
||||
|
||||
if (mLaunchedFromUid < 0 || UserHandle.isIsolated(mLaunchedFromUid)) {
|
||||
// Gulp!
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
|
||||
int count = mAdapter.mDisplayList.size();
|
||||
if (count > 1 || (count == 1 && mAdapter.getOtherProfile() != null)) {
|
||||
setContentView(layoutId);
|
||||
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) {
|
||||
mAdapterView.setChoiceMode(AbsListView.CHOICE_MODE_SINGLE);
|
||||
}
|
||||
|
||||
if (useHeader && mListView != null) {
|
||||
mListView.addHeaderView(LayoutInflater.from(this).inflate(
|
||||
R.layout.resolver_different_item_header, mListView, false));
|
||||
}
|
||||
} else if (count == 1) {
|
||||
safelyStartActivity(mAdapter.targetInfoForPosition(0, false));
|
||||
mPackageMonitor.unregister();
|
||||
mRegistered = false;
|
||||
finish();
|
||||
return;
|
||||
} else {
|
||||
setContentView(R.layout.resolver_list);
|
||||
|
||||
final TextView empty = (TextView) findViewById(R.id.empty);
|
||||
empty.setVisibility(View.VISIBLE);
|
||||
|
||||
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.
|
||||
getWindow().clearFlags(FLAG_LAYOUT_IN_SCREEN|FLAG_LAYOUT_INSET_DECOR);
|
||||
@@ -548,29 +496,6 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
|
||||
if (mListView != null) {
|
||||
position -= mListView.getHeaderViewsCount();
|
||||
}
|
||||
if (position < 0) {
|
||||
// Header views don't count.
|
||||
return;
|
||||
}
|
||||
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) {
|
||||
mAdapterView.smoothScrollToPosition(checkedPos);
|
||||
}
|
||||
mLastSelected = checkedPos;
|
||||
} else {
|
||||
startSelected(position, false, true);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean hasManagedProfile() {
|
||||
UserManager userManager = (UserManager) getSystemService(Context.USER_SERVICE);
|
||||
if (userManager == null) {
|
||||
@@ -831,14 +756,68 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic
|
||||
startActivity(in);
|
||||
}
|
||||
|
||||
ResolveListAdapter createAdapter(Context context, Intent[] initialIntents,
|
||||
List<ResolveInfo> rList, int launchedFromUid, boolean filterLastUsed) {
|
||||
return new ResolveListAdapter(context, initialIntents, rList, launchedFromUid,
|
||||
filterLastUsed);
|
||||
ResolveListAdapter createAdapter(Context context, List<Intent> payloadIntents,
|
||||
Intent[] initialIntents, List<ResolveInfo> rList, int launchedFromUid,
|
||||
boolean filterLastUsed) {
|
||||
return new ResolveListAdapter(context, payloadIntents, initialIntents, rList,
|
||||
launchedFromUid, filterLastUsed);
|
||||
}
|
||||
|
||||
ResolveListAdapter getAdapter() {
|
||||
return mAdapter;
|
||||
void configureContentView(List<Intent> payloadIntents, Intent[] initialIntents,
|
||||
List<ResolveInfo> rList, boolean alwaysUseOption) {
|
||||
mAdapter = createAdapter(this, payloadIntents, initialIntents, rList,
|
||||
mLaunchedFromUid, alwaysUseOption);
|
||||
|
||||
final int layoutId;
|
||||
if (mAdapter.hasFilteredItem()) {
|
||||
layoutId = R.layout.resolver_list_with_default;
|
||||
alwaysUseOption = false;
|
||||
} else {
|
||||
layoutId = getLayoutResource();
|
||||
}
|
||||
mAlwaysUseOption = alwaysUseOption;
|
||||
|
||||
int count = mAdapter.mDisplayList.size();
|
||||
if (count > 1 || (count == 1 && mAdapter.getOtherProfile() != null)) {
|
||||
setContentView(layoutId);
|
||||
mAdapterView = (AbsListView) findViewById(R.id.resolver_list);
|
||||
onPrepareAdapterView(mAdapterView, mAdapter, alwaysUseOption);
|
||||
} else if (count == 1) {
|
||||
safelyStartActivity(mAdapter.targetInfoForPosition(0, false));
|
||||
mPackageMonitor.unregister();
|
||||
mRegistered = false;
|
||||
finish();
|
||||
return;
|
||||
} else {
|
||||
setContentView(R.layout.resolver_list);
|
||||
|
||||
final TextView empty = (TextView) findViewById(R.id.empty);
|
||||
empty.setVisibility(View.VISIBLE);
|
||||
|
||||
mAdapterView = (AbsListView) findViewById(R.id.resolver_list);
|
||||
mAdapterView.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
|
||||
void onPrepareAdapterView(AbsListView adapterView, ResolveListAdapter adapter,
|
||||
boolean alwaysUseOption) {
|
||||
final boolean useHeader = adapter.hasFilteredItem();
|
||||
final ListView listView = adapterView instanceof ListView ? (ListView) adapterView : null;
|
||||
|
||||
adapterView.setAdapter(mAdapter);
|
||||
|
||||
final ItemClickListener listener = new ItemClickListener();
|
||||
adapterView.setOnItemClickListener(listener);
|
||||
adapterView.setOnItemLongClickListener(listener);
|
||||
|
||||
if (alwaysUseOption) {
|
||||
listView.setChoiceMode(AbsListView.CHOICE_MODE_SINGLE);
|
||||
}
|
||||
|
||||
if (useHeader && listView != null) {
|
||||
listView.addHeaderView(LayoutInflater.from(this).inflate(
|
||||
R.layout.resolver_different_item_header, listView, false));
|
||||
}
|
||||
}
|
||||
|
||||
final class DisplayResolveInfo implements TargetInfo {
|
||||
@@ -888,6 +867,10 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic
|
||||
return mDisplayIcon;
|
||||
}
|
||||
|
||||
public Drawable getBadgeIcon() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TargetInfo cloneFilledIn(Intent fillInIntent, int flags) {
|
||||
return new DisplayResolveInfo(this, fillInIntent, flags);
|
||||
@@ -1023,6 +1006,11 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic
|
||||
*/
|
||||
public Drawable getDisplayIcon();
|
||||
|
||||
/**
|
||||
* @return The (small) icon to badge the target with
|
||||
*/
|
||||
public Drawable getBadgeIcon();
|
||||
|
||||
/**
|
||||
* Clone this target with the given fill-in information.
|
||||
*/
|
||||
@@ -1035,6 +1023,7 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic
|
||||
}
|
||||
|
||||
class ResolveListAdapter extends BaseAdapter {
|
||||
private final List<Intent> mIntents;
|
||||
private final Intent[] mInitialIntents;
|
||||
private final List<ResolveInfo> mBaseResolveList;
|
||||
private ResolveInfo mLastChosen;
|
||||
@@ -1050,8 +1039,10 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic
|
||||
private int mLastChosenPosition = -1;
|
||||
private boolean mFilterLastUsed;
|
||||
|
||||
public ResolveListAdapter(Context context, Intent[] initialIntents,
|
||||
List<ResolveInfo> rList, int launchedFromUid, boolean filterLastUsed) {
|
||||
public ResolveListAdapter(Context context, List<Intent> payloadIntents,
|
||||
Intent[] initialIntents, List<ResolveInfo> rList, int launchedFromUid,
|
||||
boolean filterLastUsed) {
|
||||
mIntents = payloadIntents;
|
||||
mInitialIntents = initialIntents;
|
||||
mBaseResolveList = rList;
|
||||
mLaunchedFromUid = launchedFromUid;
|
||||
@@ -1430,15 +1421,19 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic
|
||||
View view = convertView;
|
||||
if (view == null) {
|
||||
view = createView(parent);
|
||||
|
||||
final ViewHolder holder = new ViewHolder(view);
|
||||
view.setTag(holder);
|
||||
}
|
||||
bindView(view, getItem(position));
|
||||
onBindView(view, getItem(position));
|
||||
return view;
|
||||
}
|
||||
|
||||
public View createView(ViewGroup parent) {
|
||||
public final View createView(ViewGroup parent) {
|
||||
final View view = onCreateView(parent);
|
||||
final ViewHolder holder = new ViewHolder(view);
|
||||
view.setTag(holder);
|
||||
return view;
|
||||
}
|
||||
|
||||
public View onCreateView(ViewGroup parent) {
|
||||
return mInflater.inflate(
|
||||
com.android.internal.R.layout.resolve_list_item, parent, false);
|
||||
}
|
||||
@@ -1447,7 +1442,11 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic
|
||||
return !TextUtils.isEmpty(info.getExtendedInfo());
|
||||
}
|
||||
|
||||
private final void bindView(View view, TargetInfo info) {
|
||||
public final void bindView(int position, View view) {
|
||||
onBindView(view, getItem(position));
|
||||
}
|
||||
|
||||
private void onBindView(View view, TargetInfo info) {
|
||||
final ViewHolder holder = (ViewHolder) view.getTag();
|
||||
holder.text.setText(info.getDisplayLabel());
|
||||
if (showsExtendedInfo(info)) {
|
||||
@@ -1461,6 +1460,15 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic
|
||||
new LoadAdapterIconTask((DisplayResolveInfo) info).execute();
|
||||
}
|
||||
holder.icon.setImageDrawable(info.getDisplayIcon());
|
||||
if (holder.badge != null) {
|
||||
final Drawable badge = info.getBadgeIcon();
|
||||
if (badge != null) {
|
||||
holder.badge.setImageDrawable(badge);
|
||||
holder.badge.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
holder.badge.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1514,20 +1522,47 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic
|
||||
public TextView text;
|
||||
public TextView text2;
|
||||
public ImageView icon;
|
||||
public ImageView badge;
|
||||
|
||||
public ViewHolder(View view) {
|
||||
text = (TextView) view.findViewById(com.android.internal.R.id.text1);
|
||||
text2 = (TextView) view.findViewById(com.android.internal.R.id.text2);
|
||||
icon = (ImageView) view.findViewById(R.id.icon);
|
||||
badge = (ImageView) view.findViewById(R.id.target_badge);
|
||||
}
|
||||
}
|
||||
|
||||
class ItemLongClickListener implements AdapterView.OnItemLongClickListener {
|
||||
class ItemClickListener implements AdapterView.OnItemClickListener,
|
||||
AdapterView.OnItemLongClickListener {
|
||||
@Override
|
||||
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
|
||||
final ListView listView = parent instanceof ListView ? (ListView) parent : null;
|
||||
if (listView != null) {
|
||||
position -= listView.getHeaderViewsCount();
|
||||
}
|
||||
if (position < 0) {
|
||||
// Header views don't count.
|
||||
return;
|
||||
}
|
||||
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) {
|
||||
mAdapterView.smoothScrollToPosition(checkedPos);
|
||||
}
|
||||
mLastSelected = checkedPos;
|
||||
} else {
|
||||
startSelected(position, false, true);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
|
||||
if (mListView != null) {
|
||||
position -= mListView.getHeaderViewsCount();
|
||||
final ListView listView = parent instanceof ListView ? (ListView) parent : null;
|
||||
if (listView != null) {
|
||||
position -= listView.getHeaderViewsCount();
|
||||
}
|
||||
if (position < 0) {
|
||||
// Header views don't count.
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:maxWidth="@dimen/resolver_max_width"
|
||||
android:maxCollapsedHeight="256dp"
|
||||
android:maxCollapsedHeight="288dp"
|
||||
android:maxCollapsedHeightSmall="56dp"
|
||||
android:id="@id/contentPanel">
|
||||
|
||||
@@ -30,24 +30,25 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alwaysShow="true"
|
||||
android:elevation="8dp"
|
||||
android:paddingStart="?attr/dialogPreferredPadding"
|
||||
android:paddingStart="16dp"
|
||||
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:visibility="gone"
|
||||
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:textSize="14sp"
|
||||
android:gravity="start|center_vertical"
|
||||
android:paddingEnd="?attr/dialogPreferredPadding"
|
||||
android:paddingTop="8dp"
|
||||
android:paddingBottom="8dp" />
|
||||
android:paddingTop="12dp"
|
||||
android:paddingBottom="12dp" />
|
||||
<LinearLayout android:id="@+id/profile_button"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="48dp"
|
||||
@@ -82,23 +83,24 @@
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
<GridView
|
||||
<ListView
|
||||
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:listSelector="@color/transparent"
|
||||
android:divider="@null"
|
||||
android:scrollIndicators="top"
|
||||
android:nestedScrollingEnabled="true" />
|
||||
|
||||
<TextView android:id="@+id/empty"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alwaysShow="true"
|
||||
android:background="@color/white"
|
||||
android:text="@string/noApplications"
|
||||
android:padding="32dp"
|
||||
android:gravity="center"
|
||||
|
||||
31
core/res/res/layout/chooser_row.xml
Normal file
31
core/res/res/layout/chooser_row.xml
Normal file
@@ -0,0 +1,31 @@
|
||||
<?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.
|
||||
*/
|
||||
-->
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="match_parent" android:layout_height="wrap_content"
|
||||
android:minHeight="80dp"
|
||||
android:gravity="start|top"
|
||||
android:paddingTop="8dp"
|
||||
android:paddingBottom="8dp"
|
||||
android:paddingStart="@dimen/chooser_grid_padding"
|
||||
android:paddingEnd="@dimen/chooser_grid_padding"
|
||||
android:weightSum="4">
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
@@ -18,18 +18,31 @@
|
||||
-->
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent" android:layout_height="wrap_content"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:minWidth="80dp"
|
||||
android:gravity="center"
|
||||
android:paddingTop="8dp"
|
||||
android:paddingBottom="8dp"
|
||||
android:background="?attr/activatedBackgroundIndicator">
|
||||
android:background="?attr/selectableItemBackgroundBorderless">
|
||||
|
||||
<!-- Activity icon when presenting dialog -->
|
||||
<ImageView android:id="@+id/icon"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="48dp"
|
||||
android:scaleType="fitCenter" />
|
||||
<FrameLayout android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content">
|
||||
<ImageView android:id="@+id/icon"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="48dp"
|
||||
android:layout_marginLeft="3dp"
|
||||
android:layout_marginRight="3dp"
|
||||
android:layout_marginBottom="3dp"
|
||||
android:scaleType="fitCenter" />
|
||||
<ImageView android:id="@+id/target_badge"
|
||||
android:layout_width="16dp"
|
||||
android:layout_height="16dp"
|
||||
android:layout_gravity="end|bottom"
|
||||
android:visibility="gone"
|
||||
android:scaleType="fitCenter" />
|
||||
</FrameLayout>
|
||||
|
||||
<!-- Activity name -->
|
||||
<TextView android:id="@android:id/text1"
|
||||
@@ -40,21 +53,23 @@
|
||||
android:layout_marginRight="4dp"
|
||||
android:textAppearance="?attr/textAppearanceSmall"
|
||||
android:textColor="?attr/textColorPrimary"
|
||||
android:textSize="12sp"
|
||||
android:fontFamily="sans-serif-condensed"
|
||||
android:gravity="center"
|
||||
android:gravity="top|center_horizontal"
|
||||
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:textSize="12sp"
|
||||
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:gravity="top|center_horizontal"
|
||||
android:ellipsize="marquee" />
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
@@ -174,4 +174,6 @@
|
||||
<color name="Pink_800">#ffad1457</color>
|
||||
<color name="Red_700">#ffc53929</color>
|
||||
<color name="Red_800">#ffb93221</color>
|
||||
|
||||
<color name="chooser_service_row_background_color">#fff5f5f5</color>
|
||||
</resources>
|
||||
|
||||
@@ -2257,4 +2257,8 @@
|
||||
<java-symbol type="id" name="day_picker_view_pager" />
|
||||
<java-symbol type="layout" name="day_picker_content_material" />
|
||||
<java-symbol type="drawable" name="scroll_indicator_material" />
|
||||
|
||||
<java-symbol type="layout" name="chooser_row" />
|
||||
<java-symbol type="color" name="chooser_service_row_background_color" />
|
||||
<java-symbol type="id" name="target_badge" />
|
||||
</resources>
|
||||
|
||||
Reference in New Issue
Block a user