Merge "Push chooser targets to the shortcut manager."
This commit is contained in:
committed by
Android (Google) Code Review
commit
1058a3dd95
@@ -55,7 +55,8 @@ interface ILauncherApps {
|
||||
String callingPackage, String packageName, int flags, in UserHandle user);
|
||||
|
||||
ParceledListSlice getShortcuts(String callingPackage, long changedSince, String packageName,
|
||||
in List shortcutIds, in ComponentName componentName, int flags, in UserHandle user);
|
||||
in List shortcutIds, in ComponentName componentName, in Intent intent, int flags,
|
||||
in UserHandle user);
|
||||
void pinShortcuts(String callingPackage, String packageName, in List<String> shortcutIds,
|
||||
in UserHandle user);
|
||||
boolean startShortcut(String callingPackage, String packageName, String id,
|
||||
|
||||
@@ -275,7 +275,18 @@ public class LauncherApps {
|
||||
@Deprecated
|
||||
public static final int FLAG_GET_MANIFEST = FLAG_MATCH_MANIFEST;
|
||||
|
||||
/** @hide */
|
||||
/**
|
||||
* Include chooser shortcuts in the result.
|
||||
* STOPSHIP TODO: Unless explicitly requesting chooser fields, we should strip out chooser
|
||||
* relevant fields from the Shortcut. This should also be adequately documented.
|
||||
*/
|
||||
public static final int FLAG_MATCH_CHOOSER = 1 << 4;
|
||||
|
||||
/**
|
||||
* Does not retrieve CHOOSER only shortcuts.
|
||||
* TODO: Add another flag for MATCH_ALL_PINNED
|
||||
* @hide
|
||||
*/
|
||||
public static final int FLAG_MATCH_ALL_KINDS =
|
||||
FLAG_GET_DYNAMIC | FLAG_GET_PINNED | FLAG_GET_MANIFEST;
|
||||
|
||||
@@ -308,6 +319,7 @@ public class LauncherApps {
|
||||
FLAG_MATCH_DYNAMIC,
|
||||
FLAG_MATCH_PINNED,
|
||||
FLAG_MATCH_MANIFEST,
|
||||
FLAG_MATCH_CHOOSER,
|
||||
FLAG_GET_KEY_FIELDS_ONLY,
|
||||
})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@@ -324,6 +336,9 @@ public class LauncherApps {
|
||||
@Nullable
|
||||
ComponentName mActivity;
|
||||
|
||||
@Nullable
|
||||
Intent mIntent;
|
||||
|
||||
@QueryFlags
|
||||
int mQueryFlags;
|
||||
|
||||
@@ -367,6 +382,14 @@ public class LauncherApps {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* If non-null, returns only shortcuts with intent filters that match this intent.
|
||||
*/
|
||||
public ShortcutQuery setIntent(@Nullable Intent intent) {
|
||||
mIntent = intent;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set query options. At least one of the {@code MATCH} flags should be set. Otherwise,
|
||||
* no shortcuts will be returned.
|
||||
@@ -681,7 +704,7 @@ public class LauncherApps {
|
||||
try {
|
||||
return mService.getShortcuts(mContext.getPackageName(),
|
||||
query.mChangedSince, query.mPackage, query.mShortcutIds, query.mActivity,
|
||||
query.mQueryFlags, user)
|
||||
query.mIntent, query.mQueryFlags, user)
|
||||
.getList();
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
|
||||
@@ -21,8 +21,10 @@ import android.annotation.Nullable;
|
||||
import android.annotation.UserIdInt;
|
||||
import android.app.TaskStackBuilder;
|
||||
import android.content.ComponentName;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.pm.LauncherApps.ShortcutQuery;
|
||||
import android.content.res.Resources;
|
||||
import android.content.res.Resources.NotFoundException;
|
||||
@@ -38,10 +40,12 @@ import android.util.ArraySet;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.internal.util.MemInfoReader;
|
||||
import com.android.internal.util.Preconditions;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
@@ -95,6 +99,14 @@ public final class ShortcutInfo implements Parcelable {
|
||||
public static final int FLAG_MASKABLE_BITMAP = 1 << 9;
|
||||
|
||||
/** @hide */
|
||||
public static final int FLAG_CHOOSER = 1 << 10;
|
||||
|
||||
/**
|
||||
* TODO: Add FLAG_CHOOSER_INFO_OMITTED to reflect that chooser info was omitted in the Shortcut
|
||||
* due to the context in which it was retrieved.
|
||||
* TODO: Add a FLAG_LAUNCHABLE to reflect whether or not the Shortcut has a launchable intent
|
||||
* @hide
|
||||
*/
|
||||
@IntDef(flag = true,
|
||||
value = {
|
||||
FLAG_DYNAMIC,
|
||||
@@ -107,6 +119,7 @@ public final class ShortcutInfo implements Parcelable {
|
||||
FLAG_STRINGS_RESOLVED,
|
||||
FLAG_IMMUTABLE,
|
||||
FLAG_MASKABLE_BITMAP,
|
||||
FLAG_CHOOSER,
|
||||
})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface ShortcutFlags {}
|
||||
@@ -201,6 +214,24 @@ public final class ShortcutInfo implements Parcelable {
|
||||
@Nullable
|
||||
private PersistableBundle[] mIntentPersistableExtrases;
|
||||
|
||||
/**
|
||||
* If used in a chooser, extras that should be added into the intent passed through.
|
||||
*/
|
||||
@Nullable
|
||||
private PersistableBundle mChooserExtras;
|
||||
|
||||
/**
|
||||
* Intent filters to be used if the shortcut is to be used in a chooser context.
|
||||
*/
|
||||
@Nullable
|
||||
private IntentFilter[] mChooserIntentFilters;
|
||||
|
||||
/**
|
||||
* Component names corresponding to the above intent filters.
|
||||
*/
|
||||
@Nullable
|
||||
private ComponentName[] mChooserComponentNames;
|
||||
|
||||
private int mRank;
|
||||
|
||||
/**
|
||||
@@ -250,6 +281,13 @@ public final class ShortcutInfo implements Parcelable {
|
||||
mDisabledMessageResId = b.mDisabledMessageResId;
|
||||
mCategories = cloneCategories(b.mCategories);
|
||||
mIntents = cloneIntents(b.mIntents);
|
||||
if (b.mChooserIntentFilters != null) {
|
||||
mChooserIntentFilters = b.mChooserIntentFilters.toArray(new IntentFilter[0]);
|
||||
}
|
||||
if (b.mChooserComponentNames != null) {
|
||||
mChooserComponentNames = b.mChooserComponentNames.toArray(new ComponentName[0]);
|
||||
}
|
||||
mChooserExtras = b.mChooserExtras;
|
||||
fixUpIntentExtras();
|
||||
mRank = b.mRank;
|
||||
mExtras = b.mExtras;
|
||||
@@ -330,8 +368,28 @@ public final class ShortcutInfo implements Parcelable {
|
||||
if (mTitle == null && mTitleResId == 0) {
|
||||
throw new IllegalArgumentException("Short label must be provided");
|
||||
}
|
||||
Preconditions.checkNotNull(mIntents, "Shortcut Intent must be provided");
|
||||
Preconditions.checkArgument(mIntents.length > 0, "Shortcut Intent must be provided");
|
||||
|
||||
// For a shortcut to be valid, there should either be an Intent, or a non-empty set of
|
||||
// intent filters.
|
||||
if (mIntents == null || mIntents.length == 0) {
|
||||
Preconditions.checkNotNull(mChooserIntentFilters,
|
||||
"Intent must be provided if not a chooser target");
|
||||
Preconditions.checkNotNull(mChooserComponentNames,
|
||||
"Intent must be provided if not a chooser target");
|
||||
}
|
||||
|
||||
// If ChooserIntentFilter are provided, they should match the length of the provided
|
||||
// component names.
|
||||
if (mChooserIntentFilters != null) {
|
||||
if (mChooserComponentNames == null
|
||||
|| mChooserIntentFilters.length != mChooserComponentNames.length) {
|
||||
throw new IllegalArgumentException("Inconsistent intent filters and "
|
||||
+ "component names given");
|
||||
}
|
||||
if (mChooserIntentFilters.length == 0 || mChooserComponentNames.length == 0) {
|
||||
throw new IllegalArgumentException("Empty intent filter and component names given");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -376,6 +434,10 @@ public final class ShortcutInfo implements Parcelable {
|
||||
mDisabledMessageResName = source.mDisabledMessageResName;
|
||||
mIconResName = source.mIconResName;
|
||||
}
|
||||
// TODO: Omit these by default and add a new clone flag.
|
||||
mChooserIntentFilters = source.mChooserIntentFilters;
|
||||
mChooserComponentNames = source.mChooserComponentNames;
|
||||
mChooserExtras = source.mChooserExtras;
|
||||
} else {
|
||||
// Set this bit.
|
||||
mFlags |= FLAG_KEY_FIELDS_ONLY;
|
||||
@@ -502,6 +564,25 @@ public final class ShortcutInfo implements Parcelable {
|
||||
return fullResourceName.substring(p1 + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the shortcut has any intentFilter matching the passed in one.
|
||||
* @hide
|
||||
*/
|
||||
@VisibleForTesting
|
||||
public boolean hasMatchingFilter(ContentResolver resolver, Intent intent) {
|
||||
if (mChooserIntentFilters == null) {
|
||||
return false;
|
||||
}
|
||||
for (IntentFilter filter : mChooserIntentFilters) {
|
||||
int match = filter.match(resolver, intent, false, TAG);
|
||||
if (match > 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Extract the entry name from a fully-donated resource name.
|
||||
* e.g. "com.android.app1:drawable/icon1" -> "icon1"
|
||||
@@ -685,6 +766,15 @@ public final class ShortcutInfo implements Parcelable {
|
||||
if (source.mExtras != null) {
|
||||
mExtras = source.mExtras;
|
||||
}
|
||||
if (source.mChooserExtras != null) {
|
||||
mChooserExtras = source.mChooserExtras;
|
||||
}
|
||||
if (source.mChooserIntentFilters != null) {
|
||||
mChooserIntentFilters = source.mChooserIntentFilters;
|
||||
}
|
||||
if (source.mChooserComponentNames != null) {
|
||||
mChooserComponentNames = source.mChooserComponentNames;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -746,6 +836,12 @@ public final class ShortcutInfo implements Parcelable {
|
||||
|
||||
private PersistableBundle mExtras;
|
||||
|
||||
private PersistableBundle mChooserExtras;
|
||||
|
||||
private List<IntentFilter> mChooserIntentFilters;
|
||||
|
||||
private List<ComponentName> mChooserComponentNames;
|
||||
|
||||
/**
|
||||
* Old style constructor.
|
||||
* @hide
|
||||
@@ -1031,6 +1127,40 @@ public final class ShortcutInfo implements Parcelable {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extras that can be added which will be added to the Intent used to launch the app if
|
||||
* launched from a chooser context.
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setChooserExtras(@NonNull PersistableBundle extras) {
|
||||
mChooserExtras = extras;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* IntentFilters and the components that should resolve a match for a given chooser target.
|
||||
* If multiple matches are found, the component corresponding to the closest match will be
|
||||
* used.
|
||||
*
|
||||
* @param filter IntendFilter that if matched will have the intent forwarded to the given
|
||||
* component
|
||||
* @param name The component that an intent that passes this filter will resolve to.
|
||||
*/
|
||||
public Builder addChooserIntentFilter(@NonNull IntentFilter filter,
|
||||
@NonNull ComponentName name) {
|
||||
Preconditions.checkNotNull(filter, "intent filter cannot be null");
|
||||
Preconditions.checkNotNull(name, "component name cannot be null");
|
||||
|
||||
if (mChooserIntentFilters == null || mChooserComponentNames == null) {
|
||||
mChooserIntentFilters = new ArrayList<>();
|
||||
mChooserComponentNames = new ArrayList<>();
|
||||
}
|
||||
|
||||
mChooserIntentFilters.add(filter);
|
||||
mChooserComponentNames.add(name);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link ShortcutInfo} instance.
|
||||
*/
|
||||
@@ -1231,6 +1361,30 @@ public final class ShortcutInfo implements Parcelable {
|
||||
return mIntentPersistableExtrases;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the extras that will be added in to any intent launched through the chooser.
|
||||
*/
|
||||
@NonNull
|
||||
public PersistableBundle getChooserExtras() {
|
||||
return mChooserExtras;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the list of intent filters for chooser targets.
|
||||
*/
|
||||
@NonNull
|
||||
public IntentFilter[] getChooserIntentFilters() {
|
||||
return mChooserIntentFilters;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the list of component names corresponding to the above intent filters.
|
||||
*/
|
||||
@NonNull
|
||||
public ComponentName[] getChooserComponentNames() {
|
||||
return mChooserComponentNames;
|
||||
}
|
||||
|
||||
/**
|
||||
* "Rank" of a shortcut, which is a non-negative, sequential value that's unique for each
|
||||
* {@link #getActivity} for each of the two types of shortcuts (static and dynamic).
|
||||
@@ -1352,6 +1506,11 @@ public final class ShortcutInfo implements Parcelable {
|
||||
return hasFlags(FLAG_PINNED);
|
||||
}
|
||||
|
||||
/** Return whether a shortcut can be shown in the chooser. */
|
||||
public boolean isChooser() {
|
||||
return hasFlags(FLAG_CHOOSER);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether a shortcut is static; that is, whether a shortcut is
|
||||
* published from AndroidManifest.xml. If {@code true}, the shortcut is
|
||||
@@ -1380,6 +1539,14 @@ public final class ShortcutInfo implements Parcelable {
|
||||
return isPinned() && !(isDynamic() || isManifestShortcut());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if pinned but neither static nor dynamic.
|
||||
* @hide
|
||||
*/
|
||||
public boolean isDynamicOrChooser() {
|
||||
return hasFlags(FLAG_DYNAMIC) || hasFlags(FLAG_CHOOSER);
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public boolean isOriginallyFromManifest() {
|
||||
return hasFlags(FLAG_IMMUTABLE);
|
||||
@@ -1661,6 +1828,19 @@ public final class ShortcutInfo implements Parcelable {
|
||||
mCategories.add(source.readString().intern());
|
||||
}
|
||||
}
|
||||
|
||||
// We put a placeholder empty array in to keep the parcelable order, but can do away with
|
||||
// them at this point if they're empty.
|
||||
mChooserComponentNames = source.readParcelableArray(cl, ComponentName.class);
|
||||
if (mChooserComponentNames.length == 0) {
|
||||
mChooserComponentNames = null;
|
||||
}
|
||||
|
||||
mChooserIntentFilters = source.readParcelableArray(cl, IntentFilter.class);
|
||||
if (mChooserIntentFilters.length == 0) {
|
||||
mChooserIntentFilters = null;
|
||||
}
|
||||
mChooserExtras = source.readPersistableBundle(cl);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1707,6 +1887,17 @@ public final class ShortcutInfo implements Parcelable {
|
||||
} else {
|
||||
dest.writeInt(0);
|
||||
}
|
||||
if (mChooserComponentNames != null) {
|
||||
dest.writeParcelableArray(mChooserComponentNames, flags);
|
||||
} else {
|
||||
dest.writeParcelableArray(new ComponentName[0], flags);
|
||||
}
|
||||
if (mChooserIntentFilters != null) {
|
||||
dest.writeParcelableArray(mChooserIntentFilters, flags);
|
||||
} else {
|
||||
dest.writeParcelableArray(new IntentFilter[0], flags);
|
||||
}
|
||||
dest.writePersistableBundle(mChooserExtras);
|
||||
}
|
||||
|
||||
public static final Creator<ShortcutInfo> CREATOR =
|
||||
|
||||
@@ -44,8 +44,8 @@ public abstract class ShortcutServiceInternal {
|
||||
getShortcuts(int launcherUserId,
|
||||
@NonNull String callingPackage, long changedSince,
|
||||
@Nullable String packageName, @Nullable List<String> shortcutIds,
|
||||
@Nullable ComponentName componentName, @ShortcutQuery.QueryFlags int flags,
|
||||
int userId);
|
||||
@Nullable ComponentName componentName, @Nullable Intent intent,
|
||||
@ShortcutQuery.QueryFlags int flags, int userId);
|
||||
|
||||
public abstract boolean
|
||||
isPinnedByCaller(int launcherUserId, @NonNull String callingPackage,
|
||||
|
||||
Reference in New Issue
Block a user