summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--api/current.txt12
-rw-r--r--api/system-current.txt12
-rw-r--r--api/test-current.txt12
-rw-r--r--core/java/android/content/pm/IShortcutService.aidl7
-rw-r--r--core/java/android/content/pm/LauncherApps.java38
-rw-r--r--core/java/android/content/pm/ShortcutInfo.java63
-rw-r--r--core/java/android/content/pm/ShortcutManager.java25
-rwxr-xr-xcore/java/android/provider/Settings.java4
-rw-r--r--services/core/java/com/android/server/pm/ShortcutPackage.java34
-rw-r--r--services/core/java/com/android/server/pm/ShortcutService.java51
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest.java227
11 files changed, 328 insertions, 157 deletions
diff --git a/api/current.txt b/api/current.txt
index 732c50080623..9dd271033a05 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -9500,8 +9500,6 @@ package android.content.pm {
method public android.content.pm.ApplicationInfo getApplicationInfo(java.lang.String, int, android.os.UserHandle);
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 int getShortcutIconResId(android.content.pm.ShortcutInfo);
- method public int getShortcutIconResId(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);
method public boolean hasShortcutHostPermission();
method public boolean isActivityEnabled(android.content.ComponentName, android.os.UserHandle);
@@ -10042,7 +10040,9 @@ package android.content.pm {
public final class ShortcutInfo implements android.os.Parcelable {
method public int describeContents();
method public android.content.ComponentName getActivityComponent();
+ method public java.util.List<java.lang.String> getCategories();
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();
@@ -10066,12 +10066,14 @@ package android.content.pm {
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 java.lang.String SHORTCUT_CATEGORY_CONVERSATION = "android.shortcut.conversation";
}
public static class ShortcutInfo.Builder {
ctor public ShortcutInfo.Builder(android.content.Context);
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.List<java.lang.String>);
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);
@@ -10082,15 +10084,15 @@ package android.content.pm {
}
public class ShortcutManager {
- method public boolean addDynamicShortcut(android.content.pm.ShortcutInfo);
- method public void deleteAllDynamicShortcuts();
- method public void deleteDynamicShortcut(java.lang.String);
+ method public boolean addDynamicShortcuts(java.util.List<android.content.pm.ShortcutInfo>);
method public java.util.List<android.content.pm.ShortcutInfo> getDynamicShortcuts();
method public int getIconMaxDimensions();
method public int getMaxDynamicShortcutCount();
method public java.util.List<android.content.pm.ShortcutInfo> getPinnedShortcuts();
method public long getRateLimitResetTime();
method public int getRemainingCallCount();
+ method public void removeAllDynamicShortcuts();
+ method public void removeDynamicShortcuts(java.util.List<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>);
}
diff --git a/api/system-current.txt b/api/system-current.txt
index 56b2f581bb82..80092c0c4316 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -9838,8 +9838,6 @@ package android.content.pm {
method public android.content.pm.ApplicationInfo getApplicationInfo(java.lang.String, int, android.os.UserHandle);
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 int getShortcutIconResId(android.content.pm.ShortcutInfo);
- method public int getShortcutIconResId(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);
method public boolean hasShortcutHostPermission();
method public boolean isActivityEnabled(android.content.ComponentName, android.os.UserHandle);
@@ -10442,7 +10440,9 @@ package android.content.pm {
public final class ShortcutInfo implements android.os.Parcelable {
method public int describeContents();
method public android.content.ComponentName getActivityComponent();
+ method public java.util.List<java.lang.String> getCategories();
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();
@@ -10466,12 +10466,14 @@ package android.content.pm {
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 java.lang.String SHORTCUT_CATEGORY_CONVERSATION = "android.shortcut.conversation";
}
public static class ShortcutInfo.Builder {
ctor public ShortcutInfo.Builder(android.content.Context);
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.List<java.lang.String>);
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);
@@ -10482,15 +10484,15 @@ package android.content.pm {
}
public class ShortcutManager {
- method public boolean addDynamicShortcut(android.content.pm.ShortcutInfo);
- method public void deleteAllDynamicShortcuts();
- method public void deleteDynamicShortcut(java.lang.String);
+ method public boolean addDynamicShortcuts(java.util.List<android.content.pm.ShortcutInfo>);
method public java.util.List<android.content.pm.ShortcutInfo> getDynamicShortcuts();
method public int getIconMaxDimensions();
method public int getMaxDynamicShortcutCount();
method public java.util.List<android.content.pm.ShortcutInfo> getPinnedShortcuts();
method public long getRateLimitResetTime();
method public int getRemainingCallCount();
+ method public void removeAllDynamicShortcuts();
+ method public void removeDynamicShortcuts(java.util.List<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>);
}
diff --git a/api/test-current.txt b/api/test-current.txt
index 679347df0feb..01649f6b1a56 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -9510,8 +9510,6 @@ package android.content.pm {
method public android.content.pm.ApplicationInfo getApplicationInfo(java.lang.String, int, android.os.UserHandle);
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 int getShortcutIconResId(android.content.pm.ShortcutInfo);
- method public int getShortcutIconResId(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);
method public boolean hasShortcutHostPermission();
method public boolean isActivityEnabled(android.content.ComponentName, android.os.UserHandle);
@@ -10053,7 +10051,9 @@ package android.content.pm {
public final class ShortcutInfo implements android.os.Parcelable {
method public int describeContents();
method public android.content.ComponentName getActivityComponent();
+ method public java.util.List<java.lang.String> getCategories();
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();
@@ -10077,12 +10077,14 @@ package android.content.pm {
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 java.lang.String SHORTCUT_CATEGORY_CONVERSATION = "android.shortcut.conversation";
}
public static class ShortcutInfo.Builder {
ctor public ShortcutInfo.Builder(android.content.Context);
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.List<java.lang.String>);
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);
@@ -10094,15 +10096,15 @@ package android.content.pm {
public class ShortcutManager {
ctor public ShortcutManager(android.content.Context);
- method public boolean addDynamicShortcut(android.content.pm.ShortcutInfo);
- method public void deleteAllDynamicShortcuts();
- method public void deleteDynamicShortcut(java.lang.String);
+ method public boolean addDynamicShortcuts(java.util.List<android.content.pm.ShortcutInfo>);
method public java.util.List<android.content.pm.ShortcutInfo> getDynamicShortcuts();
method public int getIconMaxDimensions();
method public int getMaxDynamicShortcutCount();
method public java.util.List<android.content.pm.ShortcutInfo> getPinnedShortcuts();
method public long getRateLimitResetTime();
method public int getRemainingCallCount();
+ method public void removeAllDynamicShortcuts();
+ method public void removeDynamicShortcuts(java.util.List<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>);
}
diff --git a/core/java/android/content/pm/IShortcutService.aidl b/core/java/android/content/pm/IShortcutService.aidl
index 31d377b554f8..9c90346a075c 100644
--- a/core/java/android/content/pm/IShortcutService.aidl
+++ b/core/java/android/content/pm/IShortcutService.aidl
@@ -28,11 +28,12 @@ interface IShortcutService {
ParceledListSlice getDynamicShortcuts(String packageName, int userId);
- boolean addDynamicShortcut(String packageName, in ShortcutInfo shortcutInfo, int userId);
+ boolean addDynamicShortcuts(String packageName, in ParceledListSlice shortcutInfoList,
+ int userId);
- void deleteDynamicShortcut(String packageName, in String shortcutId, int userId);
+ void removeDynamicShortcuts(String packageName, in List shortcutIds, int userId);
- void deleteAllDynamicShortcuts(String packageName, int userId);
+ void removeAllDynamicShortcuts(String packageName, int userId);
ParceledListSlice getPinnedShortcuts(String packageName, int userId);
diff --git a/core/java/android/content/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java
index a0d2339566a5..4f8650e06bef 100644
--- a/core/java/android/content/pm/LauncherApps.java
+++ b/core/java/android/content/pm/LauncherApps.java
@@ -39,6 +39,7 @@ import android.util.Log;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collections;
import java.util.List;
@@ -493,43 +494,24 @@ public class LauncherApps {
}
/**
- * Return the icon resource ID, if {@code shortcut} has one
- * (i.e. when {@link ShortcutInfo#hasIconResource()} returns {@code true}).
- *
- * <p>Callers must be allowed to access the shortcut information, as defined in {@link
- * #hasShortcutHostPermission()}.
- *
- * @param shortcut The target shortcut.
+ * @hide kept for testing.
*/
public int getShortcutIconResId(@NonNull ShortcutInfo shortcut) {
- return getShortcutIconResId(shortcut.getPackageName(), shortcut.getId(),
- shortcut.getUserId());
+ return shortcut.getIconResourceId();
}
/**
- * Return the icon resource ID, if {@code shortcut} has one
- * (i.e. when {@link ShortcutInfo#hasIconResource()} returns {@code true}).
- *
- * <p>Callers must be allowed to access the shortcut information, as defined in {@link
- * #hasShortcutHostPermission()}.
- *
- * @param packageName The target package name.
- * @param shortcutId The ID of the shortcut to lad rom.
- * @param user The UserHandle of the profile.
+ * @hide kept for testing.
*/
public int getShortcutIconResId(@NonNull String packageName, @NonNull String shortcutId,
@NonNull UserHandle user) {
- return getShortcutIconResId(packageName, shortcutId, user.getIdentifier());
- }
+ final ShortcutQuery q = new ShortcutQuery();
+ q.setPackage(packageName);
+ q.setShortcutIds(Arrays.asList(shortcutId));
+ q.setQueryFlags(ShortcutQuery.FLAG_GET_DYNAMIC | ShortcutQuery.FLAG_GET_PINNED);
+ final List<ShortcutInfo> shortcuts = getShortcuts(q, user);
- private int getShortcutIconResId(@NonNull String packageName, @NonNull String shortcutId,
- int userId) {
- try {
- return mService.getShortcutIconResId(mContext.getPackageName(),
- packageName, shortcutId, userId);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
+ return shortcuts.size() > 0 ? shortcuts.get(0).getIconResourceId() : 0;
}
/**
diff --git a/core/java/android/content/pm/ShortcutInfo.java b/core/java/android/content/pm/ShortcutInfo.java
index 7a807c4cf949..a9000155bc00 100644
--- a/core/java/android/content/pm/ShortcutInfo.java
+++ b/core/java/android/content/pm/ShortcutInfo.java
@@ -34,6 +34,8 @@ import com.android.internal.util.Preconditions;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.List;
// TODO Enhance javadoc
/**
@@ -107,6 +109,11 @@ public final class ShortcutInfo implements Parcelable {
@Retention(RetentionPolicy.SOURCE)
public @interface CloneFlags {}
+ /**
+ * Shortcut category for
+ */
+ public static final String SHORTCUT_CATEGORY_CONVERSATION = "android.shortcut.conversation";
+
private final String mId;
@NonNull
@@ -124,6 +131,9 @@ public final class ShortcutInfo implements Parcelable {
@Nullable
private String mText;
+ @NonNull
+ private List<String> mCategories;
+
/**
* Intent *with extras removed*.
*/
@@ -168,6 +178,7 @@ public final class ShortcutInfo implements Parcelable {
mIcon = b.mIcon;
mTitle = b.mTitle;
mText = b.mText;
+ mCategories = clone(b.mCategories);
mIntent = b.mIntent;
if (mIntent != null) {
final Bundle intentExtras = mIntent.getExtras();
@@ -181,6 +192,10 @@ public final class ShortcutInfo implements Parcelable {
updateTimestamp();
}
+ private <T> ArrayList<T> clone(List<T> source) {
+ return (source == null) ? null : new ArrayList<>(source);
+ }
+
/**
* Throws if any of the mandatory fields is not set.
*
@@ -202,17 +217,20 @@ public final class ShortcutInfo implements Parcelable {
mFlags = source.mFlags;
mLastChangedTimestamp = source.mLastChangedTimestamp;
+ // Just always keep it since it's cheep.
+ mIconResourceId = source.mIconResourceId;
+
if ((cloneFlags & CLONE_REMOVE_NON_KEY_INFO) == 0) {
mActivityComponent = source.mActivityComponent;
if ((cloneFlags & CLONE_REMOVE_ICON) == 0) {
mIcon = source.mIcon;
mBitmapPath = source.mBitmapPath;
- mIconResourceId = source.mIconResourceId;
}
mTitle = source.mTitle;
mText = source.mText;
+ mCategories = clone(source.mCategories);
if ((cloneFlags & CLONE_REMOVE_INTENT) == 0) {
mIntent = source.mIntent;
mIntentPersistableExtras = source.mIntentPersistableExtras;
@@ -262,6 +280,9 @@ public final class ShortcutInfo implements Parcelable {
if (source.mText != null) {
mText = source.mText;
}
+ if (source.mCategories != null) {
+ mCategories = clone(source.mCategories);
+ }
if (source.mIntent != null) {
mIntent = source.mIntent;
mIntentPersistableExtras = source.mIntentPersistableExtras;
@@ -325,6 +346,8 @@ public final class ShortcutInfo implements Parcelable {
private String mText;
+ private List<String> mCategories;
+
private Intent mIntent;
private int mWeight;
@@ -369,8 +392,9 @@ public final class ShortcutInfo implements Parcelable {
*
* <p>For performance reasons, icons will <b>NOT</b> be available on instances
* returned by {@link ShortcutManager} or {@link LauncherApps}. Launcher applications
- * need to use {@link LauncherApps#getShortcutIconFd(ShortcutInfo)}
- * and {@link LauncherApps#getShortcutIconResId(ShortcutInfo)}.
+ * can use {@link ShortcutInfo#getIconResourceId()} if {@link #hasIconResource()} is true.
+ * Otherwise, if {@link #hasIconFile()} is true, use
+ * {@link LauncherApps#getShortcutIconFd} to load the image.
*/
@NonNull
public Builder setIcon(Icon icon) {
@@ -403,6 +427,18 @@ public final class ShortcutInfo implements Parcelable {
}
/**
+ * Sets categories for a shortcut. Launcher applications may use this information to
+ * categorise shortcuts.
+ *
+ * @see #SHORTCUT_CATEGORY_CONVERSATION
+ */
+ @NonNull
+ public Builder setCategories(List<String> categories) {
+ mCategories = categories;
+ return this;
+ }
+
+ /**
* Sets the intent of a shortcut. This is a mandatory field. The extras must only contain
* persistable information. (See {@link PersistableBundle}).
*/
@@ -500,6 +536,14 @@ public final class ShortcutInfo implements Parcelable {
}
/**
+ * Return the categories.
+ */
+ @Nullable
+ public List<String> getCategories() {
+ return mCategories;
+ }
+
+ /**
* Return the intent.
*
* <p>All shortcuts must have an intent, but this method will return null when
@@ -662,7 +706,9 @@ public final class ShortcutInfo implements Parcelable {
mIconResourceId = iconResourceId;
}
- /** @hide */
+ /**
+ * Get the resource ID for the icon, valid only when {@link #hasIconResource()} } is true.
+ */
public int getIconResourceId() {
return mIconResourceId;
}
@@ -687,6 +733,8 @@ public final class ShortcutInfo implements Parcelable {
mIcon = source.readParcelable(cl);
mTitle = source.readString();
mText = source.readString();
+ mCategories = new ArrayList<>();
+ source.readStringList(mCategories);
mIntent = source.readParcelable(cl);
mIntentPersistableExtras = source.readParcelable(cl);
mWeight = source.readInt();
@@ -706,6 +754,7 @@ public final class ShortcutInfo implements Parcelable {
dest.writeParcelable(mIcon, flags);
dest.writeString(mTitle);
dest.writeString(mText);
+ dest.writeStringList(mCategories);
dest.writeParcelable(mIntent, flags);
dest.writeParcelable(mIntentPersistableExtras, flags);
dest.writeInt(mWeight);
@@ -770,6 +819,9 @@ public final class ShortcutInfo implements Parcelable {
sb.append(", text=");
sb.append(secure ? "***" : mText);
+ sb.append(", categories=");
+ sb.append(mCategories);
+
sb.append(", icon=");
sb.append(mIcon);
@@ -807,7 +859,7 @@ public final class ShortcutInfo implements Parcelable {
/** @hide */
public ShortcutInfo(
@UserIdInt int userId, String id, String packageName, ComponentName activityComponent,
- Icon icon, String title, String text, Intent intent,
+ Icon icon, String title, String text, List<String> categories, Intent intent,
PersistableBundle intentPersistableExtras,
int weight, PersistableBundle extras, long lastChangedTimestamp,
int flags, int iconResId, String bitmapPath) {
@@ -818,6 +870,7 @@ public final class ShortcutInfo implements Parcelable {
mIcon = icon;
mTitle = title;
mText = text;
+ mCategories = clone(categories);
mIntent = intent;
mIntentPersistableExtras = intentPersistableExtras;
mWeight = weight;
diff --git a/core/java/android/content/pm/ShortcutManager.java b/core/java/android/content/pm/ShortcutManager.java
index 919ccda91ba9..75803d3631a3 100644
--- a/core/java/android/content/pm/ShortcutManager.java
+++ b/core/java/android/content/pm/ShortcutManager.java
@@ -34,11 +34,11 @@ import java.util.List;
* <h3>Dynamic shortcuts and pinned shortcuts</h3>
*
* An application can publish shortcuts with {@link #setDynamicShortcuts(List)} and
- * {@link #addDynamicShortcut(ShortcutInfo)}. There can be at most
+ * {@link #addDynamicShortcuts(List)}. There can be at most
* {@link #getMaxDynamicShortcutCount()} number of dynamic shortcuts at a time from the same
* application.
- * A dynamic shortcut can be deleted with {@link #deleteDynamicShortcut(String)}, and apps
- * can also use {@link #deleteAllDynamicShortcuts()} to delete all dynamic shortcuts.
+ * A dynamic shortcut can be deleted with {@link #removeDynamicShortcuts(List)}, and apps
+ * can also use {@link #removeAllDynamicShortcuts()} to delete all dynamic shortcuts.
*
* <p>The shortcuts that are currently published by the above APIs are called "dynamic", because
* they can be removed by the creator application at any time. The user may "pin" dynamic shortcuts
@@ -61,11 +61,11 @@ import java.util.List;
*
* <h3>Rate limiting</h3>
*
- * Calls to {@link #setDynamicShortcuts(List)}, {@link #addDynamicShortcut(ShortcutInfo)},
+ * Calls to {@link #setDynamicShortcuts(List)}, {@link #addDynamicShortcuts(List)},
* and {@link #updateShortcuts(List)} will be
* rate-limited. An application can call these methods at most
* {@link #getRemainingCallCount()} times until the rate-limiting counter is reset,
- * which happens at a certain time every day.
+ * which happens every hour.
*
* <p>An application can use {@link #getRateLimitResetTime()} to get the next reset time.
*
@@ -153,10 +153,10 @@ public class ShortcutManager {
* @throws IllegalArgumentException if the caller application has already published the
* max number of dynamic shortcuts.
*/
- public boolean addDynamicShortcut(@NonNull ShortcutInfo shortcutInfo) {
+ public boolean addDynamicShortcuts(@NonNull List<ShortcutInfo> shortcutInfoList) {
try {
- return mService.addDynamicShortcut(
- mContext.getPackageName(), shortcutInfo, injectMyUserId());
+ return mService.addDynamicShortcuts(mContext.getPackageName(),
+ new ParceledListSlice(shortcutInfoList), injectMyUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -165,9 +165,10 @@ public class ShortcutManager {
/**
* Delete a single dynamic shortcut by ID.
*/
- public void deleteDynamicShortcut(@NonNull String shortcutId) {
+ public void removeDynamicShortcuts(@NonNull List<String> shortcutIds) {
try {
- mService.deleteDynamicShortcut(mContext.getPackageName(), shortcutId, injectMyUserId());
+ mService.removeDynamicShortcuts(mContext.getPackageName(), shortcutIds,
+ injectMyUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -176,9 +177,9 @@ public class ShortcutManager {
/**
* Delete all dynamic shortcuts from the caller application.
*/
- public void deleteAllDynamicShortcuts() {
+ public void removeAllDynamicShortcuts() {
try {
- mService.deleteAllDynamicShortcuts(mContext.getPackageName(), injectMyUserId());
+ mService.removeAllDynamicShortcuts(mContext.getPackageName(), injectMyUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 638be5167f86..59a522032b53 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -7793,13 +7793,13 @@ public final class Settings {
* ShortcutManager specific settings.
* This is encoded as a key=value list, separated by commas. Ex:
*
- * "reset_interval_sec=86400,max_daily_updates=5"
+ * "reset_interval_sec=86400,max_updates_per_interval=1"
*
* The following keys are supported:
*
* <pre>
* reset_interval_sec (long)
- * max_daily_updates (int)
+ * max_updates_per_interval (int)
* max_icon_dimension_dp (int, DP)
* max_icon_dimension_dp_lowram (int, DP)
* max_shortcuts (int)
diff --git a/services/core/java/com/android/server/pm/ShortcutPackage.java b/services/core/java/com/android/server/pm/ShortcutPackage.java
index 58559a53cb5a..b9b65ebc5ff8 100644
--- a/services/core/java/com/android/server/pm/ShortcutPackage.java
+++ b/services/core/java/com/android/server/pm/ShortcutPackage.java
@@ -28,6 +28,7 @@ import android.util.ArraySet;
import android.util.Slog;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.XmlUtils;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -37,7 +38,7 @@ import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
-import java.util.Collection;
+import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;
@@ -51,6 +52,7 @@ class ShortcutPackage extends ShortcutPackageItem {
private static final String TAG_INTENT_EXTRAS = "intent-extras";
private static final String TAG_EXTRAS = "extras";
private static final String TAG_SHORTCUT = "shortcut";
+ private static final String TAG_CATEGORIES = "categories";
private static final String ATTR_NAME = "name";
private static final String ATTR_DYNAMIC_COUNT = "dynamic-count";
@@ -67,6 +69,11 @@ class ShortcutPackage extends ShortcutPackageItem {
private static final String ATTR_ICON_RES = "icon-res";
private static final String ATTR_BITMAP_PATH = "bitmap-path";
+ private static final String NAME_CATEGORIES = "categories";
+
+ private static final String TAG_STRING_ARRAY_XMLUTILS = "string-array";
+ private static final String ATTR_NAME_XMLUTILS = "name";
+
/**
* All the shortcuts from the package, keyed on IDs.
*/
@@ -305,7 +312,7 @@ class ShortcutPackage extends ShortcutPackageItem {
* and return true. Otherwise just return false.
*/
public boolean tryApiCall(@NonNull ShortcutService s) {
- if (getApiCallCount(s) >= s.mMaxDailyUpdates) {
+ if (getApiCallCount(s) >= s.mMaxUpdatesPerInterval) {
return false;
}
mApiCallCount++;
@@ -485,6 +492,16 @@ class ShortcutPackage extends ShortcutPackageItem {
ShortcutService.writeAttr(out, ATTR_BITMAP_PATH, si.getBitmapPath());
}
+ {
+ final List<String> cat = si.getCategories();
+ if (cat != null && cat.size() > 0) {
+ out.startTag(null, TAG_CATEGORIES);
+ XmlUtils.writeStringArrayXml(cat.toArray(new String[cat.size()]),
+ NAME_CATEGORIES, out);
+ out.endTag(null, TAG_CATEGORIES);
+ }
+ }
+
ShortcutService.writeTagExtra(out, TAG_INTENT_EXTRAS,
si.getIntentPersistableExtras());
ShortcutService.writeTagExtra(out, TAG_EXTRAS, si.getExtras());
@@ -550,6 +567,7 @@ class ShortcutPackage extends ShortcutPackageItem {
int flags;
int iconRes;
String bitmapPath;
+ String[] categories = null;
id = ShortcutService.parseStringAttribute(parser, ATTR_ID);
activityComponent = ShortcutService.parseComponentNameAttribute(parser,
@@ -583,11 +601,21 @@ class ShortcutPackage extends ShortcutPackageItem {
case TAG_EXTRAS:
extras = PersistableBundle.restoreFromXml(parser);
continue;
+ case TAG_CATEGORIES:
+ // This just contains string-array.
+ continue;
+ case TAG_STRING_ARRAY_XMLUTILS:
+ if (NAME_CATEGORIES.equals(ShortcutService.parseStringAttribute(parser,
+ ATTR_NAME_XMLUTILS))) {
+ categories = XmlUtils.readThisStringArrayXml(parser, TAG_STRING_ARRAY_XMLUTILS, null);
+ }
+ continue;
}
throw ShortcutService.throwForInvalidTag(depth, tag);
}
return new ShortcutInfo(
- userId, id, packageName, activityComponent, /* icon =*/ null, title, text, intent,
+ userId, id, packageName, activityComponent, /* icon =*/ null, title, text,
+ (categories == null ? null : Arrays.asList(categories)), intent,
intentPersistableExtras, weight, extras, lastChangedTimestamp, flags,
iconRes, bitmapPath);
}
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index 1641e1dce169..ac6510ae57ac 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -126,10 +126,10 @@ public class ShortcutService extends IShortcutService.Stub {
static final boolean DEBUG_LOAD = false; // STOPSHIP if true
@VisibleForTesting
- static final long DEFAULT_RESET_INTERVAL_SEC = 24 * 60 * 60; // 1 day
+ static final long DEFAULT_RESET_INTERVAL_SEC = 60 * 60; // 1 hour
@VisibleForTesting
- static final int DEFAULT_MAX_DAILY_UPDATES = 10;
+ static final int DEFAULT_MAX_UPDATES_PER_INTERVAL = 2;
@VisibleForTesting
static final int DEFAULT_MAX_SHORTCUTS_PER_APP = 5;
@@ -180,7 +180,7 @@ public class ShortcutService extends IShortcutService.Stub {
/**
* Key name for the max number of modifying API calls per app for every interval. (int)
*/
- String KEY_MAX_DAILY_UPDATES = "max_daily_updates";
+ String KEY_MAX_UPDATES_PER_INTERVAL = "max_updates_per_interval";
/**
* Key name for the max icon dimensions in DP, for non-low-memory devices.
@@ -232,9 +232,9 @@ public class ShortcutService extends IShortcutService.Stub {
private int mMaxDynamicShortcuts;
/**
- * Max number of updating API calls that each application can make a day.
+ * Max number of updating API calls that each application can make during the interval.
*/
- int mMaxDailyUpdates;
+ int mMaxUpdatesPerInterval;
/**
* Actual throttling-reset interval. By default it's a day.
@@ -426,8 +426,8 @@ public class ShortcutService extends IShortcutService.Stub {
ConfigConstants.KEY_RESET_INTERVAL_SEC, DEFAULT_RESET_INTERVAL_SEC)
* 1000L);
- mMaxDailyUpdates = Math.max(0, (int) parser.getLong(
- ConfigConstants.KEY_MAX_DAILY_UPDATES, DEFAULT_MAX_DAILY_UPDATES));
+ mMaxUpdatesPerInterval = Math.max(0, (int) parser.getLong(
+ ConfigConstants.KEY_MAX_UPDATES_PER_INTERVAL, DEFAULT_MAX_UPDATES_PER_INTERVAL));
mMaxDynamicShortcuts = Math.max(0, (int) parser.getLong(
ConfigConstants.KEY_MAX_SHORTCUTS, DEFAULT_MAX_SHORTCUTS_PER_APP));
@@ -1319,10 +1319,13 @@ public class ShortcutService extends IShortcutService.Stub {
}
@Override
- public boolean addDynamicShortcut(String packageName, ShortcutInfo newShortcut,
+ public boolean addDynamicShortcuts(String packageName, ParceledListSlice shortcutInfoList,
@UserIdInt int userId) {
verifyCaller(packageName, userId);
+ final List<ShortcutInfo> newShortcuts = (List<ShortcutInfo>) shortcutInfoList.getList();
+ final int size = newShortcuts.size();
+
synchronized (mLock) {
final ShortcutPackage ps = getPackageShortcutsLocked(packageName, userId);
@@ -1330,12 +1333,15 @@ public class ShortcutService extends IShortcutService.Stub {
if (!ps.tryApiCall(this)) {
return false;
}
+ for (int i = 0; i < size; i++) {
+ final ShortcutInfo newShortcut = newShortcuts.get(i);
- // Validate the shortcut.
- fixUpIncomingShortcutInfo(newShortcut, /* forUpdate= */ false);
+ // Validate the shortcut.
+ fixUpIncomingShortcutInfo(newShortcut, /* forUpdate= */ false);
- // Add it.
- ps.addDynamicShortcut(this, newShortcut);
+ // Add it.
+ ps.addDynamicShortcut(this, newShortcut);
+ }
}
userPackageChanged(packageName, userId);
@@ -1343,19 +1349,22 @@ public class ShortcutService extends IShortcutService.Stub {
}
@Override
- public void deleteDynamicShortcut(String packageName, String shortcutId,
+ public void removeDynamicShortcuts(String packageName, List shortcutIds,
@UserIdInt int userId) {
verifyCaller(packageName, userId);
- Preconditions.checkStringNotEmpty(shortcutId, "shortcutId must be provided");
+ Preconditions.checkNotNull(shortcutIds, "shortcutIds must be provided");
synchronized (mLock) {
- getPackageShortcutsLocked(packageName, userId).deleteDynamicWithId(this, shortcutId);
+ for (int i = shortcutIds.size() - 1; i >= 0; i--) {
+ getPackageShortcutsLocked(packageName, userId).deleteDynamicWithId(this,
+ Preconditions.checkStringNotEmpty((String) shortcutIds.get(i)));
+ }
}
userPackageChanged(packageName, userId);
}
@Override
- public void deleteAllDynamicShortcuts(String packageName, @UserIdInt int userId) {
+ public void removeAllDynamicShortcuts(String packageName, @UserIdInt int userId) {
verifyCaller(packageName, userId);
synchronized (mLock) {
@@ -1409,7 +1418,7 @@ public class ShortcutService extends IShortcutService.Stub {
verifyCaller(packageName, userId);
synchronized (mLock) {
- return mMaxDailyUpdates
+ return mMaxUpdatesPerInterval
- getPackageShortcutsLocked(packageName, userId).getApiCallCount(this);
}
}
@@ -2079,8 +2088,8 @@ public class ShortcutService extends IShortcutService.Stub {
pw.println(mSaveDelayMillis);
pw.print(" resetInterval:");
pw.println(mResetInterval);
- pw.print(" maxDailyUpdates:");
- pw.println(mMaxDailyUpdates);
+ pw.print(" maxUpdatesPerInterval:");
+ pw.println(mMaxUpdatesPerInterval);
pw.print(" maxDynamicShortcuts:");
pw.println(mMaxDynamicShortcuts);
pw.println();
@@ -2423,8 +2432,8 @@ public class ShortcutService extends IShortcutService.Stub {
}
@VisibleForTesting
- int getMaxDailyUpdatesForTest() {
- return mMaxDailyUpdates;
+ int getMaxUpdatesPerIntervalForTest() {
+ return mMaxUpdatesPerInterval;
}
@VisibleForTesting
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest.java
index 2fd11da3adf3..ce02a79005ba 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest.java
@@ -216,7 +216,8 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
String injectShortcutManagerConstants() {
return ConfigConstants.KEY_RESET_INTERVAL_SEC + "=" + (INTERVAL / 1000) + ","
+ ConfigConstants.KEY_MAX_SHORTCUTS + "=" + MAX_SHORTCUTS + ","
- + ConfigConstants.KEY_MAX_DAILY_UPDATES + "=" + MAX_DAILY_UPDATES + ","
+ + ConfigConstants.KEY_MAX_UPDATES_PER_INTERVAL + "="
+ + MAX_UPDATES_PER_INTERVAL + ","
+ ConfigConstants.KEY_MAX_ICON_DIMENSION_DP + "=" + MAX_ICON_DIMENSION + ","
+ ConfigConstants.KEY_MAX_ICON_DIMENSION_DP_LOWRAM + "="
+ MAX_ICON_DIMENSION_LOWRAM + ","
@@ -465,7 +466,7 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
private static final int MAX_SHORTCUTS = 10;
- private static final int MAX_DAILY_UPDATES = 3;
+ private static final int MAX_UPDATES_PER_INTERVAL = 3;
private static final int MAX_ICON_DIMENSION = 128;
@@ -1074,7 +1075,7 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
assertResetTimes(START_TIME + INTERVAL, START_TIME + 2 * INTERVAL);
- // Advance further; 4 days since start.
+ // Advance further; 4 hours since start.
mInjectedCurrentTimeLillis = START_TIME + 4 * INTERVAL + 50;
assertResetTimes(START_TIME + 4 * INTERVAL, START_TIME + 5 * INTERVAL);
@@ -1111,14 +1112,14 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
mService.updateConfigurationLocked(
ConfigConstants.KEY_RESET_INTERVAL_SEC + "=123,"
+ ConfigConstants.KEY_MAX_SHORTCUTS + "=4,"
- + ConfigConstants.KEY_MAX_DAILY_UPDATES + "=5,"
+ + ConfigConstants.KEY_MAX_UPDATES_PER_INTERVAL + "=5,"
+ ConfigConstants.KEY_MAX_ICON_DIMENSION_DP + "=100,"
+ ConfigConstants.KEY_MAX_ICON_DIMENSION_DP_LOWRAM + "=50,"
+ ConfigConstants.KEY_ICON_FORMAT + "=WEBP,"
+ ConfigConstants.KEY_ICON_QUALITY + "=75");
assertEquals(123000, mService.getResetIntervalForTest());
assertEquals(4, mService.getMaxDynamicShortcutsForTest());
- assertEquals(5, mService.getMaxDailyUpdatesForTest());
+ assertEquals(5, mService.getMaxUpdatesPerIntervalForTest());
assertEquals(100, mService.getMaxIconDimensionForTest());
assertEquals(CompressFormat.WEBP, mService.getIconPersistFormatForTest());
assertEquals(75, mService.getIconPersistQualityForTest());
@@ -1134,8 +1135,8 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
assertEquals(ShortcutService.DEFAULT_MAX_SHORTCUTS_PER_APP,
mService.getMaxDynamicShortcutsForTest());
- assertEquals(ShortcutService.DEFAULT_MAX_DAILY_UPDATES,
- mService.getMaxDailyUpdatesForTest());
+ assertEquals(ShortcutService.DEFAULT_MAX_UPDATES_PER_INTERVAL,
+ mService.getMaxUpdatesPerIntervalForTest());
assertEquals(50, mService.getMaxIconDimensionForTest());
@@ -1154,7 +1155,7 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
/** Test for {@link android.content.pm.ShortcutManager#getRemainingCallCount()} */
public void testGetRemainingCallCount() {
- assertEquals(MAX_DAILY_UPDATES, mManager.getRemainingCallCount());
+ assertEquals(MAX_UPDATES_PER_INTERVAL, mManager.getRemainingCallCount());
}
/** Test for {@link android.content.pm.ShortcutManager#getRateLimitResetTime()} */
@@ -1241,61 +1242,71 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
mManager.getDynamicShortcuts()),
"shortcut1");
- assertTrue(mManager.addDynamicShortcut(si2));
+ assertTrue(mManager.addDynamicShortcuts(list(si2, si3)));
assertEquals(1, mManager.getRemainingCallCount());
assertShortcutIds(assertAllNotKeyFieldsOnly(
mManager.getDynamicShortcuts()),
- "shortcut1", "shortcut2");
+ "shortcut1", "shortcut2", "shortcut3");
- // Add with the same ID
- assertTrue(mManager.addDynamicShortcut(makeShortcut("shortcut1")));
+ // This should not crash. It'll still consume the quota.
+ assertTrue(mManager.addDynamicShortcuts(list()));
assertEquals(0, mManager.getRemainingCallCount());
assertShortcutIds(assertAllNotKeyFieldsOnly(
mManager.getDynamicShortcuts()),
- "shortcut1", "shortcut2");
+ "shortcut1", "shortcut2", "shortcut3");
+
+ mInjectedCurrentTimeLillis += INTERVAL; // reset
+
+ // Add with the same ID
+ assertTrue(mManager.addDynamicShortcuts(list(makeShortcut("shortcut1"))));
+ assertEquals(2, mManager.getRemainingCallCount());
+ assertShortcutIds(assertAllNotKeyFieldsOnly(
+ mManager.getDynamicShortcuts()),
+ "shortcut1", "shortcut2", "shortcut3");
// TODO Check max number
// TODO Check fields.
runWithCaller(CALLING_PACKAGE_2, USER_10, () -> {
- assertTrue(mManager.addDynamicShortcut(makeShortcut("s1")));
+ assertTrue(mManager.addDynamicShortcuts(list(makeShortcut("s1"))));
});
}
- public void testDeleteDynamicShortcut() {
+ public void testDeleteDynamicShortcuts() {
final ShortcutInfo si1 = makeShortcut("shortcut1");
final ShortcutInfo si2 = makeShortcut("shortcut2");
final ShortcutInfo si3 = makeShortcut("shortcut3");
+ final ShortcutInfo si4 = makeShortcut("shortcut4");
- assertTrue(mManager.setDynamicShortcuts(list(si1, si2, si3)));
+ assertTrue(mManager.setDynamicShortcuts(list(si1, si2, si3, si4)));
assertShortcutIds(assertAllNotKeyFieldsOnly(
mManager.getDynamicShortcuts()),
- "shortcut1", "shortcut2", "shortcut3");
+ "shortcut1", "shortcut2", "shortcut3", "shortcut4");
assertEquals(2, mManager.getRemainingCallCount());
- mManager.deleteDynamicShortcut("shortcut1");
+ mManager.removeDynamicShortcuts(list("shortcut1"));
assertShortcutIds(assertAllNotKeyFieldsOnly(
mManager.getDynamicShortcuts()),
- "shortcut2", "shortcut3");
+ "shortcut2", "shortcut3", "shortcut4");
- mManager.deleteDynamicShortcut("shortcut1");
+ mManager.removeDynamicShortcuts(list("shortcut1"));
assertShortcutIds(assertAllNotKeyFieldsOnly(
mManager.getDynamicShortcuts()),
- "shortcut2", "shortcut3");
+ "shortcut2", "shortcut3", "shortcut4");
- mManager.deleteDynamicShortcut("shortcutXXX");
+ mManager.removeDynamicShortcuts(list("shortcutXXX"));
assertShortcutIds(assertAllNotKeyFieldsOnly(
mManager.getDynamicShortcuts()),
- "shortcut2", "shortcut3");
+ "shortcut2", "shortcut3", "shortcut4");
- mManager.deleteDynamicShortcut("shortcut2");
+ mManager.removeDynamicShortcuts(list("shortcut2", "shortcut4"));
assertShortcutIds(assertAllNotKeyFieldsOnly(
mManager.getDynamicShortcuts()),
"shortcut3");
- mManager.deleteDynamicShortcut("shortcut3");
+ mManager.removeDynamicShortcuts(list("shortcut3"));
assertShortcutIds(assertAllNotKeyFieldsOnly(
mManager.getDynamicShortcuts()));
@@ -1315,7 +1326,7 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
assertEquals(2, mManager.getRemainingCallCount());
- mManager.deleteAllDynamicShortcuts();
+ mManager.removeAllDynamicShortcuts();
assertEquals(0, mManager.getDynamicShortcuts().size());
assertEquals(2, mManager.getRemainingCallCount());
@@ -1383,7 +1394,7 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
assertEquals(0, mManager.getRemainingCallCount());
assertEquals(START_TIME + INTERVAL * 2, mManager.getRateLimitResetTime());
- // 4 days later...
+ // 4 hours later...
mInjectedCurrentTimeLillis = START_TIME + 4 * INTERVAL;
assertTrue(mManager.setDynamicShortcuts(list(si1)));
assertEquals(2, mManager.getRemainingCallCount());
@@ -1791,13 +1802,13 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
getCallingUser());
});
runWithCaller(CALLING_PACKAGE_1, UserHandle.USER_SYSTEM, () -> {
- mManager.deleteDynamicShortcut("s1");
- mManager.deleteDynamicShortcut("s2");
+ mManager.removeDynamicShortcuts(list("s1"));
+ mManager.removeDynamicShortcuts(list("s2"));
});
runWithCaller(CALLING_PACKAGE_2, UserHandle.USER_SYSTEM, () -> {
- mManager.deleteDynamicShortcut("s1");
- mManager.deleteDynamicShortcut("s3");
- mManager.deleteDynamicShortcut("s5");
+ mManager.removeDynamicShortcuts(list("s1"));
+ mManager.removeDynamicShortcuts(list("s3"));
+ mManager.removeDynamicShortcuts(list("s5"));
});
runWithCaller(CALLING_PACKAGE_1, UserHandle.USER_SYSTEM, () -> {
assertShortcutIds(assertAllDynamic(
@@ -2089,7 +2100,7 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
// Delete some.
setCaller(CALLING_PACKAGE_1);
assertShortcutIds(mManager.getPinnedShortcuts(), "s2");
- mManager.deleteDynamicShortcut("s2");
+ mManager.removeDynamicShortcuts(list("s2"));
assertShortcutIds(mManager.getPinnedShortcuts(), "s2");
dumpsysOnLogcat();
@@ -2154,19 +2165,19 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
// Delete some.
runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
assertShortcutIds(mManager.getPinnedShortcuts(), "s2");
- mManager.deleteDynamicShortcut("s2");
+ mManager.removeDynamicShortcuts(list("s2"));
assertShortcutIds(mManager.getPinnedShortcuts(), "s2");
});
runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
assertShortcutIds(mManager.getPinnedShortcuts(), "s3", "s4");
- mManager.deleteDynamicShortcut("s3");
+ mManager.removeDynamicShortcuts(list("s3"));
assertShortcutIds(mManager.getPinnedShortcuts(), "s3", "s4");
});
runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
assertShortcutIds(mManager.getPinnedShortcuts() /* none */);
- mManager.deleteDynamicShortcut("s2");
+ mManager.removeDynamicShortcuts(list("s2"));
assertShortcutIds(mManager.getPinnedShortcuts() /* none */);
});
@@ -2218,7 +2229,7 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
// Delete some.
runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
assertShortcutIds(mManager.getPinnedShortcuts(), "s3");
- mManager.deleteDynamicShortcut("s3");
+ mManager.removeDynamicShortcuts(list("s3"));
assertShortcutIds(mManager.getPinnedShortcuts(), "s3");
});
@@ -2226,8 +2237,8 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
assertShortcutIds(mManager.getPinnedShortcuts(), "s1", "s2");
- mManager.deleteDynamicShortcut("s1");
- mManager.deleteDynamicShortcut("s3");
+ mManager.removeDynamicShortcuts(list("s1"));
+ mManager.removeDynamicShortcuts(list("s3"));
assertShortcutIds(mManager.getPinnedShortcuts(), "s1", "s2");
});
@@ -2336,13 +2347,13 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
// Delete all dynamic.
runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
- mManager.deleteAllDynamicShortcuts();
+ mManager.removeAllDynamicShortcuts();
assertEquals(0, mManager.getDynamicShortcuts().size());
assertShortcutIds(assertAllPinned(mManager.getPinnedShortcuts()), "s1", "s2", "s3");
});
runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
- mManager.deleteAllDynamicShortcuts();
+ mManager.removeAllDynamicShortcuts();
assertEquals(0, mManager.getDynamicShortcuts().size());
assertShortcutIds(assertAllPinned(mManager.getPinnedShortcuts()), "s2", "s1");
@@ -2377,7 +2388,7 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
});
// Re-publish s1.
runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
- assertTrue(mManager.addDynamicShortcut(makeShortcut("s1")));
+ assertTrue(mManager.addDynamicShortcuts(list(makeShortcut("s1"))));
assertShortcutIds(assertAllDynamic(mManager.getDynamicShortcuts()), "s1");
assertShortcutIds(assertAllPinned(mManager.getPinnedShortcuts()), "s1", "s2", "s3");
@@ -2979,7 +2990,7 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
// Just to make it complicated, delete some.
setCaller(CALLING_PACKAGE_1);
- mManager.deleteDynamicShortcut("s2");
+ mManager.removeDynamicShortcuts(list("s2"));
// intent and check.
setCaller(LAUNCHER_1);
@@ -3051,11 +3062,11 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
any(UserHandle.class)
);
- // Test for addDynamicShortcut.
+ // Test for addDynamicShortcuts.
reset(c0);
runWithCaller(CALLING_PACKAGE_1, UserHandle.USER_SYSTEM, () -> {
- dumpsysOnLogcat("before addDynamicShortcut");
- assertTrue(mManager.addDynamicShortcut(makeShortcut("s4")));
+ dumpsysOnLogcat("before addDynamicShortcuts");
+ assertTrue(mManager.addDynamicShortcuts(list(makeShortcut("s4"))));
});
waitOnMainThread();
@@ -3071,7 +3082,7 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
// Test for remove
reset(c0);
runWithCaller(CALLING_PACKAGE_1, UserHandle.USER_SYSTEM, () -> {
- mManager.deleteDynamicShortcut("s1");
+ mManager.removeDynamicShortcuts(list("s1"));
});
waitOnMainThread();
@@ -3104,7 +3115,7 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
// Test for deleteAll
reset(c0);
runWithCaller(CALLING_PACKAGE_1, UserHandle.USER_SYSTEM, () -> {
- mManager.deleteAllDynamicShortcuts();
+ mManager.removeAllDynamicShortcuts();
});
waitOnMainThread();
@@ -3178,7 +3189,7 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
resetAll(all);
runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
- mManager.deleteDynamicShortcut("x");
+ mManager.removeDynamicShortcuts(list());
});
waitOnMainThread();
@@ -3195,7 +3206,7 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
resetAll(all);
runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
- mManager.deleteDynamicShortcut("x");
+ mManager.removeDynamicShortcuts(list());
});
waitOnMainThread();
@@ -3213,7 +3224,7 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
resetAll(all);
runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
- mManager.deleteDynamicShortcut("x");
+ mManager.removeDynamicShortcuts(list());
});
waitOnMainThread();
@@ -3233,7 +3244,7 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
resetAll(all);
runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
- mManager.deleteDynamicShortcut("x");
+ mManager.removeDynamicShortcuts(list());
});
waitOnMainThread();
@@ -3253,7 +3264,7 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
resetAll(all);
runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
- mManager.deleteDynamicShortcut("x");
+ mManager.removeDynamicShortcuts(list());
});
waitOnMainThread();
@@ -3477,16 +3488,16 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
// Remove all dynamic shortcuts; now all shortcuts are just pinned.
runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
- mManager.deleteAllDynamicShortcuts();
+ mManager.removeAllDynamicShortcuts();
});
runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
- mManager.deleteAllDynamicShortcuts();
+ mManager.removeAllDynamicShortcuts();
});
runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
- mManager.deleteAllDynamicShortcuts();
+ mManager.removeAllDynamicShortcuts();
});
runWithCaller(CALLING_PACKAGE_2, USER_10, () -> {
- mManager.deleteAllDynamicShortcuts();
+ mManager.removeAllDynamicShortcuts();
});
@@ -4009,22 +4020,22 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
public void testHandlePackageDelete() {
setCaller(CALLING_PACKAGE_1, USER_0);
- assertTrue(mManager.addDynamicShortcut(makeShortcut("s1")));
+ assertTrue(mManager.addDynamicShortcuts(list(makeShortcut("s1"))));
setCaller(CALLING_PACKAGE_2, USER_0);
- assertTrue(mManager.addDynamicShortcut(makeShortcut("s1")));
+ assertTrue(mManager.addDynamicShortcuts(list(makeShortcut("s1"))));
setCaller(CALLING_PACKAGE_3, USER_0);
- assertTrue(mManager.addDynamicShortcut(makeShortcut("s1")));
+ assertTrue(mManager.addDynamicShortcuts(list(makeShortcut("s1"))));
setCaller(CALLING_PACKAGE_1, USER_10);
- assertTrue(mManager.addDynamicShortcut(makeShortcut("s1")));
+ assertTrue(mManager.addDynamicShortcuts(list(makeShortcut("s1"))));
setCaller(CALLING_PACKAGE_2, USER_10);
- assertTrue(mManager.addDynamicShortcut(makeShortcut("s1")));
+ assertTrue(mManager.addDynamicShortcuts(list(makeShortcut("s1"))));
setCaller(CALLING_PACKAGE_3, USER_10);
- assertTrue(mManager.addDynamicShortcut(makeShortcut("s1")));
+ assertTrue(mManager.addDynamicShortcuts(list(makeShortcut("s1"))));
assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_0));
assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_0));
@@ -4980,6 +4991,7 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
.setTitle("title")
.setText("text")
.setIntent(makeIntent("action", ShortcutActivity.class, "key", "val"))
+ .setCategories(list(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"))
.setWeight(123)
.setExtras(pb)
.build();
@@ -4995,6 +5007,7 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
assertEquals("content://a.b.c/", si.getIcon().getUriString());
assertEquals("title", si.getTitle());
assertEquals("text", si.getText());
+ assertEquals(list(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"), si.getCategories());
assertEquals("action", si.getIntent().getAction());
assertEquals("val", si.getIntent().getStringExtra("key"));
assertEquals(123, si.getWeight());
@@ -5016,6 +5029,7 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
.setIcon(Icon.createWithContentUri("content://a.b.c/"))
.setTitle("title")
.setText("text")
+ .setCategories(list(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"))
.setIntent(makeIntent("action", ShortcutActivity.class, "key", "val"))
.setWeight(123)
.setExtras(pb)
@@ -5034,6 +5048,7 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
assertEquals("content://a.b.c/", si.getIcon().getUriString());
assertEquals("title", si.getTitle());
assertEquals("text", si.getText());
+ assertEquals(list(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"), si.getCategories());
assertEquals("action", si.getIntent().getAction());
assertEquals("val", si.getIntent().getStringExtra("key"));
assertEquals(123, si.getWeight());
@@ -5051,6 +5066,7 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
assertEquals(null, si.getIcon());
assertEquals("title", si.getTitle());
assertEquals("text", si.getText());
+ assertEquals(list(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"), si.getCategories());
assertEquals("action", si.getIntent().getAction());
assertEquals("val", si.getIntent().getStringExtra("key"));
assertEquals(123, si.getWeight());
@@ -5058,7 +5074,8 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
assertEquals(ShortcutInfo.FLAG_PINNED, si.getFlags());
assertEquals(null, si.getBitmapPath());
- assertEquals(0, si.getIconResourceId());
+
+ assertEquals(456, si.getIconResourceId());
si = sorig.clone(ShortcutInfo.CLONE_REMOVE_FOR_LAUNCHER);
@@ -5068,13 +5085,15 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
assertEquals(null, si.getIcon());
assertEquals("title", si.getTitle());
assertEquals("text", si.getText());
+ assertEquals(list(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"), si.getCategories());
assertEquals(null, si.getIntent());
assertEquals(123, si.getWeight());
assertEquals(1, si.getExtras().getInt("k"));
assertEquals(ShortcutInfo.FLAG_PINNED, si.getFlags());
assertEquals(null, si.getBitmapPath());
- assertEquals(0, si.getIconResourceId());
+
+ assertEquals(456, si.getIconResourceId());
si = sorig.clone(ShortcutInfo.CLONE_REMOVE_NON_KEY_INFO);
@@ -5084,13 +5103,56 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
assertEquals(null, si.getIcon());
assertEquals(null, si.getTitle());
assertEquals(null, si.getText());
+ assertEquals(null, si.getCategories());
assertEquals(null, si.getIntent());
assertEquals(0, si.getWeight());
assertEquals(null, si.getExtras());
assertEquals(ShortcutInfo.FLAG_PINNED | ShortcutInfo.FLAG_KEY_FIELDS_ONLY, si.getFlags());
assertEquals(null, si.getBitmapPath());
- assertEquals(0, si.getIconResourceId());
+
+ assertEquals(456, si.getIconResourceId());
+ }
+
+ public void testShortcutInfoClone_minimum() {
+ PersistableBundle pb = new PersistableBundle();
+ pb.putInt("k", 1);
+ ShortcutInfo sorig = new ShortcutInfo.Builder(getTestContext())
+ .setId("id")
+ .setTitle("title")
+ .setIntent(makeIntent("action", ShortcutActivity.class))
+ .build();
+ ShortcutInfo si = sorig.clone(/* clone flags*/ 0);
+
+ assertEquals(getTestContext().getPackageName(), si.getPackageName());
+ assertEquals("id", si.getId());
+ assertEquals("title", si.getTitle());
+ assertEquals("action", si.getIntent().getAction());
+ assertEquals(null, si.getCategories());
+
+ si = sorig.clone(ShortcutInfo.CLONE_REMOVE_FOR_CREATOR);
+
+ assertEquals(getTestContext().getPackageName(), si.getPackageName());
+ assertEquals("id", si.getId());
+ assertEquals("title", si.getTitle());
+ assertEquals("action", si.getIntent().getAction());
+ assertEquals(null, si.getCategories());
+
+ si = sorig.clone(ShortcutInfo.CLONE_REMOVE_FOR_LAUNCHER);
+
+ assertEquals(getTestContext().getPackageName(), si.getPackageName());
+ assertEquals("id", si.getId());
+ assertEquals("title", si.getTitle());
+ assertEquals(null, si.getIntent());
+ assertEquals(null, si.getCategories());
+
+ si = sorig.clone(ShortcutInfo.CLONE_REMOVE_NON_KEY_INFO);
+
+ assertEquals(getTestContext().getPackageName(), si.getPackageName());
+ assertEquals("id", si.getId());
+ assertEquals(null, si.getTitle());
+ assertEquals(null, si.getIntent());
+ assertEquals(null, si.getCategories());
}
public void testShortcutInfoCopyNonNullFieldsFrom() throws InterruptedException {
@@ -5102,6 +5164,7 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
.setIcon(Icon.createWithContentUri("content://a.b.c/"))
.setTitle("title")
.setText("text")
+ .setCategories(list(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"))
.setIntent(makeIntent("action", ShortcutActivity.class, "key", "val"))
.setWeight(123)
.setExtras(pb)
@@ -5115,38 +5178,57 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
si = sorig.clone(/* flags=*/ 0);
si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
.setActivityComponent(new ComponentName("x", "y")).build());
+ assertEquals("text", si.getText());
assertEquals(new ComponentName("x", "y"), si.getActivityComponent());
si = sorig.clone(/* flags=*/ 0);
si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
.setIcon(Icon.createWithContentUri("content://x.y.z/")).build());
+ assertEquals("text", si.getText());
assertEquals("content://x.y.z/", si.getIcon().getUriString());
si = sorig.clone(/* flags=*/ 0);
si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
.setTitle("xyz").build());
+ assertEquals("text", si.getText());
assertEquals("xyz", si.getTitle());
si = sorig.clone(/* flags=*/ 0);
si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
.setText("xxx").build());
+ assertEquals(123, si.getWeight());
assertEquals("xxx", si.getText());
si = sorig.clone(/* flags=*/ 0);
si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
+ .setCategories(list()).build());
+ assertEquals("text", si.getText());
+ assertEquals(list(), si.getCategories());
+
+ si = sorig.clone(/* flags=*/ 0);
+ si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
+ .setCategories(list("x")).build());
+ assertEquals("text", si.getText());
+ assertEquals(list("x"), si.getCategories());
+
+ si = sorig.clone(/* flags=*/ 0);
+ si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
.setIntent(makeIntent("action2", ShortcutActivity.class)).build());
+ assertEquals("text", si.getText());
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("text", si.getText());
assertEquals("action3", si.getIntent().getAction());
assertEquals("x", si.getIntent().getStringExtra("key"));
si = sorig.clone(/* flags=*/ 0);
si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
.setWeight(999).build());
+ assertEquals("text", si.getText());
assertEquals(999, si.getWeight());
@@ -5156,8 +5238,11 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
si = sorig.clone(/* flags=*/ 0);
si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
.setExtras(pb2).build());
+ assertEquals("text", si.getText());
assertEquals(99, si.getExtras().getInt("x"));
+ // Make sure the timestamp gets updated too.
+
final long timestamp = si.getLastChangedTimestamp();
Thread.sleep(2);
@@ -5181,12 +5266,13 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
.setIcon(bmp32x32)
.setTitle("title")
.setText("text")
+ .setCategories(list(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"))
.setIntent(makeIntent("action", ShortcutActivity.class, "key", "val"))
.setWeight(123)
.setExtras(pb)
.build();
- mManager.addDynamicShortcut(sorig);
+ mManager.addDynamicShortcuts(list(sorig));
Thread.sleep(2);
final long now = System.currentTimeMillis();
@@ -5207,6 +5293,7 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
assertEquals(null, si.getIcon());
assertEquals("title", si.getTitle());
assertEquals("text", si.getText());
+ assertEquals(list(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"), si.getCategories());
assertEquals("action", si.getIntent().getAction());
assertEquals("val", si.getIntent().getStringExtra("key"));
assertEquals(123, si.getWeight());
@@ -5232,12 +5319,13 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
.setIcon(bmp32x32)
.setTitle("title")
.setText("text")
+ .setCategories(list(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"))
.setIntent(makeIntent("action", ShortcutActivity.class, "key", "val"))
.setWeight(123)
.setExtras(pb)
.build();
- mManager.addDynamicShortcut(sorig);
+ mManager.addDynamicShortcuts(list(sorig));
// Dynamic shortcuts won't be backed up, so we need to pin it.
setCaller(LAUNCHER_1, USER_0);
@@ -5246,6 +5334,8 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
// Do backup & restore.
backupAndRestore();
+ mService.handleUnlockUser(USER_0); // Load user-0.
+
ShortcutInfo si;
si = mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "id", USER_0);
@@ -5255,6 +5345,7 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
assertEquals(null, si.getIcon());
assertEquals("title", si.getTitle());
assertEquals("text", si.getText());
+ assertEquals(list(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"), si.getCategories());
assertEquals("action", si.getIntent().getAction());
assertEquals("val", si.getIntent().getStringExtra("key"));
assertEquals(123, si.getWeight());