Merge "Push chooser targets to the shortcut manager."

This commit is contained in:
TreeHugger Robot
2017-02-27 20:24:52 +00:00
committed by Android (Google) Code Review
17 changed files with 824 additions and 127 deletions

View File

@@ -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,

View File

@@ -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();

View File

@@ -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 =

View File

@@ -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,