ShortcutManager: API changes for DR

See https://goto.google.com/shortcutmanager-spec-dr for
the details.

This CL contains changes to ShortcutInfo and all the new API
entry points, but not the implementation of the new APIs.

- ShortcutInfo.activityComponent is now mandatory.
- Publishers can now disable shortcuts.  ShortcutInfo can now have
"disabled message".
- ShortcutInfo now supports string resources for all the String
fields.
  -> When launcher fetches shortcuts, ShortcutService will
  automatically load resources and expose as strings.
- LauncherApps now supports getShortcutIconDrawable() and
getShortcutBadgedIconDrawable() to be consistent with
LauncherActivityInfo.

- ShortcutInfo.weight is replaced with "rank".

- Added ShortcutManager.reportShortcutUsed(), which will be used for
usage tracking / suggestion.

Bug 28536054
Bug 28536066
Bug 28564134
Bug 28594168

Change-Id: Ib8245b39bb1e753991a9de89c0b73accacd90355
This commit is contained in:
Makoto Onuki
2016-05-11 16:51:01 -07:00
parent f4e2832742
commit 20c95f854e
11 changed files with 973 additions and 71 deletions

View File

@@ -9502,6 +9502,8 @@ package android.content.pm {
public class LauncherApps {
method public java.util.List<android.content.pm.LauncherActivityInfo> getActivityList(java.lang.String, android.os.UserHandle);
method public android.graphics.drawable.Drawable getShortcutBadgedIconDrawable(int);
method public android.graphics.drawable.Drawable getShortcutIconDrawable(int);
method public android.os.ParcelFileDescriptor getShortcutIconFd(android.content.pm.ShortcutInfo);
method public android.os.ParcelFileDescriptor getShortcutIconFd(java.lang.String, java.lang.String, android.os.UserHandle);
method public java.util.List<android.content.pm.ShortcutInfo> getShortcuts(android.content.pm.LauncherApps.ShortcutQuery, android.os.UserHandle);
@@ -10045,31 +10047,41 @@ package android.content.pm {
method public int describeContents();
method public android.content.ComponentName getActivityComponent();
method public java.util.Set<java.lang.String> getCategories();
method public java.lang.String getDisabledMessage();
method public int getDisabledMessageResId();
method public android.os.PersistableBundle getExtras();
method public int getIconResourceId();
method public java.lang.String getId();
method public android.content.Intent getIntent();
method public long getLastChangedTimestamp();
method public java.lang.String getPackageName();
method public int getRank();
method public java.lang.String getText();
method public int getTextResId();
method public java.lang.String getTitle();
method public int getTitleResId();
method public android.os.UserHandle getUserHandle();
method public int getWeight();
method public boolean hasIconFile();
method public boolean hasIconResource();
method public boolean hasKeyFieldsOnly();
method public boolean hasStringResourcesResolved();
method public boolean isDisabled();
method public boolean isDynamic();
method public boolean isFromManifest();
method public boolean isPinned();
method public void writeToParcel(android.os.Parcel, int);
field public static final int CLONE_REMOVE_FOR_CREATOR = 1; // 0x1
field public static final int CLONE_REMOVE_FOR_LAUNCHER = 3; // 0x3
field public static final int CLONE_REMOVE_NON_KEY_INFO = 4; // 0x4
field public static final android.os.Parcelable.Creator<android.content.pm.ShortcutInfo> CREATOR;
field public static final int FLAG_DISABLED = 64; // 0x40
field public static final int FLAG_DYNAMIC = 1; // 0x1
field public static final int FLAG_FROM_MANIFEST = 32; // 0x20
field public static final int FLAG_HAS_ICON_FILE = 8; // 0x8
field public static final int FLAG_HAS_ICON_RES = 4; // 0x4
field public static final int FLAG_KEY_FIELDS_ONLY = 16; // 0x10
field public static final int FLAG_PINNED = 2; // 0x2
field public static final int FLAG_STRINGS_RESOLVED = 128; // 0x80
field public static final java.lang.String SHORTCUT_CATEGORY_CONVERSATION = "android.shortcut.conversation";
}
@@ -10078,17 +10090,24 @@ package android.content.pm {
method public android.content.pm.ShortcutInfo build();
method public android.content.pm.ShortcutInfo.Builder setActivityComponent(android.content.ComponentName);
method public android.content.pm.ShortcutInfo.Builder setCategories(java.util.Set<java.lang.String>);
method public android.content.pm.ShortcutInfo.Builder setDisabledMessage(java.lang.String);
method public android.content.pm.ShortcutInfo.Builder setDisabledMessageResId(int);
method public android.content.pm.ShortcutInfo.Builder setExtras(android.os.PersistableBundle);
method public android.content.pm.ShortcutInfo.Builder setIcon(android.graphics.drawable.Icon);
method public android.content.pm.ShortcutInfo.Builder setId(java.lang.String);
method public android.content.pm.ShortcutInfo.Builder setIntent(android.content.Intent);
method public android.content.pm.ShortcutInfo.Builder setRank(int);
method public android.content.pm.ShortcutInfo.Builder setText(java.lang.String);
method public android.content.pm.ShortcutInfo.Builder setTextResId(int);
method public android.content.pm.ShortcutInfo.Builder setTitle(java.lang.String);
method public android.content.pm.ShortcutInfo.Builder setWeight(int);
method public android.content.pm.ShortcutInfo.Builder setTitleResId(int);
}
public class ShortcutManager {
method public boolean addDynamicShortcuts(java.util.List<android.content.pm.ShortcutInfo>);
method public void disableShortcuts(java.util.List<java.lang.String>);
method public void disableShortcuts(java.util.List<java.lang.String>, int);
method public void disableShortcuts(java.util.List<java.lang.String>, java.lang.String);
method public java.util.List<android.content.pm.ShortcutInfo> getDynamicShortcuts();
method public int getIconMaxDimensions();
method public int getMaxDynamicShortcutCount();
@@ -10097,6 +10116,7 @@ package android.content.pm {
method public int getRemainingCallCount();
method public void removeAllDynamicShortcuts();
method public void removeDynamicShortcuts(java.util.List<java.lang.String>);
method public void reportShortcutUsed(java.lang.String);
method public boolean setDynamicShortcuts(java.util.List<android.content.pm.ShortcutInfo>);
method public boolean updateShortcuts(java.util.List<android.content.pm.ShortcutInfo>);
}

View File

@@ -9859,6 +9859,8 @@ package android.content.pm {
public class LauncherApps {
method public java.util.List<android.content.pm.LauncherActivityInfo> getActivityList(java.lang.String, android.os.UserHandle);
method public android.graphics.drawable.Drawable getShortcutBadgedIconDrawable(int);
method public android.graphics.drawable.Drawable getShortcutIconDrawable(int);
method public android.os.ParcelFileDescriptor getShortcutIconFd(android.content.pm.ShortcutInfo);
method public android.os.ParcelFileDescriptor getShortcutIconFd(java.lang.String, java.lang.String, android.os.UserHandle);
method public java.util.List<android.content.pm.ShortcutInfo> getShortcuts(android.content.pm.LauncherApps.ShortcutQuery, android.os.UserHandle);
@@ -10472,31 +10474,41 @@ package android.content.pm {
method public int describeContents();
method public android.content.ComponentName getActivityComponent();
method public java.util.Set<java.lang.String> getCategories();
method public java.lang.String getDisabledMessage();
method public int getDisabledMessageResId();
method public android.os.PersistableBundle getExtras();
method public int getIconResourceId();
method public java.lang.String getId();
method public android.content.Intent getIntent();
method public long getLastChangedTimestamp();
method public java.lang.String getPackageName();
method public int getRank();
method public java.lang.String getText();
method public int getTextResId();
method public java.lang.String getTitle();
method public int getTitleResId();
method public android.os.UserHandle getUserHandle();
method public int getWeight();
method public boolean hasIconFile();
method public boolean hasIconResource();
method public boolean hasKeyFieldsOnly();
method public boolean hasStringResourcesResolved();
method public boolean isDisabled();
method public boolean isDynamic();
method public boolean isFromManifest();
method public boolean isPinned();
method public void writeToParcel(android.os.Parcel, int);
field public static final int CLONE_REMOVE_FOR_CREATOR = 1; // 0x1
field public static final int CLONE_REMOVE_FOR_LAUNCHER = 3; // 0x3
field public static final int CLONE_REMOVE_NON_KEY_INFO = 4; // 0x4
field public static final android.os.Parcelable.Creator<android.content.pm.ShortcutInfo> CREATOR;
field public static final int FLAG_DISABLED = 64; // 0x40
field public static final int FLAG_DYNAMIC = 1; // 0x1
field public static final int FLAG_FROM_MANIFEST = 32; // 0x20
field public static final int FLAG_HAS_ICON_FILE = 8; // 0x8
field public static final int FLAG_HAS_ICON_RES = 4; // 0x4
field public static final int FLAG_KEY_FIELDS_ONLY = 16; // 0x10
field public static final int FLAG_PINNED = 2; // 0x2
field public static final int FLAG_STRINGS_RESOLVED = 128; // 0x80
field public static final java.lang.String SHORTCUT_CATEGORY_CONVERSATION = "android.shortcut.conversation";
}
@@ -10505,17 +10517,24 @@ package android.content.pm {
method public android.content.pm.ShortcutInfo build();
method public android.content.pm.ShortcutInfo.Builder setActivityComponent(android.content.ComponentName);
method public android.content.pm.ShortcutInfo.Builder setCategories(java.util.Set<java.lang.String>);
method public android.content.pm.ShortcutInfo.Builder setDisabledMessage(java.lang.String);
method public android.content.pm.ShortcutInfo.Builder setDisabledMessageResId(int);
method public android.content.pm.ShortcutInfo.Builder setExtras(android.os.PersistableBundle);
method public android.content.pm.ShortcutInfo.Builder setIcon(android.graphics.drawable.Icon);
method public android.content.pm.ShortcutInfo.Builder setId(java.lang.String);
method public android.content.pm.ShortcutInfo.Builder setIntent(android.content.Intent);
method public android.content.pm.ShortcutInfo.Builder setRank(int);
method public android.content.pm.ShortcutInfo.Builder setText(java.lang.String);
method public android.content.pm.ShortcutInfo.Builder setTextResId(int);
method public android.content.pm.ShortcutInfo.Builder setTitle(java.lang.String);
method public android.content.pm.ShortcutInfo.Builder setWeight(int);
method public android.content.pm.ShortcutInfo.Builder setTitleResId(int);
}
public class ShortcutManager {
method public boolean addDynamicShortcuts(java.util.List<android.content.pm.ShortcutInfo>);
method public void disableShortcuts(java.util.List<java.lang.String>);
method public void disableShortcuts(java.util.List<java.lang.String>, int);
method public void disableShortcuts(java.util.List<java.lang.String>, java.lang.String);
method public java.util.List<android.content.pm.ShortcutInfo> getDynamicShortcuts();
method public int getIconMaxDimensions();
method public int getMaxDynamicShortcutCount();
@@ -10524,6 +10543,7 @@ package android.content.pm {
method public int getRemainingCallCount();
method public void removeAllDynamicShortcuts();
method public void removeDynamicShortcuts(java.util.List<java.lang.String>);
method public void reportShortcutUsed(java.lang.String);
method public boolean setDynamicShortcuts(java.util.List<android.content.pm.ShortcutInfo>);
method public boolean updateShortcuts(java.util.List<android.content.pm.ShortcutInfo>);
}

View File

@@ -9513,6 +9513,8 @@ package android.content.pm {
public class LauncherApps {
ctor public LauncherApps(android.content.Context);
method public java.util.List<android.content.pm.LauncherActivityInfo> getActivityList(java.lang.String, android.os.UserHandle);
method public android.graphics.drawable.Drawable getShortcutBadgedIconDrawable(int);
method public android.graphics.drawable.Drawable getShortcutIconDrawable(int);
method public android.os.ParcelFileDescriptor getShortcutIconFd(android.content.pm.ShortcutInfo);
method public android.os.ParcelFileDescriptor getShortcutIconFd(java.lang.String, java.lang.String, android.os.UserHandle);
method public java.util.List<android.content.pm.ShortcutInfo> getShortcuts(android.content.pm.LauncherApps.ShortcutQuery, android.os.UserHandle);
@@ -10057,31 +10059,41 @@ package android.content.pm {
method public int describeContents();
method public android.content.ComponentName getActivityComponent();
method public java.util.Set<java.lang.String> getCategories();
method public java.lang.String getDisabledMessage();
method public int getDisabledMessageResId();
method public android.os.PersistableBundle getExtras();
method public int getIconResourceId();
method public java.lang.String getId();
method public android.content.Intent getIntent();
method public long getLastChangedTimestamp();
method public java.lang.String getPackageName();
method public int getRank();
method public java.lang.String getText();
method public int getTextResId();
method public java.lang.String getTitle();
method public int getTitleResId();
method public android.os.UserHandle getUserHandle();
method public int getWeight();
method public boolean hasIconFile();
method public boolean hasIconResource();
method public boolean hasKeyFieldsOnly();
method public boolean hasStringResourcesResolved();
method public boolean isDisabled();
method public boolean isDynamic();
method public boolean isFromManifest();
method public boolean isPinned();
method public void writeToParcel(android.os.Parcel, int);
field public static final int CLONE_REMOVE_FOR_CREATOR = 1; // 0x1
field public static final int CLONE_REMOVE_FOR_LAUNCHER = 3; // 0x3
field public static final int CLONE_REMOVE_NON_KEY_INFO = 4; // 0x4
field public static final android.os.Parcelable.Creator<android.content.pm.ShortcutInfo> CREATOR;
field public static final int FLAG_DISABLED = 64; // 0x40
field public static final int FLAG_DYNAMIC = 1; // 0x1
field public static final int FLAG_FROM_MANIFEST = 32; // 0x20
field public static final int FLAG_HAS_ICON_FILE = 8; // 0x8
field public static final int FLAG_HAS_ICON_RES = 4; // 0x4
field public static final int FLAG_KEY_FIELDS_ONLY = 16; // 0x10
field public static final int FLAG_PINNED = 2; // 0x2
field public static final int FLAG_STRINGS_RESOLVED = 128; // 0x80
field public static final java.lang.String SHORTCUT_CATEGORY_CONVERSATION = "android.shortcut.conversation";
}
@@ -10090,18 +10102,25 @@ package android.content.pm {
method public android.content.pm.ShortcutInfo build();
method public android.content.pm.ShortcutInfo.Builder setActivityComponent(android.content.ComponentName);
method public android.content.pm.ShortcutInfo.Builder setCategories(java.util.Set<java.lang.String>);
method public android.content.pm.ShortcutInfo.Builder setDisabledMessage(java.lang.String);
method public android.content.pm.ShortcutInfo.Builder setDisabledMessageResId(int);
method public android.content.pm.ShortcutInfo.Builder setExtras(android.os.PersistableBundle);
method public android.content.pm.ShortcutInfo.Builder setIcon(android.graphics.drawable.Icon);
method public android.content.pm.ShortcutInfo.Builder setId(java.lang.String);
method public android.content.pm.ShortcutInfo.Builder setIntent(android.content.Intent);
method public android.content.pm.ShortcutInfo.Builder setRank(int);
method public android.content.pm.ShortcutInfo.Builder setText(java.lang.String);
method public android.content.pm.ShortcutInfo.Builder setTextResId(int);
method public android.content.pm.ShortcutInfo.Builder setTitle(java.lang.String);
method public android.content.pm.ShortcutInfo.Builder setWeight(int);
method public android.content.pm.ShortcutInfo.Builder setTitleResId(int);
}
public class ShortcutManager {
ctor public ShortcutManager(android.content.Context);
method public boolean addDynamicShortcuts(java.util.List<android.content.pm.ShortcutInfo>);
method public void disableShortcuts(java.util.List<java.lang.String>);
method public void disableShortcuts(java.util.List<java.lang.String>, int);
method public void disableShortcuts(java.util.List<java.lang.String>, java.lang.String);
method public java.util.List<android.content.pm.ShortcutInfo> getDynamicShortcuts();
method public int getIconMaxDimensions();
method public int getMaxDynamicShortcutCount();
@@ -10110,6 +10129,7 @@ package android.content.pm {
method public int getRemainingCallCount();
method public void removeAllDynamicShortcuts();
method public void removeDynamicShortcuts(java.util.List<java.lang.String>);
method public void reportShortcutUsed(java.lang.String);
method public boolean setDynamicShortcuts(java.util.List<android.content.pm.ShortcutInfo>);
method public boolean updateShortcuts(java.util.List<android.content.pm.ShortcutInfo>);
}

View File

@@ -39,6 +39,9 @@ interface IShortcutService {
boolean updateShortcuts(String packageName, in ParceledListSlice shortcuts, int userId);
void disableShortcuts(String packageName, in List shortcutIds, String disabledMessage,
int disabledMessageResId, int userId);
int getMaxDynamicShortcutCount(String packageName, int userId);
int getRemainingCallCount(String packageName, int userId);
@@ -47,6 +50,8 @@ interface IShortcutService {
int getIconMaxDimensions(String packageName, int userId);
void reportShortcutUsed(String packageName, String shortcutId, int userId);
void resetThrottling(); // system only API for developer opsions
void onApplicationActive(String packageName, int userId); // system only API for sysUI

View File

@@ -25,6 +25,7 @@ import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager.ApplicationInfoFlags;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
@@ -554,6 +555,16 @@ public class LauncherApps {
}
}
/** TODO Javadoc */
public Drawable getShortcutIconDrawable(int density) {
throw new RuntimeException("TODO implement it");
}
/** TODO Javadoc */
public Drawable getShortcutBadgedIconDrawable(int density) {
throw new RuntimeException("TODO implement it");
}
/**
* Launches a shortcut.
*

View File

@@ -22,6 +22,8 @@ import android.annotation.UserIdInt;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.Resources;
import android.graphics.drawable.Icon;
import android.os.Bundle;
import android.os.Parcel;
@@ -67,6 +69,15 @@ public final class ShortcutInfo implements Parcelable {
/* @hide */
public static final int FLAG_KEY_FIELDS_ONLY = 1 << 4;
/* @hide */
public static final int FLAG_FROM_MANIFEST = 1 << 5;
/* @hide */
public static final int FLAG_DISABLED = 1 << 6;
/* @hide */
public static final int FLAG_STRINGS_RESOLVED = 1 << 7;
/** @hide */
@IntDef(flag = true,
value = {
@@ -75,6 +86,9 @@ public final class ShortcutInfo implements Parcelable {
FLAG_HAS_ICON_RES,
FLAG_HAS_ICON_FILE,
FLAG_KEY_FIELDS_ONLY,
FLAG_FROM_MANIFEST,
FLAG_DISABLED,
FLAG_STRINGS_RESOLVED,
})
@Retention(RetentionPolicy.SOURCE)
public @interface ShortcutFlags {}
@@ -124,28 +138,37 @@ public final class ShortcutInfo implements Parcelable {
@Nullable
private Icon mIcon;
@NonNull
private int mTitleResId;
@Nullable
private String mTitle;
private int mTextResId;
@Nullable
private String mText;
@NonNull
private int mDisabledMessageResId;
@Nullable
private String mDisabledMessage;
@Nullable
private ArraySet<String> mCategories;
/**
* Intent *with extras removed*.
*/
@NonNull
@Nullable
private Intent mIntent;
/**
* Extras for the intent.
*/
@NonNull
@Nullable
private PersistableBundle mIntentPersistableExtras;
private int mWeight;
private int mRank;
@Nullable
private PersistableBundle mExtras;
@@ -176,7 +199,11 @@ public final class ShortcutInfo implements Parcelable {
mActivityComponent = b.mActivityComponent;
mIcon = b.mIcon;
mTitle = b.mTitle;
mTitleResId = b.mTitleResId;
mText = b.mText;
mTextResId = b.mTextResId;
mDisabledMessage = b.mDisabledMessage;
mDisabledMessageResId = b.mDisabledMessageResId;
mCategories = clone(b.mCategories);
mIntent = b.mIntent;
if (mIntent != null) {
@@ -186,7 +213,7 @@ public final class ShortcutInfo implements Parcelable {
mIntentPersistableExtras = new PersistableBundle(intentExtras);
}
}
mWeight = b.mWeight;
mRank = b.mRank;
mExtras = b.mExtras;
updateTimestamp();
}
@@ -202,7 +229,10 @@ public final class ShortcutInfo implements Parcelable {
*/
public void enforceMandatoryFields() {
Preconditions.checkStringNotEmpty(mId, "Shortcut ID must be provided");
Preconditions.checkStringNotEmpty(mTitle, "Shortcut title must be provided");
Preconditions.checkNotNull(mActivityComponent, "activityComponent must be provided");
if (mTitle == null && mTitleResId == 0) {
throw new IllegalArgumentException("Shortcut title must be provided");
}
Preconditions.checkNotNull(mIntent, "Shortcut Intent must be provided");
}
@@ -228,13 +258,17 @@ public final class ShortcutInfo implements Parcelable {
}
mTitle = source.mTitle;
mTitleResId = source.mTitleResId;
mText = source.mText;
mTextResId = source.mTextResId;
mDisabledMessage = source.mDisabledMessage;
mDisabledMessageResId = source.mDisabledMessageResId;
mCategories = clone(source.mCategories);
if ((cloneFlags & CLONE_REMOVE_INTENT) == 0) {
mIntent = source.mIntent;
mIntentPersistableExtras = source.mIntentPersistableExtras;
}
mWeight = source.mWeight;
mRank = source.mRank;
mExtras = source.mExtras;
} else {
// Set this bit.
@@ -242,6 +276,30 @@ public final class ShortcutInfo implements Parcelable {
}
}
/** @hide */
public void resolveStringsRequiringCrossUser(Context context) throws NameNotFoundException {
mFlags |= FLAG_STRINGS_RESOLVED;
if ((mTitleResId == 0) && (mTextResId == 0) && (mDisabledMessageResId == 0)) {
return; // Bail early.
}
final Resources res = context.getPackageManager().getResourcesForApplicationAsUser(
mPackageName, mUserId);
if (mTitleResId != 0) {
mTitle = res.getString(mTitleResId);
mTitleResId = 0;
}
if (mTextResId != 0) {
mText = res.getString(mTextResId);
mTextResId = 0;
}
if (mDisabledMessageResId != 0) {
mDisabledMessage = res.getString(mDisabledMessageResId);
mDisabledMessageResId = 0;
}
}
/**
* Copy a {@link ShortcutInfo}, optionally removing fields.
* @hide
@@ -275,9 +333,24 @@ public final class ShortcutInfo implements Parcelable {
}
if (source.mTitle != null) {
mTitle = source.mTitle;
mTitleResId = 0;
} else if (source.mTitleResId != 0) {
mTitle = null;
mTitleResId = source.getTitleResId();
}
if (source.mText != null) {
mText = source.mText;
mTextResId = 0;
} else if (source.mTextResId != 0) {
mText = null;
mTextResId = source.mTextResId;
}
if (source.mDisabledMessage != null) {
mDisabledMessage = source.mDisabledMessage;
mDisabledMessageResId = 0;
} else if (source.mDisabledMessageResId != 0) {
mDisabledMessage = null;
mDisabledMessageResId = source.mDisabledMessageResId;
}
if (source.mCategories != null) {
mCategories = clone(source.mCategories);
@@ -286,8 +359,8 @@ public final class ShortcutInfo implements Parcelable {
mIntent = source.mIntent;
mIntentPersistableExtras = source.mIntentPersistableExtras;
}
if (source.mWeight != 0) {
mWeight = source.mWeight;
if (source.mRank != 0) {
mRank = source.mRank;
}
if (source.mExtras != null) {
mExtras = source.mExtras;
@@ -308,7 +381,6 @@ public final class ShortcutInfo implements Parcelable {
throw getInvalidIconException();
}
if (icon.hasTint()) {
// TODO support it
throw new IllegalArgumentException("Icons with tints are not supported");
}
@@ -333,15 +405,23 @@ public final class ShortcutInfo implements Parcelable {
private Icon mIcon;
private int mTitleResId;
private String mTitle;
private int mTextResId;
private String mText;
private int mDisabledMessageResId;
private String mDisabledMessage;
private Set<String> mCategories;
private Intent mIntent;
private int mWeight;
private int mRank;
private PersistableBundle mExtras;
@@ -396,6 +476,13 @@ public final class ShortcutInfo implements Parcelable {
return this;
}
/** TODO Javadoc */
public Builder setTitleResId(int titleResId) {
Preconditions.checkState(mTitle == null, "title already set");
mTitleResId = titleResId;
return this;
}
/**
* Sets the title of a shortcut. This is a mandatory field.
*
@@ -404,10 +491,18 @@ public final class ShortcutInfo implements Parcelable {
*/
@NonNull
public Builder setTitle(@NonNull String title) {
Preconditions.checkState(mTitleResId == 0, "titleResId already set");
mTitle = Preconditions.checkStringNotEmpty(title, "title");
return this;
}
/** TODO Javadoc */
public Builder setTextResId(int textResId) {
Preconditions.checkState(mText == null, "text already set");
mTextResId = textResId;
return this;
}
/**
* Sets the text of a shortcut. This is an optional field.
*
@@ -416,10 +511,27 @@ public final class ShortcutInfo implements Parcelable {
*/
@NonNull
public Builder setText(@NonNull String text) {
Preconditions.checkState(mTextResId == 0, "textResId already set");
mText = Preconditions.checkStringNotEmpty(text, "text");
return this;
}
/** TODO Javadoc */
public Builder setDisabledMessageResId(int disabledMessageResId) {
Preconditions.checkState(mDisabledMessage == null, "disabledMessage already set");
mDisabledMessageResId = disabledMessageResId;
return this;
}
@NonNull
public Builder setDisabledMessage(@NonNull String disabledMessage) {
Preconditions.checkState(
mDisabledMessageResId == 0, "disabledMessageResId already set");
mDisabledMessage =
Preconditions.checkStringNotEmpty(disabledMessage, "disabledMessage");
return this;
}
/**
* Sets categories for a shortcut. Launcher applications may use this information to
* categorise shortcuts.
@@ -444,12 +556,11 @@ public final class ShortcutInfo implements Parcelable {
}
/**
* Optionally sets the weight of a shortcut, which will be used by the launcher for sorting.
* The larger the weight, the more "important" a shortcut is.
* TODO javadoc.
*/
@NonNull
public Builder setWeight(int weight) {
mWeight = weight;
public Builder setRank(int rank) {
mRank = rank;
return this;
}
@@ -527,6 +638,11 @@ public final class ShortcutInfo implements Parcelable {
return mTitle;
}
/** TODO Javadoc */
public int getTitleResId() {
return mTitleResId;
}
/**
* Return the shortcut text.
*/
@@ -535,6 +651,24 @@ public final class ShortcutInfo implements Parcelable {
return mText;
}
/** TODO Javadoc */
public int getTextResId() {
return mTextResId;
}
/**
* Return the message that should be shown when a shortcut in disabled state is launched.
*/
@Nullable
public String getDisabledMessage() {
return mDisabledMessage;
}
/** TODO Javadoc */
public int getDisabledMessageResId() {
return mDisabledMessageResId;
}
/**
* Return the categories.
*/
@@ -584,11 +718,10 @@ public final class ShortcutInfo implements Parcelable {
}
/**
* Return the weight of a shortcut, which will be used by Launcher for sorting.
* The larger the weight, the more "important" a shortcut is.
* TODO Javadoc
*/
public int getWeight() {
return mWeight;
public int getRank() {
return mRank;
}
/**
@@ -654,6 +787,19 @@ public final class ShortcutInfo implements Parcelable {
return hasFlags(FLAG_PINNED);
}
/**
* Return whether a shortcut is published via manifest or not. If true, the shortcut is
* immutable.
*/
public boolean isFromManifest() {
return hasFlags(FLAG_FROM_MANIFEST);
}
/** Return whether a shortcut is disabled by publisher or not. */
public boolean isDisabled() {
return !hasFlags(FLAG_DISABLED);
}
/**
* Return whether a shortcut's icon is a resource in the owning package.
*
@@ -663,6 +809,16 @@ public final class ShortcutInfo implements Parcelable {
return hasFlags(FLAG_HAS_ICON_RES);
}
/** @hide */
public boolean hasStringResources() {
return (mTitleResId != 0) || (mTextResId != 0) || (mDisabledMessageResId != 0);
}
/** @hide */
public boolean hasAnyResources() {
return hasIconResource() || hasStringResources();
}
/**
* Return whether a shortcut's icon is stored as a file.
*
@@ -689,6 +845,11 @@ public final class ShortcutInfo implements Parcelable {
return hasFlags(FLAG_KEY_FIELDS_ONLY);
}
/** TODO Javadoc */
public boolean hasStringResourcesResolved() {
return hasFlags(FLAG_STRINGS_RESOLVED);
}
/** @hide */
public void updateTimestamp() {
mLastChangedTimestamp = System.currentTimeMillis();
@@ -736,10 +897,14 @@ public final class ShortcutInfo implements Parcelable {
mActivityComponent = source.readParcelable(cl);
mIcon = source.readParcelable(cl);
mTitle = source.readString();
mTitleResId = source.readInt();
mText = source.readString();
mTextResId = source.readInt();
mDisabledMessage = source.readString();
mDisabledMessageResId = source.readInt();
mIntent = source.readParcelable(cl);
mIntentPersistableExtras = source.readParcelable(cl);
mWeight = source.readInt();
mRank = source.readInt();
mExtras = source.readParcelable(cl);
mLastChangedTimestamp = source.readLong();
mFlags = source.readInt();
@@ -765,11 +930,15 @@ public final class ShortcutInfo implements Parcelable {
dest.writeParcelable(mActivityComponent, flags);
dest.writeParcelable(mIcon, flags);
dest.writeString(mTitle);
dest.writeInt(mTitleResId);
dest.writeString(mText);
dest.writeInt(mTextResId);
dest.writeString(mDisabledMessage);
dest.writeInt(mDisabledMessageResId);
dest.writeParcelable(mIntent, flags);
dest.writeParcelable(mIntentPersistableExtras, flags);
dest.writeInt(mWeight);
dest.writeInt(mRank);
dest.writeParcelable(mExtras, flags);
dest.writeLong(mLastChangedTimestamp);
dest.writeInt(mFlags);
@@ -837,9 +1006,18 @@ public final class ShortcutInfo implements Parcelable {
sb.append(", title=");
sb.append(secure ? "***" : mTitle);
sb.append(", titleResId=");
sb.append(mTitleResId);
sb.append(", text=");
sb.append(secure ? "***" : mText);
sb.append(", textResId=");
sb.append(mTextResId);
sb.append(", disabledMessage=");
sb.append(secure ? "***" : mDisabledMessage);
sb.append(", disabledMessageResId=");
sb.append(mDisabledMessageResId);
sb.append(", categories=");
sb.append(mCategories);
@@ -847,8 +1025,8 @@ public final class ShortcutInfo implements Parcelable {
sb.append(", icon=");
sb.append(mIcon);
sb.append(", weight=");
sb.append(mWeight);
sb.append(", rank=");
sb.append(mRank);
sb.append(", timestamp=");
sb.append(mLastChangedTimestamp);
@@ -864,6 +1042,32 @@ public final class ShortcutInfo implements Parcelable {
sb.append(", flags=");
sb.append(mFlags);
sb.append(" [");
if (hasFlags(FLAG_DISABLED)) {
sb.append("X");
}
if (hasFlags(FLAG_FROM_MANIFEST)) {
sb.append("M");
}
if (hasFlags(FLAG_DYNAMIC)) {
sb.append("D");
}
if (hasFlags(FLAG_PINNED)) {
sb.append("P");
}
if (hasFlags(FLAG_HAS_ICON_FILE)) {
sb.append("If");
}
if (hasFlags(FLAG_HAS_ICON_RES)) {
sb.append("Ir");
}
if (hasFlags(FLAG_KEY_FIELDS_ONLY)) {
sb.append("K");
}
if (hasFlags(FLAG_STRINGS_RESOLVED)) {
sb.append("S");
}
sb.append("]");
if (includeInternalData) {
@@ -881,9 +1085,10 @@ public final class ShortcutInfo implements Parcelable {
/** @hide */
public ShortcutInfo(
@UserIdInt int userId, String id, String packageName, ComponentName activityComponent,
Icon icon, String title, String text, Set<String> categories, Intent intent,
Icon icon, String title, int titleResId, String text, int textResId,
String disabledMessage, int disabledMessageResId, Set<String> categories, Intent intent,
PersistableBundle intentPersistableExtras,
int weight, PersistableBundle extras, long lastChangedTimestamp,
int rank, PersistableBundle extras, long lastChangedTimestamp,
int flags, int iconResId, String bitmapPath) {
mUserId = userId;
mId = id;
@@ -891,11 +1096,15 @@ public final class ShortcutInfo implements Parcelable {
mActivityComponent = activityComponent;
mIcon = icon;
mTitle = title;
mTitleResId = titleResId;
mText = text;
mTextResId = textResId;
mDisabledMessage = disabledMessage;
mDisabledMessageResId = disabledMessageResId;
mCategories = clone(categories);
mIntent = intent;
mIntentPersistableExtras = intentPersistableExtras;
mWeight = weight;
mRank = rank;
mExtras = extras;
mLastChangedTimestamp = lastChangedTimestamp;
mFlags = flags;

View File

@@ -28,6 +28,8 @@ import java.util.List;
// TODO Enhance javadoc
/**
* <b>TODO: Update to reflect DR changes.</b><br>
*
* {@link ShortcutManager} manages shortcuts created by applications.
*
* <h3>Dynamic shortcuts and pinned shortcuts</h3>
@@ -227,6 +229,45 @@ public class ShortcutManager {
}
}
/**
* TODO Javadoc
*/
public void disableShortcuts(@NonNull List<String> shortcutIds) {
try {
mService.disableShortcuts(mContext.getPackageName(), shortcutIds,
/* disabledMessage =*/ null, /* disabledMessageResId =*/ 0,
injectMyUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
/**
* TODO Javadoc
*/
public void disableShortcuts(@NonNull List<String> shortcutIds, int disabledMessageResId) {
try {
mService.disableShortcuts(mContext.getPackageName(), shortcutIds,
/* disabledMessage =*/ null, disabledMessageResId,
injectMyUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
/**
* TODO Javadoc
*/
public void disableShortcuts(@NonNull List<String> shortcutIds, String disabledMessage) {
try {
mService.disableShortcuts(mContext.getPackageName(), shortcutIds,
disabledMessage, /* disabledMessageResId =*/ 0,
injectMyUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
/**
* Return the max number of dynamic shortcuts that each application can have at a time.
*/
@@ -277,6 +318,15 @@ public class ShortcutManager {
}
}
public void reportShortcutUsed(String shortcutId) {
try {
mService.reportShortcutUsed(mContext.getPackageName(), shortcutId,
injectMyUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
/** @hide injection point */
@VisibleForTesting
protected int injectMyUserId() {

View File

@@ -61,9 +61,13 @@ class ShortcutPackage extends ShortcutPackageItem {
private static final String ATTR_ID = "id";
private static final String ATTR_ACTIVITY = "activity";
private static final String ATTR_TITLE = "title";
private static final String ATTR_TITLE_RES_ID = "titleid";
private static final String ATTR_TEXT = "text";
private static final String ATTR_TEXT_RES_ID = "textid";
private static final String ATTR_DISABLED_MESSAGE = "dmessage";
private static final String ATTR_DISABLED_MESSAGE_RES_ID = "dmessageid";
private static final String ATTR_INTENT = "intent";
private static final String ATTR_WEIGHT = "weight";
private static final String ATTR_RANK = "rank";
private static final String ATTR_TIMESTAMP = "timestamp";
private static final String ATTR_FLAGS = "flags";
private static final String ATTR_ICON_RES = "icon-res";
@@ -503,7 +507,7 @@ class ShortcutPackage extends ShortcutPackageItem {
for (int i = mShortcuts.size() - 1; i >= 0; i--) {
final ShortcutInfo si = mShortcuts.valueAt(i);
if (si.hasIconResource()) {
if (si.hasAnyResources()) {
changed = true;
si.setTimestamp(s.injectCurrentTimeMillis());
}
@@ -618,9 +622,13 @@ class ShortcutPackage extends ShortcutPackageItem {
ShortcutService.writeAttr(out, ATTR_ACTIVITY, si.getActivityComponent());
// writeAttr(out, "icon", si.getIcon()); // We don't save it.
ShortcutService.writeAttr(out, ATTR_TITLE, si.getTitle());
ShortcutService.writeAttr(out, ATTR_TITLE_RES_ID, si.getTitleResId());
ShortcutService.writeAttr(out, ATTR_TEXT, si.getText());
ShortcutService.writeAttr(out, ATTR_TEXT_RES_ID, si.getTextResId());
ShortcutService.writeAttr(out, ATTR_DISABLED_MESSAGE, si.getDisabledMessage());
ShortcutService.writeAttr(out, ATTR_DISABLED_MESSAGE_RES_ID, si.getDisabledMessageResId());
ShortcutService.writeAttr(out, ATTR_INTENT, si.getIntentNoExtras());
ShortcutService.writeAttr(out, ATTR_WEIGHT, si.getWeight());
ShortcutService.writeAttr(out, ATTR_RANK, si.getRank());
ShortcutService.writeAttr(out, ATTR_TIMESTAMP,
si.getLastChangedTimestamp());
if (forBackup) {
@@ -703,10 +711,14 @@ class ShortcutPackage extends ShortcutPackageItem {
ComponentName activityComponent;
// Icon icon;
String title;
int titleResId;
String text;
int textResId;
String disabledMessage;
int disabledMessageResId;
Intent intent;
PersistableBundle intentPersistableExtras = null;
int weight;
int rank;
PersistableBundle extras = null;
long lastChangedTimestamp;
int flags;
@@ -718,9 +730,14 @@ class ShortcutPackage extends ShortcutPackageItem {
activityComponent = ShortcutService.parseComponentNameAttribute(parser,
ATTR_ACTIVITY);
title = ShortcutService.parseStringAttribute(parser, ATTR_TITLE);
titleResId = ShortcutService.parseIntAttribute(parser, ATTR_TITLE_RES_ID);
text = ShortcutService.parseStringAttribute(parser, ATTR_TEXT);
textResId = ShortcutService.parseIntAttribute(parser, ATTR_TEXT_RES_ID);
disabledMessage = ShortcutService.parseStringAttribute(parser, ATTR_DISABLED_MESSAGE);
disabledMessageResId = ShortcutService.parseIntAttribute(parser,
ATTR_DISABLED_MESSAGE_RES_ID);
intent = ShortcutService.parseIntentAttribute(parser, ATTR_INTENT);
weight = (int) ShortcutService.parseLongAttribute(parser, ATTR_WEIGHT);
rank = (int) ShortcutService.parseLongAttribute(parser, ATTR_RANK);
lastChangedTimestamp = ShortcutService.parseLongAttribute(parser, ATTR_TIMESTAMP);
flags = (int) ShortcutService.parseLongAttribute(parser, ATTR_FLAGS);
iconRes = (int) ShortcutService.parseLongAttribute(parser, ATTR_ICON_RES);
@@ -765,9 +782,10 @@ class ShortcutPackage extends ShortcutPackageItem {
}
return new ShortcutInfo(
userId, id, packageName, activityComponent, /* icon =*/ null, title, text,
userId, id, packageName, activityComponent, /* icon =*/ null,
title, titleResId, text, textResId, disabledMessage, disabledMessageResId,
categories, intent,
intentPersistableExtras, weight, extras, lastChangedTimestamp, flags,
intentPersistableExtras, rank, extras, lastChangedTimestamp, flags,
iconRes, bitmapPath);
}

View File

@@ -32,6 +32,7 @@ import android.content.pm.LauncherApps;
import android.content.pm.LauncherApps.ShortcutQuery;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.PackageManagerInternal;
import android.content.pm.ParceledListSlice;
import android.content.pm.ResolveInfo;
@@ -110,13 +111,19 @@ import java.util.function.Predicate;
/**
* TODO:
* - Manifest shortcuts.
*
* - Implement disableShortcuts().
*
* - Implement reportShortcutUsed().
*
* - Ranks should be recalculated after each update.
*
* - When the system locale changes, update timestamps for shortcuts with string resources,
* and notify the launcher.
*
* - Default launcher check does take a few ms. Worth caching.
*
* - Clear data -> remove all dynamic? but not the pinned?
*
* - Scan and remove orphan bitmaps (just in case).
*
* - Detect when already registered instances are passed to APIs again, which might break
* internal bitmap handling.
*
@@ -1514,6 +1521,18 @@ public class ShortcutService extends IShortcutService.Stub {
return true;
}
@Override
public void disableShortcuts(String packageName, List shortcutIds,
String disabledMessage, int disabledMessageResId, @UserIdInt int userId) {
verifyCaller(packageName, userId);
Preconditions.checkNotNull(shortcutIds, "shortcutIds must be provided");
synchronized (mLock) {
// TODO implement it.
}
packageShortcutsChanged(packageName, userId);
}
@Override
public void removeDynamicShortcuts(String packageName, List shortcutIds,
@UserIdInt int userId) {
@@ -1599,7 +1618,7 @@ public class ShortcutService extends IShortcutService.Stub {
}
@Override
public int getIconMaxDimensions(String packageName, int userId) throws RemoteException {
public int getIconMaxDimensions(String packageName, int userId) {
verifyCaller(packageName, userId);
synchronized (mLock) {
@@ -1607,6 +1626,13 @@ public class ShortcutService extends IShortcutService.Stub {
}
}
@Override
public void reportShortcutUsed(String packageName, String shortcutId, int userId) {
verifyCaller(packageName, userId);
// TODO Implement it.
}
/**
* Reset all throttling, for developer options and command line. Only system/shell can call it.
*/
@@ -1792,10 +1818,10 @@ public class ShortcutService extends IShortcutService.Stub {
@Nullable ComponentName componentName,
int queryFlags, int userId) {
final ArrayList<ShortcutInfo> ret = new ArrayList<>();
final int cloneFlag =
((queryFlags & ShortcutQuery.FLAG_GET_KEY_FIELDS_ONLY) == 0)
? ShortcutInfo.CLONE_REMOVE_FOR_LAUNCHER
: ShortcutInfo.CLONE_REMOVE_NON_KEY_INFO;
final boolean cloneKeyFieldOnly =
((queryFlags & ShortcutQuery.FLAG_GET_KEY_FIELDS_ONLY) != 0);
final int cloneFlag = cloneKeyFieldOnly ? ShortcutInfo.CLONE_REMOVE_NON_KEY_INFO
: ShortcutInfo.CLONE_REMOVE_FOR_LAUNCHER;
if (packageName == null) {
shortcutIds = null; // LauncherAppsService already threw for it though.
}
@@ -1817,6 +1843,21 @@ public class ShortcutService extends IShortcutService.Stub {
});
}
}
// Resolve all strings if needed.
if (!cloneKeyFieldOnly) {
final long token = injectClearCallingIdentity();
try {
for (int i = ret.size() - 1; i >= 0; i--) {
try {
ret.get(i).resolveStringsRequiringCrossUser(mContext);
} catch (NameNotFoundException e) {
continue;
}
}
} finally {
injectRestoreCallingIdentity(token);
}
}
return ret;
}

View File

@@ -27,6 +27,7 @@ import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils
import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertAllNotHaveTitle;
import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertAllNotKeyFieldsOnly;
import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertAllPinned;
import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertAllStringsResolved;
import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertAllUnique;
import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertBitmapSize;
import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertBundleEmpty;
@@ -945,11 +946,12 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
* Make a shortcut with details.
*/
private ShortcutInfo makeShortcut(String id, String title, ComponentName activity,
Icon icon, Intent intent, int weight) {
Icon icon, Intent intent, int rank) {
final ShortcutInfo.Builder b = new ShortcutInfo.Builder(mClientContext)
.setId(id)
.setActivityComponent(new ComponentName(mClientContext.getPackageName(), "dummy"))
.setTitle(title)
.setWeight(weight)
.setRank(rank)
.setIntent(intent);
if (icon != null) {
b.setIcon(icon);
@@ -2269,11 +2271,12 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
setCaller(LAUNCHER_1);
// Get dynamic
assertAllDynamic(assertAllHaveTitle(assertAllNotHaveIntents(assertShortcutIds(
assertAllDynamic(assertAllHaveTitle(assertAllNotHaveIntents(assertAllStringsResolved(
assertShortcutIds(
assertAllNotKeyFieldsOnly(
mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
/* activity =*/ null, ShortcutQuery.FLAG_GET_DYNAMIC), getCallingUser())),
"s1", "s2"))));
"s1", "s2")))));
// Get pinned
assertShortcutIds(
@@ -2307,7 +2310,7 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
new ComponentName(CALLING_PACKAGE_2, ShortcutActivity.class.getName()),
ShortcutQuery.FLAG_GET_PINNED | ShortcutQuery.FLAG_GET_DYNAMIC),
getCallingUser())),
"s2", "s4"))));
"s4"))));
// With ID.
assertAllDynamic(assertAllNotHaveTitle(assertAllNotHaveIntents(assertShortcutIds(
@@ -2371,6 +2374,70 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
// TODO More tests: pinned but dynamic.
}
public void testGetShortcuts_resolveStrings() throws Exception {
doAnswer(pmInvocation -> {
assertEquals(Process.SYSTEM_UID, mInjectedCallingUid);
final String packageName = (String) pmInvocation.getArguments()[0];
final int userId = (Integer) pmInvocation.getArguments()[1];
final Resources res = mock(Resources.class);
doAnswer(resInvocation -> {
final int resId = (Integer) resInvocation.getArguments()[0];
return "string-" + packageName + "-user:" + userId + "-res:" + resId;
}).when(res).getString(anyInt());
return res;
}).when(mMockPackageManager).getResourcesForApplicationAsUser(anyString(), anyInt());
runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
ShortcutInfo si = new ShortcutInfo.Builder(mClientContext)
.setId("id")
.setActivityComponent(new ComponentName(mClientContext, "dummy"))
.setTitleResId(10)
.setTextResId(11)
.setDisabledMessageResId(12)
.setIntent(makeIntent("action", ShortcutActivity.class))
.build();
mManager.setDynamicShortcuts(list(si));
});
runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
ShortcutInfo si = new ShortcutInfo.Builder(mClientContext)
.setId("id")
.setActivityComponent(new ComponentName(mClientContext, "dummy"))
.setTitleResId(10)
.setTextResId(11)
.setDisabledMessageResId(12)
.setIntent(makeIntent("action", ShortcutActivity.class))
.build();
mManager.setDynamicShortcuts(list(si));
});
runWithCaller(LAUNCHER_1, USER_0, () -> {
final ShortcutQuery q = new ShortcutQuery();
q.setQueryFlags(ShortcutQuery.FLAG_GET_DYNAMIC);
// USER 0
List<ShortcutInfo> ret = assertShortcutIds(
assertAllStringsResolved(mLauncherApps.getShortcuts(q, HANDLE_USER_0)),
"id");
assertEquals("string-com.android.test.1-user:0-res:10", ret.get(0).getTitle());
assertEquals("string-com.android.test.1-user:0-res:11", ret.get(0).getText());
assertEquals("string-com.android.test.1-user:0-res:12",
ret.get(0).getDisabledMessage());
// USER P0
ret = assertShortcutIds(
assertAllStringsResolved(mLauncherApps.getShortcuts(q, HANDLE_USER_P0)),
"id");
assertEquals("string-com.android.test.1-user:20-res:10", ret.get(0).getTitle());
assertEquals("string-com.android.test.1-user:20-res:11", ret.get(0).getText());
assertEquals("string-com.android.test.1-user:20-res:12",
ret.get(0).getDisabledMessage());
});
}
// TODO resource
public void testGetShortcutInfo() {
// Create shortcuts.
setCaller(CALLING_PACKAGE_1);
@@ -5938,15 +6005,26 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
NullPointerException.class,
"Intent action must be set",
() -> new ShortcutInfo.Builder(getTestContext()).setIntent(new Intent()));
assertExpectException(
NullPointerException.class,
"activityComponent must be provided",
() -> new ShortcutInfo.Builder(getTestContext()).setId("id").build()
.enforceMandatoryFields());
assertExpectException(
IllegalArgumentException.class,
"title must be provided",
() -> new ShortcutInfo.Builder(getTestContext()).setId("id").build()
() -> new ShortcutInfo.Builder(getTestContext()).setId("id")
.setActivityComponent(
new ComponentName(getTestContext().getPackageName(), "s"))
.build()
.enforceMandatoryFields());
assertExpectException(
NullPointerException.class,
"Intent must be provided",
() -> new ShortcutInfo.Builder(getTestContext()).setId("id").setTitle("x").build()
() -> new ShortcutInfo.Builder(getTestContext()).setId("id")
.setActivityComponent(
new ComponentName(getTestContext().getPackageName(), "s"))
.setTitle("x").build()
.enforceMandatoryFields());
}
@@ -5973,9 +6051,10 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
.setIcon(Icon.createWithResource(mClientContext, 123))
.setTitle("title")
.setText("text")
.setDisabledMessage("dismes")
.setIntent(makeIntent("action", ShortcutActivity.class, "key", "val"))
.setCategories(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"))
.setWeight(123)
.setRank(123)
.setExtras(pb)
.build();
si.addFlags(ShortcutInfo.FLAG_PINNED);
@@ -5990,10 +6069,54 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
assertEquals(123, si.getIcon().getResId());
assertEquals("title", si.getTitle());
assertEquals("text", si.getText());
assertEquals("dismes", si.getDisabledMessage());
assertEquals(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"), si.getCategories());
assertEquals("action", si.getIntent().getAction());
assertEquals("val", si.getIntent().getStringExtra("key"));
assertEquals(123, si.getWeight());
assertEquals(123, si.getRank());
assertEquals(1, si.getExtras().getInt("k"));
assertEquals(ShortcutInfo.FLAG_PINNED, si.getFlags());
assertEquals("abc", si.getBitmapPath());
assertEquals(456, si.getIconResourceId());
}
public void testShortcutInfoParcel_resId() {
setCaller(CALLING_PACKAGE_1, USER_10);
ShortcutInfo si;
PersistableBundle pb = new PersistableBundle();
pb.putInt("k", 1);
si = new ShortcutInfo.Builder(getTestContext())
.setId("id")
.setActivityComponent(new ComponentName("a", "b"))
.setIcon(Icon.createWithResource(mClientContext, 123))
.setTitleResId(10)
.setTextResId(11)
.setDisabledMessageResId(12)
.setIntent(makeIntent("action", ShortcutActivity.class, "key", "val"))
.setCategories(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"))
.setRank(123)
.setExtras(pb)
.build();
si.addFlags(ShortcutInfo.FLAG_PINNED);
si.setBitmapPath("abc");
si.setIconResourceId(456);
si = parceled(si);
assertEquals(getTestContext().getPackageName(), si.getPackageName());
assertEquals("id", si.getId());
assertEquals(new ComponentName("a", "b"), si.getActivityComponent());
assertEquals(123, si.getIcon().getResId());
assertEquals(10, si.getTitleResId());
assertEquals(11, si.getTextResId());
assertEquals(12, si.getDisabledMessageResId());
assertEquals(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"), si.getCategories());
assertEquals("action", si.getIntent().getAction());
assertEquals("val", si.getIntent().getStringExtra("key"));
assertEquals(123, si.getRank());
assertEquals(1, si.getExtras().getInt("k"));
assertEquals(ShortcutInfo.FLAG_PINNED, si.getFlags());
@@ -6012,9 +6135,10 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
.setIcon(Icon.createWithResource(mClientContext, 123))
.setTitle("title")
.setText("text")
.setDisabledMessage("dismes")
.setCategories(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"))
.setIntent(makeIntent("action", ShortcutActivity.class, "key", "val"))
.setWeight(123)
.setRank(123)
.setExtras(pb)
.build();
sorig.addFlags(ShortcutInfo.FLAG_PINNED);
@@ -6031,10 +6155,11 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
assertEquals(123, si.getIcon().getResId());
assertEquals("title", si.getTitle());
assertEquals("text", si.getText());
assertEquals("dismes", si.getDisabledMessage());
assertEquals(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"), si.getCategories());
assertEquals("action", si.getIntent().getAction());
assertEquals("val", si.getIntent().getStringExtra("key"));
assertEquals(123, si.getWeight());
assertEquals(123, si.getRank());
assertEquals(1, si.getExtras().getInt("k"));
assertEquals(ShortcutInfo.FLAG_PINNED, si.getFlags());
@@ -6049,10 +6174,11 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
assertEquals(null, si.getIcon());
assertEquals("title", si.getTitle());
assertEquals("text", si.getText());
assertEquals("dismes", si.getDisabledMessage());
assertEquals(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"), si.getCategories());
assertEquals("action", si.getIntent().getAction());
assertEquals("val", si.getIntent().getStringExtra("key"));
assertEquals(123, si.getWeight());
assertEquals(123, si.getRank());
assertEquals(1, si.getExtras().getInt("k"));
assertEquals(ShortcutInfo.FLAG_PINNED, si.getFlags());
@@ -6068,9 +6194,10 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
assertEquals(null, si.getIcon());
assertEquals("title", si.getTitle());
assertEquals("text", si.getText());
assertEquals("dismes", si.getDisabledMessage());
assertEquals(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"), si.getCategories());
assertEquals(null, si.getIntent());
assertEquals(123, si.getWeight());
assertEquals(123, si.getRank());
assertEquals(1, si.getExtras().getInt("k"));
assertEquals(ShortcutInfo.FLAG_PINNED, si.getFlags());
@@ -6086,9 +6213,111 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
assertEquals(null, si.getIcon());
assertEquals(null, si.getTitle());
assertEquals(null, si.getText());
assertEquals(null, si.getDisabledMessage());
assertEquals(null, si.getCategories());
assertEquals(null, si.getIntent());
assertEquals(0, si.getWeight());
assertEquals(0, si.getRank());
assertEquals(null, si.getExtras());
assertEquals(ShortcutInfo.FLAG_PINNED | ShortcutInfo.FLAG_KEY_FIELDS_ONLY, si.getFlags());
assertEquals(null, si.getBitmapPath());
assertEquals(456, si.getIconResourceId());
}
public void testShortcutInfoClone_resId() {
setCaller(CALLING_PACKAGE_1, USER_11);
PersistableBundle pb = new PersistableBundle();
pb.putInt("k", 1);
ShortcutInfo sorig = new ShortcutInfo.Builder(mClientContext)
.setId("id")
.setActivityComponent(new ComponentName("a", "b"))
.setIcon(Icon.createWithResource(mClientContext, 123))
.setTitleResId(10)
.setTextResId(11)
.setDisabledMessageResId(12)
.setCategories(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"))
.setIntent(makeIntent("action", ShortcutActivity.class, "key", "val"))
.setRank(123)
.setExtras(pb)
.build();
sorig.addFlags(ShortcutInfo.FLAG_PINNED);
sorig.setBitmapPath("abc");
sorig.setIconResourceId(456);
ShortcutInfo si = sorig.clone(/* clone flags*/ 0);
assertEquals(USER_11, si.getUserId());
assertEquals(HANDLE_USER_11, si.getUserHandle());
assertEquals(mClientContext.getPackageName(), si.getPackageName());
assertEquals("id", si.getId());
assertEquals(new ComponentName("a", "b"), si.getActivityComponent());
assertEquals(123, si.getIcon().getResId());
assertEquals(10, si.getTitleResId());
assertEquals(11, si.getTextResId());
assertEquals(12, si.getDisabledMessageResId());
assertEquals(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"), si.getCategories());
assertEquals("action", si.getIntent().getAction());
assertEquals("val", si.getIntent().getStringExtra("key"));
assertEquals(123, si.getRank());
assertEquals(1, si.getExtras().getInt("k"));
assertEquals(ShortcutInfo.FLAG_PINNED, si.getFlags());
assertEquals("abc", si.getBitmapPath());
assertEquals(456, si.getIconResourceId());
si = sorig.clone(ShortcutInfo.CLONE_REMOVE_FOR_CREATOR);
assertEquals(mClientContext.getPackageName(), si.getPackageName());
assertEquals("id", si.getId());
assertEquals(new ComponentName("a", "b"), si.getActivityComponent());
assertEquals(null, si.getIcon());
assertEquals(10, si.getTitleResId());
assertEquals(11, si.getTextResId());
assertEquals(12, si.getDisabledMessageResId());
assertEquals(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"), si.getCategories());
assertEquals("action", si.getIntent().getAction());
assertEquals("val", si.getIntent().getStringExtra("key"));
assertEquals(123, si.getRank());
assertEquals(1, si.getExtras().getInt("k"));
assertEquals(ShortcutInfo.FLAG_PINNED, si.getFlags());
assertEquals(null, si.getBitmapPath());
assertEquals(456, si.getIconResourceId());
si = sorig.clone(ShortcutInfo.CLONE_REMOVE_FOR_LAUNCHER);
assertEquals(mClientContext.getPackageName(), si.getPackageName());
assertEquals("id", si.getId());
assertEquals(new ComponentName("a", "b"), si.getActivityComponent());
assertEquals(null, si.getIcon());
assertEquals(10, si.getTitleResId());
assertEquals(11, si.getTextResId());
assertEquals(12, si.getDisabledMessageResId());
assertEquals(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"), si.getCategories());
assertEquals(null, si.getIntent());
assertEquals(123, si.getRank());
assertEquals(1, si.getExtras().getInt("k"));
assertEquals(ShortcutInfo.FLAG_PINNED, si.getFlags());
assertEquals(null, si.getBitmapPath());
assertEquals(456, si.getIconResourceId());
si = sorig.clone(ShortcutInfo.CLONE_REMOVE_NON_KEY_INFO);
assertEquals(mClientContext.getPackageName(), si.getPackageName());
assertEquals("id", si.getId());
assertEquals(null, si.getActivityComponent());
assertEquals(null, si.getIcon());
assertEquals(0, si.getTitleResId());
assertEquals(0, si.getTextResId());
assertEquals(0, si.getDisabledMessageResId());
assertEquals(null, si.getCategories());
assertEquals(null, si.getIntent());
assertEquals(0, si.getRank());
assertEquals(null, si.getExtras());
assertEquals(ShortcutInfo.FLAG_PINNED | ShortcutInfo.FLAG_KEY_FIELDS_ONLY, si.getFlags());
@@ -6147,9 +6376,10 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
.setIcon(Icon.createWithResource(mClientContext, 123))
.setTitle("title")
.setText("text")
.setDisabledMessage("dismes")
.setCategories(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"))
.setIntent(makeIntent("action", ShortcutActivity.class, "key", "val"))
.setWeight(123)
.setRank(123)
.setExtras(pb)
.build();
sorig.addFlags(ShortcutInfo.FLAG_PINNED);
@@ -6175,12 +6405,42 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
.setTitle("xyz").build());
assertEquals("text", si.getText());
assertEquals("xyz", si.getTitle());
assertEquals(0, si.getTitleResId());
si = sorig.clone(/* flags=*/ 0);
si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
.setTitleResId(123).build());
assertEquals("text", si.getText());
assertEquals(null, si.getTitle());
assertEquals(123, si.getTitleResId());
si = sorig.clone(/* flags=*/ 0);
si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
.setText("xxx").build());
assertEquals(123, si.getWeight());
assertEquals(123, si.getRank());
assertEquals("xxx", si.getText());
assertEquals(0, si.getTextResId());
si = sorig.clone(/* flags=*/ 0);
si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
.setTextResId(1111).build());
assertEquals(123, si.getRank());
assertEquals(null, si.getText());
assertEquals(1111, si.getTextResId());
si = sorig.clone(/* flags=*/ 0);
si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
.setDisabledMessage("xxx").build());
assertEquals(123, si.getRank());
assertEquals("xxx", si.getDisabledMessage());
assertEquals(0, si.getDisabledMessageResId());
si = sorig.clone(/* flags=*/ 0);
si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
.setDisabledMessageResId(11111).build());
assertEquals(123, si.getRank());
assertEquals(null, si.getDisabledMessage());
assertEquals(11111, si.getDisabledMessageResId());
si = sorig.clone(/* flags=*/ 0);
si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
@@ -6210,9 +6470,9 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
si = sorig.clone(/* flags=*/ 0);
si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
.setWeight(999).build());
.setRank(999).build());
assertEquals("text", si.getText());
assertEquals(999, si.getWeight());
assertEquals(999, si.getRank());
PersistableBundle pb2 = new PersistableBundle();
@@ -6235,6 +6495,134 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
assertTrue(si.getLastChangedTimestamp() > timestamp);
}
public void testShortcutInfoCopyNonNullFieldsFrom_resId() throws InterruptedException {
PersistableBundle pb = new PersistableBundle();
pb.putInt("k", 1);
ShortcutInfo sorig = new ShortcutInfo.Builder(getTestContext())
.setId("id")
.setActivityComponent(new ComponentName("a", "b"))
.setIcon(Icon.createWithResource(mClientContext, 123))
.setTitleResId(10)
.setTextResId(11)
.setDisabledMessageResId(12)
.setCategories(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"))
.setIntent(makeIntent("action", ShortcutActivity.class, "key", "val"))
.setRank(123)
.setExtras(pb)
.build();
sorig.addFlags(ShortcutInfo.FLAG_PINNED);
sorig.setBitmapPath("abc");
sorig.setIconResourceId(456);
ShortcutInfo si;
si = sorig.clone(/* flags=*/ 0);
si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
.setActivityComponent(new ComponentName("x", "y")).build());
assertEquals(11, si.getTextResId());
assertEquals(new ComponentName("x", "y"), si.getActivityComponent());
si = sorig.clone(/* flags=*/ 0);
si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
.setIcon(Icon.createWithResource(mClientContext, 456)).build());
assertEquals(11, si.getTextResId());
assertEquals(456, si.getIcon().getResId());
si = sorig.clone(/* flags=*/ 0);
si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
.setTitle("xyz").build());
assertEquals(11, si.getTextResId());
assertEquals("xyz", si.getTitle());
assertEquals(0, si.getTitleResId());
si = sorig.clone(/* flags=*/ 0);
si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
.setTitleResId(123).build());
assertEquals(11, si.getTextResId());
assertEquals(null, si.getTitle());
assertEquals(123, si.getTitleResId());
si = sorig.clone(/* flags=*/ 0);
si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
.setText("xxx").build());
assertEquals(123, si.getRank());
assertEquals("xxx", si.getText());
assertEquals(0, si.getTextResId());
si = sorig.clone(/* flags=*/ 0);
si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
.setTextResId(1111).build());
assertEquals(123, si.getRank());
assertEquals(null, si.getText());
assertEquals(1111, si.getTextResId());
si = sorig.clone(/* flags=*/ 0);
si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
.setDisabledMessage("xxx").build());
assertEquals(123, si.getRank());
assertEquals("xxx", si.getDisabledMessage());
assertEquals(0, si.getDisabledMessageResId());
si = sorig.clone(/* flags=*/ 0);
si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
.setDisabledMessageResId(11111).build());
assertEquals(123, si.getRank());
assertEquals(null, si.getDisabledMessage());
assertEquals(11111, si.getDisabledMessageResId());
si = sorig.clone(/* flags=*/ 0);
si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
.setCategories(set()).build());
assertEquals(11, si.getTextResId());
assertEquals(set(), si.getCategories());
si = sorig.clone(/* flags=*/ 0);
si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
.setCategories(set("x")).build());
assertEquals(11, si.getTextResId());
assertEquals(set("x"), si.getCategories());
si = sorig.clone(/* flags=*/ 0);
si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
.setIntent(makeIntent("action2", ShortcutActivity.class)).build());
assertEquals(11, si.getTextResId());
assertEquals("action2", si.getIntent().getAction());
assertEquals(null, si.getIntent().getStringExtra("key"));
si = sorig.clone(/* flags=*/ 0);
si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
.setIntent(makeIntent("action3", ShortcutActivity.class, "key", "x")).build());
assertEquals(11, si.getTextResId());
assertEquals("action3", si.getIntent().getAction());
assertEquals("x", si.getIntent().getStringExtra("key"));
si = sorig.clone(/* flags=*/ 0);
si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
.setRank(999).build());
assertEquals(11, si.getTextResId());
assertEquals(999, si.getRank());
PersistableBundle pb2 = new PersistableBundle();
pb2.putInt("x", 99);
si = sorig.clone(/* flags=*/ 0);
si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
.setExtras(pb2).build());
assertEquals(11, si.getTextResId());
assertEquals(99, si.getExtras().getInt("x"));
// Make sure the timestamp gets updated too.
final long timestamp = si.getLastChangedTimestamp();
Thread.sleep(2);
si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
.setTitle("xyz").build());
assertTrue(si.getLastChangedTimestamp() > timestamp);
}
public void testShortcutInfoSaveAndLoad() throws InterruptedException {
setCaller(CALLING_PACKAGE_1, USER_10);
@@ -6249,9 +6637,10 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
.setIcon(bmp32x32)
.setTitle("title")
.setText("text")
.setDisabledMessage("dismes")
.setCategories(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"))
.setIntent(makeIntent("action", ShortcutActivity.class, "key", "val"))
.setWeight(123)
.setRank(123)
.setExtras(pb)
.build();
@@ -6276,10 +6665,66 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
assertEquals(null, si.getIcon());
assertEquals("title", si.getTitle());
assertEquals("text", si.getText());
assertEquals("dismes", si.getDisabledMessage());
assertEquals(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"), si.getCategories());
assertEquals("action", si.getIntent().getAction());
assertEquals("val", si.getIntent().getStringExtra("key"));
assertEquals(123, si.getWeight());
assertEquals(123, si.getRank());
assertEquals(1, si.getExtras().getInt("k"));
assertEquals(ShortcutInfo.FLAG_DYNAMIC | ShortcutInfo.FLAG_HAS_ICON_FILE, si.getFlags());
assertNotNull(si.getBitmapPath()); // Something should be set.
assertEquals(0, si.getIconResourceId());
assertTrue(si.getLastChangedTimestamp() < now);
}
public void testShortcutInfoSaveAndLoad_resId() throws InterruptedException {
setCaller(CALLING_PACKAGE_1, USER_10);
final Icon bmp32x32 = Icon.createWithBitmap(BitmapFactory.decodeResource(
getTestContext().getResources(), R.drawable.black_32x32));
PersistableBundle pb = new PersistableBundle();
pb.putInt("k", 1);
ShortcutInfo sorig = new ShortcutInfo.Builder(mClientContext)
.setId("id")
.setActivityComponent(new ComponentName(mClientContext, ShortcutActivity2.class))
.setIcon(bmp32x32)
.setTitleResId(10)
.setTextResId(11)
.setDisabledMessageResId(12)
.setCategories(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"))
.setIntent(makeIntent("action", ShortcutActivity.class, "key", "val"))
.setRank(123)
.setExtras(pb)
.build();
mManager.addDynamicShortcuts(list(sorig));
Thread.sleep(2);
final long now = System.currentTimeMillis();
// Save and load.
mService.saveDirtyInfo();
initService();
mService.handleUnlockUser(USER_10);
ShortcutInfo si;
si = mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "id", USER_10);
assertEquals(USER_10, si.getUserId());
assertEquals(HANDLE_USER_10, si.getUserHandle());
assertEquals(CALLING_PACKAGE_1, si.getPackageName());
assertEquals("id", si.getId());
assertEquals(ShortcutActivity2.class.getName(), si.getActivityComponent().getClassName());
assertEquals(null, si.getIcon());
assertEquals(10, si.getTitleResId());
assertEquals(11, si.getTextResId());
assertEquals(12, si.getDisabledMessageResId());
assertEquals(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"), si.getCategories());
assertEquals("action", si.getIntent().getAction());
assertEquals("val", si.getIntent().getStringExtra("key"));
assertEquals(123, si.getRank());
assertEquals(1, si.getExtras().getInt("k"));
assertEquals(ShortcutInfo.FLAG_DYNAMIC | ShortcutInfo.FLAG_HAS_ICON_FILE, si.getFlags());
@@ -6302,9 +6747,10 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
.setIcon(bmp32x32)
.setTitle("title")
.setText("text")
.setDisabledMessage("dismes")
.setCategories(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"))
.setIntent(makeIntent("action", ShortcutActivity.class, "key", "val"))
.setWeight(123)
.setRank(123)
.setExtras(pb)
.build();
@@ -6328,10 +6774,64 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
assertEquals(null, si.getIcon());
assertEquals("title", si.getTitle());
assertEquals("text", si.getText());
assertEquals("dismes", si.getDisabledMessage());
assertEquals(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"), si.getCategories());
assertEquals("action", si.getIntent().getAction());
assertEquals("val", si.getIntent().getStringExtra("key"));
assertEquals(123, si.getWeight());
assertEquals(123, si.getRank());
assertEquals(1, si.getExtras().getInt("k"));
assertEquals(ShortcutInfo.FLAG_PINNED, si.getFlags());
assertNull(si.getBitmapPath()); // No icon.
assertEquals(0, si.getIconResourceId());
}
public void testShortcutInfoSaveAndLoad_forBackup_resId() {
setCaller(CALLING_PACKAGE_1, USER_0);
final Icon bmp32x32 = Icon.createWithBitmap(BitmapFactory.decodeResource(
getTestContext().getResources(), R.drawable.black_32x32));
PersistableBundle pb = new PersistableBundle();
pb.putInt("k", 1);
ShortcutInfo sorig = new ShortcutInfo.Builder(mClientContext)
.setId("id")
.setActivityComponent(new ComponentName(mClientContext, ShortcutActivity2.class))
.setIcon(bmp32x32)
.setTitleResId(10)
.setTextResId(11)
.setDisabledMessageResId(12)
.setCategories(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"))
.setIntent(makeIntent("action", ShortcutActivity.class, "key", "val"))
.setRank(123)
.setExtras(pb)
.build();
mManager.addDynamicShortcuts(list(sorig));
// Dynamic shortcuts won't be backed up, so we need to pin it.
setCaller(LAUNCHER_1, USER_0);
mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("id"), HANDLE_USER_0);
// Do backup & restore.
backupAndRestore();
mService.handleUnlockUser(USER_0); // Load user-0.
ShortcutInfo si;
si = mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "id", USER_0);
assertEquals(CALLING_PACKAGE_1, si.getPackageName());
assertEquals("id", si.getId());
assertEquals(ShortcutActivity2.class.getName(), si.getActivityComponent().getClassName());
assertEquals(null, si.getIcon());
assertEquals(10, si.getTitleResId());
assertEquals(11, si.getTextResId());
assertEquals(12, si.getDisabledMessageResId());
assertEquals(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"), si.getCategories());
assertEquals("action", si.getIntent().getAction());
assertEquals("val", si.getIntent().getStringExtra("key"));
assertEquals(123, si.getRank());
assertEquals(1, si.getExtras().getInt("k"));
assertEquals(ShortcutInfo.FLAG_PINNED, si.getFlags());

View File

@@ -383,6 +383,14 @@ public class ShortcutManagerTestUtils {
return actualShortcuts;
}
public static List<ShortcutInfo> assertAllStringsResolved(
List<ShortcutInfo> actualShortcuts) {
for (ShortcutInfo s : actualShortcuts) {
assertTrue("ID " + s.getId(), s.hasStringResourcesResolved());
}
return actualShortcuts;
}
public static void assertDynamicOnly(ShortcutInfo si) {
assertTrue(si.isDynamic());
assertFalse(si.isPinned());