Introducing ShortcutManager
What's supported: - Most APIs are implemented, except for SM.updateShortcuts(), the icon APIs in LA, and LA.startShortcut(). - Persisting information, except for icons - Throttling In addition, now PersistableBundle has a public copy constructor from a Bundle. (Do we want to @hide it?) TODOs: - Add icon support - Implement missing APIs - Listen to PACKAGE_* broadcasts and do clean-up - Support multi-launcher apps (pinned shortcuts per launcher) - Dev option to reset throttling - Load throttling config from Settings - Backup & restore - Figure out LauncherApps permissions (BIND_APPWIDGETS??) - Other minor TODOs in the code - Better javadoc Note: This requires Idf2f9ae816e1f3d822a6286a4cf738c14e29a45e Bug 27325877 Change-Id: Ia5aa555a4759df5f79a859338f1dc5e624cd0e35
This commit is contained in:
@@ -149,6 +149,7 @@ LOCAL_SRC_FILES += \
|
||||
core/java/android/content/pm/IPackageMoveObserver.aidl \
|
||||
core/java/android/content/pm/IPackageStatsObserver.aidl \
|
||||
core/java/android/content/pm/IOnPermissionsChangeListener.aidl \
|
||||
core/java/android/content/pm/IShortcutService.aidl \
|
||||
core/java/android/database/IContentObserver.aidl \
|
||||
../av/camera/aidl/android/hardware/ICameraService.aidl \
|
||||
../av/camera/aidl/android/hardware/ICameraServiceListener.aidl \
|
||||
@@ -650,6 +651,7 @@ aidl_files := \
|
||||
frameworks/base/core/java/android/content/pm/ProviderInfo.aidl \
|
||||
frameworks/base/core/java/android/content/pm/PackageStats.aidl \
|
||||
frameworks/base/core/java/android/content/pm/PermissionGroupInfo.aidl \
|
||||
frameworks/base/core/java/android/content/pm/ShortcutInfo.aidl \
|
||||
frameworks/base/core/java/android/content/pm/LabeledIntent.aidl \
|
||||
frameworks/base/core/java/android/content/ComponentName.aidl \
|
||||
frameworks/base/core/java/android/content/SyncStats.aidl \
|
||||
|
||||
@@ -8138,6 +8138,7 @@ package android.content {
|
||||
field public static final java.lang.String RESTRICTIONS_SERVICE = "restrictions";
|
||||
field public static final java.lang.String SEARCH_SERVICE = "search";
|
||||
field public static final java.lang.String SENSOR_SERVICE = "sensor";
|
||||
field public static final java.lang.String SHORTCUT_SERVICE = "shortcut";
|
||||
field public static final java.lang.String STORAGE_SERVICE = "storage";
|
||||
field public static final java.lang.String TELECOM_SERVICE = "telecom";
|
||||
field public static final java.lang.String TELEPHONY_SERVICE = "phone";
|
||||
@@ -9443,13 +9444,19 @@ 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.content.pm.ApplicationInfo getApplicationInfo(java.lang.String, int, android.os.UserHandle);
|
||||
method public android.os.ParcelFileDescriptor getShortcutIconFd(android.content.pm.ShortcutInfo, android.os.UserHandle);
|
||||
method public int getShortcutIconResId(android.content.pm.ShortcutInfo, android.os.UserHandle);
|
||||
method public java.util.List<android.content.pm.ShortcutInfo> getShortcutInfo(java.lang.String, java.util.List<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 isActivityEnabled(android.content.ComponentName, android.os.UserHandle);
|
||||
method public boolean isPackageEnabled(java.lang.String, android.os.UserHandle);
|
||||
method public void pinShortcuts(java.lang.String, java.util.List<java.lang.String>, android.os.UserHandle);
|
||||
method public void registerCallback(android.content.pm.LauncherApps.Callback);
|
||||
method public void registerCallback(android.content.pm.LauncherApps.Callback, android.os.Handler);
|
||||
method public android.content.pm.LauncherActivityInfo resolveActivity(android.content.Intent, android.os.UserHandle);
|
||||
method public void startAppDetailsActivity(android.content.ComponentName, android.os.UserHandle, android.graphics.Rect, android.os.Bundle);
|
||||
method public void startMainActivity(android.content.ComponentName, android.os.UserHandle, android.graphics.Rect, android.os.Bundle);
|
||||
method public void startShortcut(android.content.pm.ShortcutInfo, android.graphics.Rect, android.os.Bundle, android.os.UserHandle);
|
||||
method public void unregisterCallback(android.content.pm.LauncherApps.Callback);
|
||||
}
|
||||
|
||||
@@ -9462,6 +9469,18 @@ package android.content.pm {
|
||||
method public void onPackagesSuspended(java.lang.String[], android.os.UserHandle);
|
||||
method public abstract void onPackagesUnavailable(java.lang.String[], android.os.UserHandle, boolean);
|
||||
method public void onPackagesUnsuspended(java.lang.String[], android.os.UserHandle);
|
||||
method public void onShortcutsChanged(java.lang.String, java.util.List<android.content.pm.ShortcutInfo>, android.os.UserHandle);
|
||||
}
|
||||
|
||||
public static class LauncherApps.ShortcutQuery {
|
||||
ctor public LauncherApps.ShortcutQuery();
|
||||
method public void setActivity(android.content.ComponentName);
|
||||
method public void setChangedSince(long);
|
||||
method public void setPackage(java.lang.String);
|
||||
method public void setQueryFlags(int);
|
||||
field public static final int FLAG_GET_DYNAMIC = 1; // 0x1
|
||||
field public static final int FLAG_GET_KEY_FIELDS_ONLY = 4; // 0x4
|
||||
field public static final int FLAG_GET_PINNED = 2; // 0x2
|
||||
}
|
||||
|
||||
public class PackageInfo implements android.os.Parcelable {
|
||||
@@ -9961,6 +9980,56 @@ package android.content.pm {
|
||||
field public java.lang.String permission;
|
||||
}
|
||||
|
||||
public class ShortcutInfo implements android.os.Parcelable {
|
||||
method public int describeContents();
|
||||
method public android.content.ComponentName getActivityComponent();
|
||||
method public android.os.PersistableBundle getExtras();
|
||||
method public java.lang.String getId();
|
||||
method public android.content.Intent getIntent();
|
||||
method public long getLastChangedTimestamp();
|
||||
method public java.lang.String getPackageName();
|
||||
method public java.lang.String getTitle();
|
||||
method public int getWeight();
|
||||
method public boolean hasIconFile();
|
||||
method public boolean hasIconResource();
|
||||
method public boolean isDynamic();
|
||||
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_DYNAMIC = 1; // 0x1
|
||||
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_PINNED = 2; // 0x2
|
||||
}
|
||||
|
||||
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 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 setTitle(java.lang.String);
|
||||
method public android.content.pm.ShortcutInfo.Builder setWeight(int);
|
||||
}
|
||||
|
||||
public class ShortcutManager {
|
||||
method public boolean addDynamicShortcut(android.content.pm.ShortcutInfo);
|
||||
method public void deleteAllDynamicShortcuts();
|
||||
method public void deleteDynamicShortcut(java.lang.String);
|
||||
method public java.util.List<android.content.pm.ShortcutInfo> getDynamicShortcuts();
|
||||
method public int getMaxDynamicShortcutCount();
|
||||
method public java.util.List<android.content.pm.ShortcutInfo> getPinnedShortcuts();
|
||||
method public long getRateLimitResetTime();
|
||||
method public int getRemainingCallCount();
|
||||
method public boolean setDynamicShortcuts(java.util.List<android.content.pm.ShortcutInfo>);
|
||||
method public boolean updateShortcuts(java.util.List<android.content.pm.ShortcutInfo>);
|
||||
}
|
||||
|
||||
public class Signature implements android.os.Parcelable {
|
||||
ctor public Signature(byte[]);
|
||||
ctor public Signature(java.lang.String);
|
||||
@@ -29003,6 +29072,7 @@ package android.os {
|
||||
ctor public PersistableBundle();
|
||||
ctor public PersistableBundle(int);
|
||||
ctor public PersistableBundle(android.os.PersistableBundle);
|
||||
ctor public PersistableBundle(android.os.Bundle);
|
||||
method public java.lang.Object clone();
|
||||
method public int describeContents();
|
||||
method public android.os.PersistableBundle getPersistableBundle(java.lang.String);
|
||||
|
||||
@@ -8444,6 +8444,7 @@ package android.content {
|
||||
field public static final java.lang.String RESTRICTIONS_SERVICE = "restrictions";
|
||||
field public static final java.lang.String SEARCH_SERVICE = "search";
|
||||
field public static final java.lang.String SENSOR_SERVICE = "sensor";
|
||||
field public static final java.lang.String SHORTCUT_SERVICE = "shortcut";
|
||||
field public static final java.lang.String STORAGE_SERVICE = "storage";
|
||||
field public static final java.lang.String TELECOM_SERVICE = "telecom";
|
||||
field public static final java.lang.String TELEPHONY_SERVICE = "phone";
|
||||
@@ -9777,13 +9778,19 @@ 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.content.pm.ApplicationInfo getApplicationInfo(java.lang.String, int, android.os.UserHandle);
|
||||
method public android.os.ParcelFileDescriptor getShortcutIconFd(android.content.pm.ShortcutInfo, android.os.UserHandle);
|
||||
method public int getShortcutIconResId(android.content.pm.ShortcutInfo, android.os.UserHandle);
|
||||
method public java.util.List<android.content.pm.ShortcutInfo> getShortcutInfo(java.lang.String, java.util.List<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 isActivityEnabled(android.content.ComponentName, android.os.UserHandle);
|
||||
method public boolean isPackageEnabled(java.lang.String, android.os.UserHandle);
|
||||
method public void pinShortcuts(java.lang.String, java.util.List<java.lang.String>, android.os.UserHandle);
|
||||
method public void registerCallback(android.content.pm.LauncherApps.Callback);
|
||||
method public void registerCallback(android.content.pm.LauncherApps.Callback, android.os.Handler);
|
||||
method public android.content.pm.LauncherActivityInfo resolveActivity(android.content.Intent, android.os.UserHandle);
|
||||
method public void startAppDetailsActivity(android.content.ComponentName, android.os.UserHandle, android.graphics.Rect, android.os.Bundle);
|
||||
method public void startMainActivity(android.content.ComponentName, android.os.UserHandle, android.graphics.Rect, android.os.Bundle);
|
||||
method public void startShortcut(android.content.pm.ShortcutInfo, android.graphics.Rect, android.os.Bundle, android.os.UserHandle);
|
||||
method public void unregisterCallback(android.content.pm.LauncherApps.Callback);
|
||||
}
|
||||
|
||||
@@ -9796,6 +9803,18 @@ package android.content.pm {
|
||||
method public void onPackagesSuspended(java.lang.String[], android.os.UserHandle);
|
||||
method public abstract void onPackagesUnavailable(java.lang.String[], android.os.UserHandle, boolean);
|
||||
method public void onPackagesUnsuspended(java.lang.String[], android.os.UserHandle);
|
||||
method public void onShortcutsChanged(java.lang.String, java.util.List<android.content.pm.ShortcutInfo>, android.os.UserHandle);
|
||||
}
|
||||
|
||||
public static class LauncherApps.ShortcutQuery {
|
||||
ctor public LauncherApps.ShortcutQuery();
|
||||
method public void setActivity(android.content.ComponentName);
|
||||
method public void setChangedSince(long);
|
||||
method public void setPackage(java.lang.String);
|
||||
method public void setQueryFlags(int);
|
||||
field public static final int FLAG_GET_DYNAMIC = 1; // 0x1
|
||||
field public static final int FLAG_GET_KEY_FIELDS_ONLY = 4; // 0x4
|
||||
field public static final int FLAG_GET_PINNED = 2; // 0x2
|
||||
}
|
||||
|
||||
public class PackageInfo implements android.os.Parcelable {
|
||||
@@ -10355,6 +10374,56 @@ package android.content.pm {
|
||||
field public java.lang.String permission;
|
||||
}
|
||||
|
||||
public class ShortcutInfo implements android.os.Parcelable {
|
||||
method public int describeContents();
|
||||
method public android.content.ComponentName getActivityComponent();
|
||||
method public android.os.PersistableBundle getExtras();
|
||||
method public java.lang.String getId();
|
||||
method public android.content.Intent getIntent();
|
||||
method public long getLastChangedTimestamp();
|
||||
method public java.lang.String getPackageName();
|
||||
method public java.lang.String getTitle();
|
||||
method public int getWeight();
|
||||
method public boolean hasIconFile();
|
||||
method public boolean hasIconResource();
|
||||
method public boolean isDynamic();
|
||||
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_DYNAMIC = 1; // 0x1
|
||||
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_PINNED = 2; // 0x2
|
||||
}
|
||||
|
||||
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 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 setTitle(java.lang.String);
|
||||
method public android.content.pm.ShortcutInfo.Builder setWeight(int);
|
||||
}
|
||||
|
||||
public class ShortcutManager {
|
||||
method public boolean addDynamicShortcut(android.content.pm.ShortcutInfo);
|
||||
method public void deleteAllDynamicShortcuts();
|
||||
method public void deleteDynamicShortcut(java.lang.String);
|
||||
method public java.util.List<android.content.pm.ShortcutInfo> getDynamicShortcuts();
|
||||
method public int getMaxDynamicShortcutCount();
|
||||
method public java.util.List<android.content.pm.ShortcutInfo> getPinnedShortcuts();
|
||||
method public long getRateLimitResetTime();
|
||||
method public int getRemainingCallCount();
|
||||
method public boolean setDynamicShortcuts(java.util.List<android.content.pm.ShortcutInfo>);
|
||||
method public boolean updateShortcuts(java.util.List<android.content.pm.ShortcutInfo>);
|
||||
}
|
||||
|
||||
public class Signature implements android.os.Parcelable {
|
||||
ctor public Signature(byte[]);
|
||||
ctor public Signature(java.lang.String);
|
||||
@@ -31288,6 +31357,7 @@ package android.os {
|
||||
ctor public PersistableBundle();
|
||||
ctor public PersistableBundle(int);
|
||||
ctor public PersistableBundle(android.os.PersistableBundle);
|
||||
ctor public PersistableBundle(android.os.Bundle);
|
||||
method public java.lang.Object clone();
|
||||
method public int describeContents();
|
||||
method public android.os.PersistableBundle getPersistableBundle(java.lang.String);
|
||||
|
||||
@@ -8144,6 +8144,7 @@ package android.content {
|
||||
field public static final java.lang.String RESTRICTIONS_SERVICE = "restrictions";
|
||||
field public static final java.lang.String SEARCH_SERVICE = "search";
|
||||
field public static final java.lang.String SENSOR_SERVICE = "sensor";
|
||||
field public static final java.lang.String SHORTCUT_SERVICE = "shortcut";
|
||||
field public static final java.lang.String STORAGE_SERVICE = "storage";
|
||||
field public static final java.lang.String TELECOM_SERVICE = "telecom";
|
||||
field public static final java.lang.String TELEPHONY_SERVICE = "phone";
|
||||
@@ -9452,13 +9453,19 @@ 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.content.pm.ApplicationInfo getApplicationInfo(java.lang.String, int, android.os.UserHandle);
|
||||
method public android.os.ParcelFileDescriptor getShortcutIconFd(android.content.pm.ShortcutInfo, android.os.UserHandle);
|
||||
method public int getShortcutIconResId(android.content.pm.ShortcutInfo, android.os.UserHandle);
|
||||
method public java.util.List<android.content.pm.ShortcutInfo> getShortcutInfo(java.lang.String, java.util.List<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 isActivityEnabled(android.content.ComponentName, android.os.UserHandle);
|
||||
method public boolean isPackageEnabled(java.lang.String, android.os.UserHandle);
|
||||
method public void pinShortcuts(java.lang.String, java.util.List<java.lang.String>, android.os.UserHandle);
|
||||
method public void registerCallback(android.content.pm.LauncherApps.Callback);
|
||||
method public void registerCallback(android.content.pm.LauncherApps.Callback, android.os.Handler);
|
||||
method public android.content.pm.LauncherActivityInfo resolveActivity(android.content.Intent, android.os.UserHandle);
|
||||
method public void startAppDetailsActivity(android.content.ComponentName, android.os.UserHandle, android.graphics.Rect, android.os.Bundle);
|
||||
method public void startMainActivity(android.content.ComponentName, android.os.UserHandle, android.graphics.Rect, android.os.Bundle);
|
||||
method public void startShortcut(android.content.pm.ShortcutInfo, android.graphics.Rect, android.os.Bundle, android.os.UserHandle);
|
||||
method public void unregisterCallback(android.content.pm.LauncherApps.Callback);
|
||||
}
|
||||
|
||||
@@ -9471,6 +9478,18 @@ package android.content.pm {
|
||||
method public void onPackagesSuspended(java.lang.String[], android.os.UserHandle);
|
||||
method public abstract void onPackagesUnavailable(java.lang.String[], android.os.UserHandle, boolean);
|
||||
method public void onPackagesUnsuspended(java.lang.String[], android.os.UserHandle);
|
||||
method public void onShortcutsChanged(java.lang.String, java.util.List<android.content.pm.ShortcutInfo>, android.os.UserHandle);
|
||||
}
|
||||
|
||||
public static class LauncherApps.ShortcutQuery {
|
||||
ctor public LauncherApps.ShortcutQuery();
|
||||
method public void setActivity(android.content.ComponentName);
|
||||
method public void setChangedSince(long);
|
||||
method public void setPackage(java.lang.String);
|
||||
method public void setQueryFlags(int);
|
||||
field public static final int FLAG_GET_DYNAMIC = 1; // 0x1
|
||||
field public static final int FLAG_GET_KEY_FIELDS_ONLY = 4; // 0x4
|
||||
field public static final int FLAG_GET_PINNED = 2; // 0x2
|
||||
}
|
||||
|
||||
public class PackageInfo implements android.os.Parcelable {
|
||||
@@ -9971,6 +9990,56 @@ package android.content.pm {
|
||||
field public java.lang.String permission;
|
||||
}
|
||||
|
||||
public class ShortcutInfo implements android.os.Parcelable {
|
||||
method public int describeContents();
|
||||
method public android.content.ComponentName getActivityComponent();
|
||||
method public android.os.PersistableBundle getExtras();
|
||||
method public java.lang.String getId();
|
||||
method public android.content.Intent getIntent();
|
||||
method public long getLastChangedTimestamp();
|
||||
method public java.lang.String getPackageName();
|
||||
method public java.lang.String getTitle();
|
||||
method public int getWeight();
|
||||
method public boolean hasIconFile();
|
||||
method public boolean hasIconResource();
|
||||
method public boolean isDynamic();
|
||||
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_DYNAMIC = 1; // 0x1
|
||||
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_PINNED = 2; // 0x2
|
||||
}
|
||||
|
||||
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 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 setTitle(java.lang.String);
|
||||
method public android.content.pm.ShortcutInfo.Builder setWeight(int);
|
||||
}
|
||||
|
||||
public class ShortcutManager {
|
||||
method public boolean addDynamicShortcut(android.content.pm.ShortcutInfo);
|
||||
method public void deleteAllDynamicShortcuts();
|
||||
method public void deleteDynamicShortcut(java.lang.String);
|
||||
method public java.util.List<android.content.pm.ShortcutInfo> getDynamicShortcuts();
|
||||
method public int getMaxDynamicShortcutCount();
|
||||
method public java.util.List<android.content.pm.ShortcutInfo> getPinnedShortcuts();
|
||||
method public long getRateLimitResetTime();
|
||||
method public int getRemainingCallCount();
|
||||
method public boolean setDynamicShortcuts(java.util.List<android.content.pm.ShortcutInfo>);
|
||||
method public boolean updateShortcuts(java.util.List<android.content.pm.ShortcutInfo>);
|
||||
}
|
||||
|
||||
public class Signature implements android.os.Parcelable {
|
||||
ctor public Signature(byte[]);
|
||||
ctor public Signature(java.lang.String);
|
||||
@@ -29014,6 +29083,7 @@ package android.os {
|
||||
ctor public PersistableBundle();
|
||||
ctor public PersistableBundle(int);
|
||||
ctor public PersistableBundle(android.os.PersistableBundle);
|
||||
ctor public PersistableBundle(android.os.Bundle);
|
||||
method public java.lang.Object clone();
|
||||
method public int describeContents();
|
||||
method public android.os.PersistableBundle getPersistableBundle(java.lang.String);
|
||||
|
||||
@@ -37,7 +37,9 @@ import android.content.Context;
|
||||
import android.content.IRestrictionsManager;
|
||||
import android.content.RestrictionsManager;
|
||||
import android.content.pm.ILauncherApps;
|
||||
import android.content.pm.IShortcutService;
|
||||
import android.content.pm.LauncherApps;
|
||||
import android.content.pm.ShortcutManager;
|
||||
import android.content.res.Resources;
|
||||
import android.hardware.ConsumerIrManager;
|
||||
import android.hardware.ISerialManager;
|
||||
@@ -748,6 +750,15 @@ final class SystemServiceRegistry {
|
||||
Log.i(TAG, "Creating new instance of SoundTriggerManager object.");
|
||||
return new SoundTriggerManager(ctx, ISoundTriggerService.Stub.asInterface(b));
|
||||
}});
|
||||
|
||||
registerService(Context.SHORTCUT_SERVICE, ShortcutManager.class,
|
||||
new CachedServiceFetcher<ShortcutManager>() {
|
||||
@Override
|
||||
public ShortcutManager createService(ContextImpl ctx) {
|
||||
IBinder b = ServiceManager.getService(Context.SHORTCUT_SERVICE);
|
||||
return new ShortcutManager(ctx,
|
||||
IShortcutService.Stub.asInterface(b));
|
||||
}});
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -2680,6 +2680,7 @@ public abstract class Context {
|
||||
RADIO_SERVICE,
|
||||
HARDWARE_PROPERTIES_SERVICE,
|
||||
//@hide: SOUND_TRIGGER_SERVICE,
|
||||
SHORTCUT_SERVICE,
|
||||
})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface ServiceName {}
|
||||
@@ -3575,6 +3576,14 @@ public abstract class Context {
|
||||
*/
|
||||
public static final String HARDWARE_PROPERTIES_SERVICE = "hardwareproperties";
|
||||
|
||||
/**
|
||||
* TODO Javadoc
|
||||
*
|
||||
* @see #getSystemService
|
||||
* @see android.content.pm.ShortcutManager
|
||||
*/
|
||||
public static final String SHORTCUT_SERVICE = "shortcut";
|
||||
|
||||
/**
|
||||
* Determine whether the given permission is allowed for a particular
|
||||
* process and user ID running in the system.
|
||||
|
||||
@@ -22,6 +22,7 @@ import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.IOnAppsChangedListener;
|
||||
import android.content.pm.ParceledListSlice;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.content.pm.ShortcutInfo;
|
||||
import android.graphics.Rect;
|
||||
import android.os.Bundle;
|
||||
import android.os.UserHandle;
|
||||
@@ -42,4 +43,13 @@ interface ILauncherApps {
|
||||
boolean isPackageEnabled(String packageName, in UserHandle user);
|
||||
boolean isActivityEnabled(in ComponentName component, in UserHandle user);
|
||||
ApplicationInfo getApplicationInfo(String packageName, int flags, in UserHandle user);
|
||||
|
||||
ParceledListSlice getShortcuts(String callingPackage, long changedSince, String packageName,
|
||||
in ComponentName componentName, int flags, in UserHandle user);
|
||||
ParceledListSlice getShortcutInfo(String callingPackage, String packageName, in List<String> ids,
|
||||
in UserHandle user);
|
||||
void pinShortcuts(String callingPackage, String packageName, in List<String> shortcutIds,
|
||||
in UserHandle user);
|
||||
void startShortcut(String callingPackage, in ShortcutInfo shortcut, in Rect sourceBounds,
|
||||
in Bundle startActivityOptions, in UserHandle user);
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package android.content.pm;
|
||||
|
||||
import android.content.pm.ParceledListSlice;
|
||||
import android.os.UserHandle;
|
||||
|
||||
/**
|
||||
@@ -29,4 +30,5 @@ oneway interface IOnAppsChangedListener {
|
||||
void onPackagesUnavailable(in UserHandle user, in String[] packageNames, boolean replacing);
|
||||
void onPackagesSuspended(in UserHandle user, in String[] packageNames);
|
||||
void onPackagesUnsuspended(in UserHandle user, in String[] packageNames);
|
||||
void onShortcutChanged(in UserHandle user, String packageName, in ParceledListSlice shortcuts);
|
||||
}
|
||||
|
||||
48
core/java/android/content/pm/IShortcutService.aidl
Normal file
48
core/java/android/content/pm/IShortcutService.aidl
Normal file
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright (C) 2016 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package android.content.pm;
|
||||
|
||||
import android.content.pm.ParceledListSlice;
|
||||
import android.content.pm.ShortcutInfo;
|
||||
|
||||
/**
|
||||
* {@hide}
|
||||
*/
|
||||
interface IShortcutService {
|
||||
|
||||
boolean setDynamicShortcuts(String packageName, in ParceledListSlice shortcutInfoList,
|
||||
int userId);
|
||||
|
||||
ParceledListSlice getDynamicShortcuts(String packageName, int userId);
|
||||
|
||||
boolean addDynamicShortcut(String packageName, in ShortcutInfo shortcutInfo, int userId);
|
||||
|
||||
void deleteDynamicShortcut(String packageName, in String shortcutId, int userId);
|
||||
|
||||
void deleteAllDynamicShortcuts(String packageName, int userId);
|
||||
|
||||
ParceledListSlice getPinnedShortcuts(String packageName, int userId);
|
||||
|
||||
boolean updateShortcuts(String packageName, in ParceledListSlice shortcuts, int userId);
|
||||
|
||||
int getMaxDynamicShortcutCount(String packageName, int userId);
|
||||
|
||||
int getRemainingCallCount(String packageName, int userId);
|
||||
|
||||
long getRateLimitResetTime(String packageName, int userId);
|
||||
|
||||
void resetThrottling(); // system only API for developer opsions
|
||||
}
|
||||
@@ -16,23 +16,29 @@
|
||||
|
||||
package android.content.pm;
|
||||
|
||||
import android.Manifest.permission;
|
||||
import android.annotation.IntDef;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.RequiresPermission;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ILauncherApps;
|
||||
import android.content.pm.IOnAppsChangedListener;
|
||||
import android.content.pm.PackageManager.ApplicationInfoFlags;
|
||||
import android.content.pm.PackageManager.NameNotFoundException;
|
||||
import android.graphics.Rect;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.os.Message;
|
||||
import android.os.Parcel;
|
||||
import android.os.ParcelFileDescriptor;
|
||||
import android.os.RemoteException;
|
||||
import android.os.UserHandle;
|
||||
import android.os.UserManager;
|
||||
import android.util.Log;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
@@ -148,6 +154,91 @@ public class LauncherApps {
|
||||
*/
|
||||
public void onPackagesUnsuspended(String[] packageNames, UserHandle user) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates that one or more shortcuts (which may be dynamic and/or pinned)
|
||||
* have been added, updated or removed.
|
||||
*
|
||||
* @param packageName The name of the package that has the shortcuts.
|
||||
* @param shortcuts all shortcuts from the package (dynamic and/or pinned).
|
||||
* @param user The UserHandle of the profile that generated the change.
|
||||
*/
|
||||
public void onShortcutsChanged(@NonNull String packageName,
|
||||
@NonNull List<ShortcutInfo> shortcuts, @NonNull UserHandle user) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a query passed to {@link #getShortcuts(ShortcutQuery, UserHandle)}.
|
||||
*/
|
||||
public static class ShortcutQuery {
|
||||
/**
|
||||
* Include dynamic shortcuts in the result.
|
||||
*/
|
||||
public static final int FLAG_GET_DYNAMIC = 1 << 0;
|
||||
|
||||
/**
|
||||
* Include pinned shortcuts in the result.
|
||||
*/
|
||||
public static final int FLAG_GET_PINNED = 1 << 1;
|
||||
|
||||
/**
|
||||
* Requests "key" fields only.
|
||||
*/
|
||||
public static final int FLAG_GET_KEY_FIELDS_ONLY = 1 << 2;
|
||||
|
||||
/** @hide */
|
||||
@IntDef(flag = true,
|
||||
value = {
|
||||
FLAG_GET_DYNAMIC,
|
||||
FLAG_GET_PINNED,
|
||||
FLAG_GET_KEY_FIELDS_ONLY,
|
||||
})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface QueryFlags {}
|
||||
|
||||
long mChangedSince;
|
||||
|
||||
@Nullable
|
||||
String mPackage;
|
||||
|
||||
@Nullable
|
||||
ComponentName mActivity;
|
||||
|
||||
@QueryFlags
|
||||
int mQueryFlags;
|
||||
|
||||
public ShortcutQuery() {
|
||||
}
|
||||
|
||||
/**
|
||||
* If non-zero, returns only shortcuts that have been added or updated since the timestamp,
|
||||
* which is a milliseconds since the Epoch.
|
||||
*/
|
||||
public void setChangedSince(long changedSince) {
|
||||
mChangedSince = changedSince;
|
||||
}
|
||||
|
||||
/**
|
||||
* If non-null, returns only shortcuts from the package.
|
||||
*/
|
||||
public void setPackage(@Nullable String packageName) {
|
||||
mPackage = packageName;
|
||||
}
|
||||
|
||||
/**
|
||||
* If non-null, returns only shortcuts associated with the activity.
|
||||
*/
|
||||
public void setActivity(@Nullable ComponentName activity) {
|
||||
mActivity = activity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set query options.
|
||||
*/
|
||||
public void setQueryFlags(@QueryFlags int queryFlags) {
|
||||
mQueryFlags = queryFlags;
|
||||
}
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
@@ -302,6 +393,125 @@ public class LauncherApps {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the IDs of {@link ShortcutInfo}s that match {@code query}.
|
||||
*
|
||||
* <p>Callers mut have the {@link permission#BIND_APPWIDGET} permission.
|
||||
*
|
||||
* @param query result includes shortcuts matching this query.
|
||||
* @param user The UserHandle of the profile.
|
||||
*
|
||||
* @return the IDs of {@link ShortcutInfo}s that match the query.
|
||||
*/
|
||||
@RequiresPermission(permission.BIND_APPWIDGET)
|
||||
@Nullable
|
||||
public List<ShortcutInfo> getShortcuts(@NonNull ShortcutQuery query,
|
||||
@NonNull UserHandle user) {
|
||||
try {
|
||||
return mService.getShortcuts(mContext.getPackageName(),
|
||||
query.mChangedSince, query.mPackage, query.mActivity, query.mQueryFlags, user)
|
||||
.getList();
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@link ShortcutInfo}s with the given IDs from a package.
|
||||
*
|
||||
* <p>Callers mut have the {@link permission#BIND_APPWIDGET} permission.
|
||||
*
|
||||
* @param packageName The target package.
|
||||
* @param ids IDs of the shortcuts to retrieve.
|
||||
* @param user The UserHandle of the profile.
|
||||
*
|
||||
* @return list of {@link ShortcutInfo} associated with the package.
|
||||
*/
|
||||
@RequiresPermission(permission.BIND_APPWIDGET)
|
||||
@Nullable
|
||||
public List<ShortcutInfo> getShortcutInfo(@NonNull String packageName,
|
||||
@NonNull List<String> ids, @NonNull UserHandle user) {
|
||||
try {
|
||||
return mService.getShortcutInfo(mContext.getPackageName(), packageName, ids, user)
|
||||
.getList();
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Pin shortcuts on a package.
|
||||
*
|
||||
* <p>This API is <b>NOT</b> cumulative; this will replace all pinned shortcuts for the package.
|
||||
* However, different launchers may have different set of pinned shortcuts.
|
||||
*
|
||||
* <p>Callers must have the {@link permission#BIND_APPWIDGET} permission.
|
||||
*
|
||||
* @param packageName The target package name.
|
||||
* @param shortcutIds The IDs of the shortcut to be pinned.
|
||||
* @param user The UserHandle of the profile.
|
||||
*/
|
||||
@RequiresPermission(permission.BIND_APPWIDGET)
|
||||
public void pinShortcuts(@NonNull String packageName, @NonNull List<String> shortcutIds,
|
||||
@NonNull UserHandle user) {
|
||||
try {
|
||||
mService.pinShortcuts(mContext.getPackageName(), packageName, shortcutIds, user);
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the icon resource ID, if {@code shortcut} has one
|
||||
* (i.e. when {@link ShortcutInfo#hasIconResource()} returns {@code true}).
|
||||
*
|
||||
* <p>Callers mut have the {@link permission#BIND_APPWIDGET} permission.
|
||||
*
|
||||
* @param shortcut The target shortcut.
|
||||
* @param user The UserHandle of the profile.
|
||||
*/
|
||||
@RequiresPermission(permission.BIND_APPWIDGET)
|
||||
public int getShortcutIconResId(@NonNull ShortcutInfo shortcut, @NonNull UserHandle user) {
|
||||
throw new RuntimeException("not implemented yet");
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the icon as {@link ParcelFileDescriptor}, when it's stored as a file
|
||||
* (i.e. when {@link ShortcutInfo#hasIconFile()} returns {@code true}).
|
||||
*
|
||||
* <p>Callers mut have the {@link permission#BIND_APPWIDGET} permission.
|
||||
*
|
||||
* @param shortcut The target shortcut.
|
||||
* @param user The UserHandle of the profile.
|
||||
*/
|
||||
@RequiresPermission(permission.BIND_APPWIDGET)
|
||||
public ParcelFileDescriptor getShortcutIconFd(
|
||||
@NonNull ShortcutInfo shortcut, @NonNull UserHandle user) {
|
||||
throw new RuntimeException("not implemented yet");
|
||||
}
|
||||
|
||||
/**
|
||||
* Launches a shortcut.
|
||||
*
|
||||
* <p>Callers mut have the {@link permission#BIND_APPWIDGET} permission.
|
||||
*
|
||||
* @param shortcut The target shortcut.
|
||||
* @param sourceBounds The Rect containing the source bounds of the clicked icon.
|
||||
* @param startActivityOptions Options to pass to startActivity.
|
||||
* @param user The UserHandle of the profile.
|
||||
*/
|
||||
@RequiresPermission(permission.BIND_APPWIDGET)
|
||||
public void startShortcut(@NonNull ShortcutInfo shortcut,
|
||||
@Nullable Rect sourceBounds, @Nullable Bundle startActivityOptions,
|
||||
@NonNull UserHandle user) {
|
||||
try {
|
||||
mService.startShortcut(mContext.getPackageName(), shortcut, sourceBounds,
|
||||
startActivityOptions, user);
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a callback for changes to packages in current and managed profiles.
|
||||
@@ -474,6 +684,20 @@ public class LauncherApps {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onShortcutChanged(UserHandle user, String packageName,
|
||||
ParceledListSlice shortcuts) {
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "onShortcutChanged " + user.getIdentifier() + "," + packageName);
|
||||
}
|
||||
final List<ShortcutInfo> list = shortcuts.getList();
|
||||
synchronized (LauncherApps.this) {
|
||||
for (CallbackMessageHandler callback : mCallbacks) {
|
||||
callback.postOnShortcutChanged(packageName, user, list);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private static class CallbackMessageHandler extends Handler {
|
||||
@@ -484,6 +708,7 @@ public class LauncherApps {
|
||||
private static final int MSG_UNAVAILABLE = 5;
|
||||
private static final int MSG_SUSPENDED = 6;
|
||||
private static final int MSG_UNSUSPENDED = 7;
|
||||
private static final int MSG_SHORTCUT_CHANGED = 8;
|
||||
|
||||
private LauncherApps.Callback mCallback;
|
||||
|
||||
@@ -492,6 +717,7 @@ public class LauncherApps {
|
||||
String packageName;
|
||||
boolean replacing;
|
||||
UserHandle user;
|
||||
List<ShortcutInfo> shortcuts;
|
||||
}
|
||||
|
||||
public CallbackMessageHandler(Looper looper, LauncherApps.Callback callback) {
|
||||
@@ -527,6 +753,9 @@ public class LauncherApps {
|
||||
case MSG_UNSUSPENDED:
|
||||
mCallback.onPackagesUnsuspended(info.packageNames, info.user);
|
||||
break;
|
||||
case MSG_SHORTCUT_CHANGED:
|
||||
mCallback.onShortcutsChanged(info.packageName, info.shortcuts, info.user);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -582,5 +811,14 @@ public class LauncherApps {
|
||||
info.user = user;
|
||||
obtainMessage(MSG_UNSUSPENDED, info).sendToTarget();
|
||||
}
|
||||
|
||||
public void postOnShortcutChanged(String packageName, UserHandle user,
|
||||
List<ShortcutInfo> shortcuts) {
|
||||
CallbackInfo info = new CallbackInfo();
|
||||
info.packageName = packageName;
|
||||
info.user = user;
|
||||
info.shortcuts = shortcuts;
|
||||
obtainMessage(MSG_SHORTCUT_CHANGED, info).sendToTarget();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
18
core/java/android/content/pm/ShortcutInfo.aidl
Normal file
18
core/java/android/content/pm/ShortcutInfo.aidl
Normal file
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
* Copyright (C) 2016 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package android.content.pm;
|
||||
|
||||
parcelable ShortcutInfo;
|
||||
680
core/java/android/content/pm/ShortcutInfo.java
Normal file
680
core/java/android/content/pm/ShortcutInfo.java
Normal file
@@ -0,0 +1,680 @@
|
||||
/*
|
||||
* Copyright (C) 2016 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package android.content.pm;
|
||||
|
||||
import android.annotation.IntDef;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.graphics.drawable.Icon;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.os.PersistableBundle;
|
||||
import android.os.UserHandle;
|
||||
|
||||
import com.android.internal.util.Preconditions;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
/**
|
||||
* TODO Enhance javadoc
|
||||
*
|
||||
* Represents a shortcut form an application.
|
||||
*
|
||||
* Notes...
|
||||
* - If an {@link Icon} is of a resource, then we'll just persist the package name and resource ID.
|
||||
*
|
||||
* Otherwise, the bitmap will be fetched when it's registered to ShortcutManager, then *shrunk*
|
||||
* if necessary, and persisted.
|
||||
*
|
||||
* We will disallow byte[] icons, because they can easily go over binder size limit.
|
||||
*
|
||||
* TODO Move save/load to this class
|
||||
*/
|
||||
public class ShortcutInfo implements Parcelable {
|
||||
/* @hide */
|
||||
public static final int FLAG_DYNAMIC = 1 << 0;
|
||||
|
||||
/* @hide */
|
||||
public static final int FLAG_PINNED = 1 << 1;
|
||||
|
||||
/* @hide */
|
||||
public static final int FLAG_HAS_ICON_RES = 1 << 2;
|
||||
|
||||
/* @hide */
|
||||
public static final int FLAG_HAS_ICON_FILE = 1 << 3;
|
||||
|
||||
/** @hide */
|
||||
@IntDef(flag = true,
|
||||
value = {
|
||||
FLAG_DYNAMIC,
|
||||
FLAG_PINNED,
|
||||
FLAG_HAS_ICON_RES,
|
||||
FLAG_HAS_ICON_FILE,
|
||||
})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface ShortcutFlags {}
|
||||
|
||||
// Cloning options.
|
||||
|
||||
/* @hide */
|
||||
private static final int CLONE_REMOVE_ICON = 1 << 0;
|
||||
|
||||
/* @hide */
|
||||
private static final int CLONE_REMOVE_INTENT = 1 << 1;
|
||||
|
||||
/* @hide */
|
||||
public static final int CLONE_REMOVE_NON_KEY_INFO = 1 << 2;
|
||||
|
||||
/* @hide */
|
||||
public static final int CLONE_REMOVE_FOR_CREATOR = CLONE_REMOVE_ICON;
|
||||
|
||||
/* @hide */
|
||||
public static final int CLONE_REMOVE_FOR_LAUNCHER = CLONE_REMOVE_ICON | CLONE_REMOVE_INTENT;
|
||||
|
||||
/** @hide */
|
||||
@IntDef(flag = true,
|
||||
value = {
|
||||
CLONE_REMOVE_ICON,
|
||||
CLONE_REMOVE_INTENT,
|
||||
CLONE_REMOVE_NON_KEY_INFO,
|
||||
CLONE_REMOVE_FOR_CREATOR,
|
||||
CLONE_REMOVE_FOR_LAUNCHER
|
||||
})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface CloneFlags {}
|
||||
|
||||
private final String mId;
|
||||
|
||||
@NonNull
|
||||
private final String mPackageName;
|
||||
|
||||
@Nullable
|
||||
private ComponentName mActivityComponent;
|
||||
|
||||
@Nullable
|
||||
private Icon mIcon;
|
||||
|
||||
@NonNull
|
||||
private String mTitle;
|
||||
|
||||
@NonNull
|
||||
private Intent mIntent;
|
||||
|
||||
// Internal use only.
|
||||
@NonNull
|
||||
private PersistableBundle mIntentPersistableExtras;
|
||||
|
||||
private int mWeight;
|
||||
|
||||
@Nullable
|
||||
private PersistableBundle mExtras;
|
||||
|
||||
private long mLastChangedTimestamp;
|
||||
|
||||
// Internal use only.
|
||||
@ShortcutFlags
|
||||
private int mFlags;
|
||||
|
||||
// Internal use only.
|
||||
private int mIconResourceId;
|
||||
|
||||
// Internal use only.
|
||||
@Nullable
|
||||
private String mBitmapPath;
|
||||
|
||||
private ShortcutInfo(Builder b) {
|
||||
mId = Preconditions.checkStringNotEmpty(b.mId, "Shortcut ID must be provided");
|
||||
|
||||
// Note we can't do other null checks here because SM.updateShortcuts() takes partial
|
||||
// information.
|
||||
mPackageName = b.mContext.getPackageName();
|
||||
mActivityComponent = b.mActivityComponent;
|
||||
mIcon = b.mIcon;
|
||||
mTitle = b.mTitle;
|
||||
mIntent = b.mIntent;
|
||||
mWeight = b.mWeight;
|
||||
mExtras = b.mExtras;
|
||||
updateTimestamp();
|
||||
}
|
||||
|
||||
/**
|
||||
* Throws if any of the mandatory fields is not set.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public void enforceMandatoryFields() {
|
||||
Preconditions.checkStringNotEmpty(mTitle, "Shortcut title must be provided");
|
||||
Preconditions.checkNotNull(mIntent, "Shortcut Intent must be provided");
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy constructor.
|
||||
*/
|
||||
private ShortcutInfo(ShortcutInfo source, @CloneFlags int cloneFlags) {
|
||||
mId = source.mId;
|
||||
mPackageName = source.mPackageName;
|
||||
mActivityComponent = source.mActivityComponent;
|
||||
mFlags = source.mFlags;
|
||||
mLastChangedTimestamp = source.mLastChangedTimestamp;
|
||||
|
||||
if ((cloneFlags & CLONE_REMOVE_NON_KEY_INFO) == 0) {
|
||||
if ((cloneFlags & CLONE_REMOVE_ICON) == 0) {
|
||||
mIcon = source.mIcon;
|
||||
}
|
||||
|
||||
mTitle = source.mTitle;
|
||||
if ((cloneFlags & CLONE_REMOVE_INTENT) == 0) {
|
||||
mIntent = source.mIntent;
|
||||
mIntentPersistableExtras = source.mIntentPersistableExtras;
|
||||
}
|
||||
mWeight = source.mWeight;
|
||||
mExtras = source.mExtras;
|
||||
mIconResourceId = source.mIconResourceId;
|
||||
mBitmapPath = source.mBitmapPath;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy a {@link ShortcutInfo}, optionally removing fields.
|
||||
* @hide
|
||||
*/
|
||||
public ShortcutInfo clone(@CloneFlags int cloneFlags) {
|
||||
return new ShortcutInfo(this, cloneFlags);
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy non-null/zero fields from another {@link ShortcutInfo}. Only "public" information
|
||||
* will be overwritten. The timestamp will be updated.
|
||||
*
|
||||
* - Flags will not change
|
||||
* - mBitmapPath will not change
|
||||
* - Current time will be set to timestamp
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public void copyNonNullFieldsFrom(ShortcutInfo source) {
|
||||
Preconditions.checkState(mId == source.mId, "ID must match");
|
||||
Preconditions.checkState(mPackageName.equals(source.mPackageName),
|
||||
"Package namae must match");
|
||||
|
||||
if (source.mActivityComponent != null) {
|
||||
mActivityComponent = source.mActivityComponent;
|
||||
}
|
||||
|
||||
if (source.mIcon != null) {
|
||||
mIcon = source.mIcon;
|
||||
}
|
||||
if (source.mTitle != null) {
|
||||
mTitle = source.mTitle;
|
||||
}
|
||||
if (source.mIntent != null) {
|
||||
mIntent = source.mIntent;
|
||||
mIntentPersistableExtras = source.mIntentPersistableExtras;
|
||||
}
|
||||
if (source.mWeight != 0) {
|
||||
mWeight = source.mWeight;
|
||||
}
|
||||
if (source.mExtras != null) {
|
||||
mExtras = source.mExtras;
|
||||
}
|
||||
|
||||
updateTimestamp();
|
||||
}
|
||||
|
||||
/**
|
||||
* Builder class for {@link ShortcutInfo} objects.
|
||||
*/
|
||||
public static class Builder {
|
||||
private final Context mContext;
|
||||
|
||||
private String mId;
|
||||
|
||||
private ComponentName mActivityComponent;
|
||||
|
||||
private Icon mIcon;
|
||||
|
||||
private String mTitle;
|
||||
|
||||
private Intent mIntent;
|
||||
|
||||
private int mWeight;
|
||||
|
||||
private PersistableBundle mExtras;
|
||||
|
||||
/** Constructor. */
|
||||
public Builder(Context context) {
|
||||
mContext = context;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the ID of the shortcut. This is a mandatory field.
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setId(@NonNull String id) {
|
||||
mId = Preconditions.checkStringNotEmpty(id, "id");
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Optionally sets the target activity.
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setActivityComponent(@NonNull ComponentName activityComponent) {
|
||||
mActivityComponent = Preconditions.checkNotNull(activityComponent, "activityComponent");
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Optionally sets an icon.
|
||||
*
|
||||
* - Tint is not supported TODO Either check and throw, or support it.
|
||||
* - URI icons will be converted into Bitmap icons at the registration time.
|
||||
*
|
||||
* TODO Only allow Bitmap, Resource and URI types. byte[] type can easily go over
|
||||
* binder size limit.
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setIcon(Icon icon) {
|
||||
mIcon = icon;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the title of a shortcut. This is a mandatory field.
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setTitle(@NonNull String title) {
|
||||
mTitle = Preconditions.checkStringNotEmpty(title, "title");
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the intent of a shortcut. This is a mandatory field. The extras must only contain
|
||||
* persistable information. (See {@link PersistableBundle}).
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setIntent(@NonNull Intent intent) {
|
||||
mIntent = Preconditions.checkNotNull(intent, "intent");
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Optionally sets the weight of a shortcut, which will be used by Launcher for sorting.
|
||||
* The larger the weight, the more "important" a shortcut is.
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setWeight(int weight) {
|
||||
mWeight = weight;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Optional values that application can set.
|
||||
* TODO: reserve keys starting with "android."
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setExtras(@NonNull PersistableBundle extras) {
|
||||
mExtras = extras;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link ShortcutInfo} instance.
|
||||
*/
|
||||
@NonNull
|
||||
public ShortcutInfo build() {
|
||||
return new ShortcutInfo(this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the ID of the shortcut.
|
||||
*/
|
||||
@NonNull
|
||||
public String getId() {
|
||||
return mId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the ID of the shortcut.
|
||||
*/
|
||||
@NonNull
|
||||
public String getPackageName() {
|
||||
return mPackageName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the target activity, which may be null, in which case the shortcut is not associated
|
||||
* with a specific activity.
|
||||
*/
|
||||
@Nullable
|
||||
public ComponentName getActivityComponent() {
|
||||
return mActivityComponent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Icon.
|
||||
*
|
||||
* For performance reasons, this will <b>NOT</b> be available when an instance is returned
|
||||
* by {@link ShortcutManager} or {@link LauncherApps}. A launcher application needs to use
|
||||
* other APIs in LauncherApps to fetch the bitmap. TODO Add a precondition for it.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@Nullable
|
||||
public Icon getIcon() {
|
||||
return mIcon;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the shortcut title.
|
||||
*/
|
||||
@NonNull
|
||||
public String getTitle() {
|
||||
return mTitle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the intent.
|
||||
* TODO Set mIntentPersistableExtras and before returning.
|
||||
*/
|
||||
@NonNull
|
||||
public Intent getIntent() {
|
||||
return mIntent;
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
@Nullable
|
||||
public PersistableBundle getIntentPersistableExtras() {
|
||||
return mIntentPersistableExtras;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the weight of a shortcut, which will be used by Launcher for sorting.
|
||||
* The larger the weight, the more "important" a shortcut is.
|
||||
*/
|
||||
public int getWeight() {
|
||||
return mWeight;
|
||||
}
|
||||
|
||||
/**
|
||||
* Optional values that application can set.
|
||||
*/
|
||||
@Nullable
|
||||
public PersistableBundle getExtras() {
|
||||
return mExtras;
|
||||
}
|
||||
|
||||
/**
|
||||
* Last time when any of the fields was updated.
|
||||
*/
|
||||
public long getLastChangedTimestamp() {
|
||||
return mLastChangedTimestamp;
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
@ShortcutFlags
|
||||
public int getFlags() {
|
||||
return mFlags;
|
||||
}
|
||||
|
||||
/** @hide*/
|
||||
public void setFlags(@ShortcutFlags int flags) {
|
||||
mFlags = flags;
|
||||
}
|
||||
|
||||
/** @hide*/
|
||||
public void addFlags(@ShortcutFlags int flags) {
|
||||
mFlags |= flags;
|
||||
}
|
||||
|
||||
/** @hide*/
|
||||
public void clearFlags(@ShortcutFlags int flags) {
|
||||
mFlags &= ~flags;
|
||||
}
|
||||
|
||||
/** @hide*/
|
||||
public boolean hasFlags(@ShortcutFlags int flags) {
|
||||
return (mFlags & flags) == flags;
|
||||
}
|
||||
|
||||
/** Return whether a shortcut is dynamic. */
|
||||
public boolean isDynamic() {
|
||||
return hasFlags(FLAG_DYNAMIC);
|
||||
}
|
||||
|
||||
/** Return whether a shortcut is pinned. */
|
||||
public boolean isPinned() {
|
||||
return hasFlags(FLAG_PINNED);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether a shortcut's icon is a resource in the owning package.
|
||||
*
|
||||
* @see LauncherApps#getShortcutIconResId(ShortcutInfo, UserHandle)
|
||||
*/
|
||||
public boolean hasIconResource() {
|
||||
return hasFlags(FLAG_HAS_ICON_RES);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether a shortcut's icon is stored as a file.
|
||||
*
|
||||
* @see LauncherApps#getShortcutIconFd(ShortcutInfo, UserHandle)
|
||||
*/
|
||||
public boolean hasIconFile() {
|
||||
return hasFlags(FLAG_HAS_ICON_FILE);
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public void updateTimestamp() {
|
||||
mLastChangedTimestamp = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
// VisibleForTesting
|
||||
public void setTimestamp(long value) {
|
||||
mLastChangedTimestamp = value;
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public void setIcon(Icon icon) {
|
||||
mIcon = icon;
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public void setTitle(String title) {
|
||||
mTitle = title;
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public void setIntent(Intent intent) {
|
||||
mIntent = intent;
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public void setIntentPersistableExtras(PersistableBundle intentPersistableExtras) {
|
||||
mIntentPersistableExtras = intentPersistableExtras;
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public void setWeight(int weight) {
|
||||
mWeight = weight;
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public void setExtras(PersistableBundle extras) {
|
||||
mExtras = extras;
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public int getIconResourceId() {
|
||||
return mIconResourceId;
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public String getBitmapPath() {
|
||||
return mBitmapPath;
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public void setBitmapPath(String bitmapPath) {
|
||||
mBitmapPath = bitmapPath;
|
||||
}
|
||||
|
||||
private ShortcutInfo(Parcel source) {
|
||||
final ClassLoader cl = getClass().getClassLoader();
|
||||
|
||||
mId = source.readString();
|
||||
mPackageName = source.readString();
|
||||
mActivityComponent = source.readParcelable(cl);
|
||||
mIcon = source.readParcelable(cl);
|
||||
mTitle = source.readString();
|
||||
mIntent = source.readParcelable(cl);
|
||||
mIntentPersistableExtras = source.readParcelable(cl);
|
||||
mWeight = source.readInt();
|
||||
mExtras = source.readParcelable(cl);
|
||||
mLastChangedTimestamp = source.readLong();
|
||||
mFlags = source.readInt();
|
||||
mIconResourceId = source.readInt();
|
||||
mBitmapPath = source.readString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeString(mId);
|
||||
dest.writeString(mPackageName);
|
||||
dest.writeParcelable(mActivityComponent, flags);
|
||||
dest.writeParcelable(mIcon, flags);
|
||||
dest.writeString(mTitle);
|
||||
dest.writeParcelable(mIntent, flags);
|
||||
dest.writeParcelable(mIntentPersistableExtras, flags);
|
||||
dest.writeInt(mWeight);
|
||||
dest.writeParcelable(mExtras, flags);
|
||||
dest.writeLong(mLastChangedTimestamp);
|
||||
dest.writeInt(mFlags);
|
||||
dest.writeInt(mIconResourceId);
|
||||
dest.writeString(mBitmapPath);
|
||||
}
|
||||
|
||||
public static final Creator<ShortcutInfo> CREATOR =
|
||||
new Creator<ShortcutInfo>() {
|
||||
public ShortcutInfo createFromParcel(Parcel source) {
|
||||
return new ShortcutInfo(source);
|
||||
}
|
||||
public ShortcutInfo[] newArray(int size) {
|
||||
return new ShortcutInfo[size];
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a string representation, intended for logging. Some fields will be retracted.
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return toStringInner(/* secure =*/ true, /* includeInternalData =*/ false);
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public String toInsecureString() {
|
||||
return toStringInner(/* secure =*/ false, /* includeInternalData =*/ true);
|
||||
}
|
||||
|
||||
private String toStringInner(boolean secure, boolean includeInternalData) {
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
sb.append("ShortcutInfo {");
|
||||
|
||||
sb.append("id=");
|
||||
sb.append(secure ? "***" : mId);
|
||||
|
||||
sb.append(", packageName=");
|
||||
sb.append(mPackageName);
|
||||
|
||||
if (isDynamic()) {
|
||||
sb.append(", dynamic");
|
||||
}
|
||||
if (isPinned()) {
|
||||
sb.append(", pinned");
|
||||
}
|
||||
|
||||
sb.append(", activity=");
|
||||
sb.append(mActivityComponent);
|
||||
|
||||
sb.append(", title=");
|
||||
sb.append(secure ? "***" : mTitle);
|
||||
|
||||
sb.append(", icon=");
|
||||
sb.append(mIcon);
|
||||
|
||||
sb.append(", weight=");
|
||||
sb.append(mWeight);
|
||||
|
||||
sb.append(", timestamp=");
|
||||
sb.append(mLastChangedTimestamp);
|
||||
|
||||
sb.append(", intent=");
|
||||
sb.append(mIntent);
|
||||
|
||||
sb.append(", intentExtras=");
|
||||
sb.append(secure ? "***" : mIntentPersistableExtras);
|
||||
|
||||
sb.append(", extras=");
|
||||
sb.append(mExtras);
|
||||
|
||||
if (includeInternalData) {
|
||||
sb.append(", flags=");
|
||||
sb.append(mFlags);
|
||||
|
||||
sb.append(", iconRes=");
|
||||
sb.append(mIconResourceId);
|
||||
|
||||
sb.append(", bitmapPath=");
|
||||
sb.append(mBitmapPath);
|
||||
}
|
||||
|
||||
sb.append("}");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public ShortcutInfo(String id, String packageName, ComponentName activityComponent,
|
||||
Icon icon, String title, Intent intent, PersistableBundle intentPersistableExtras,
|
||||
int weight, PersistableBundle extras, long lastChangedTimestamp,
|
||||
int flags, int iconResId, String bitmapPath) {
|
||||
mId = id;
|
||||
mPackageName = packageName;
|
||||
mActivityComponent = activityComponent;
|
||||
mIcon = icon;
|
||||
mTitle = title;
|
||||
mIntent = intent;
|
||||
mIntentPersistableExtras = intentPersistableExtras;
|
||||
mWeight = weight;
|
||||
mExtras = extras;
|
||||
mLastChangedTimestamp = lastChangedTimestamp;
|
||||
mFlags = flags;
|
||||
mIconResourceId = iconResId;
|
||||
mBitmapPath = bitmapPath;
|
||||
}
|
||||
}
|
||||
247
core/java/android/content/pm/ShortcutManager.java
Normal file
247
core/java/android/content/pm/ShortcutManager.java
Normal file
@@ -0,0 +1,247 @@
|
||||
/*
|
||||
* Copyright (C) 2016 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package android.content.pm;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.content.Context;
|
||||
import android.os.RemoteException;
|
||||
import android.os.UserHandle;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* TODO Enhance javadoc
|
||||
*
|
||||
* {@link ShortcutManager} manages shortcuts created by applications.
|
||||
*
|
||||
* <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 #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.
|
||||
*
|
||||
* <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
|
||||
* on Launcher to make "pinned" shortcuts. Pinned shortcuts <b>cannot</b> be removed by the creator
|
||||
* app. An application can obtain all pinned shortcuts from itself with
|
||||
* {@link #getPinnedShortcuts()}. Applications should keep the pinned shortcut information
|
||||
* up-to-date using {@link #updateShortcuts(List)}.
|
||||
*
|
||||
* <p>The number of pinned shortcuts does not affect the number of dynamic shortcuts that can be
|
||||
* published by an application at a time.
|
||||
* No matter how many pinned shortcuts that Launcher has for an application, the
|
||||
* application can still always publish {@link #getMaxDynamicShortcutCount()} number of dynamic
|
||||
* shortcuts.
|
||||
*
|
||||
* <h3>Shortcut IDs</h3>
|
||||
*
|
||||
* Each shortcut must have an ID, which must be unique within each application. When a shortcut is
|
||||
* published, existing shortcuts with the same ID will be updated. Note this may include a
|
||||
* pinned shortcut.
|
||||
*
|
||||
* <h3>Rate limiting</h3>
|
||||
*
|
||||
* Calls to {@link #setDynamicShortcuts(List)}, {@link #addDynamicShortcut(ShortcutInfo)},
|
||||
* 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.
|
||||
*
|
||||
* <p>An applications can use {@link #getRateLimitResetTime()} to get the next reset time.
|
||||
*
|
||||
* <h3>Backup and Restore</h3>
|
||||
*
|
||||
* Shortcuts will be backed up and restored across devices. This means all information, including
|
||||
* IDs, must be meaningful on a different device.
|
||||
*
|
||||
* TODO: Define a Broadcast to let apps update shortcuts on a restored device.
|
||||
*
|
||||
* <h3>APIs for launcher</h3>
|
||||
*
|
||||
* Launcher applications should use {@link LauncherApps} to get shortcuts that are published from
|
||||
* applications. Launcher applications can also pin shortcuts with
|
||||
* {@link LauncherApps#pinShortcuts(String, List, UserHandle)}.
|
||||
*/
|
||||
public class ShortcutManager {
|
||||
private static final String TAG = "ShortcutManager";
|
||||
|
||||
private final Context mContext;
|
||||
private final IShortcutService mService;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public ShortcutManager(Context context, IShortcutService service) {
|
||||
mContext = context;
|
||||
mService = service;
|
||||
}
|
||||
|
||||
/**
|
||||
* Publish a list of shortcuts. All existing dynamic shortcuts from the caller application
|
||||
* will be replaced.
|
||||
*
|
||||
* <p>This API will be rate-limited.
|
||||
*
|
||||
* @return {@code true} if the call has succeeded. {@code false} if the call is rate-limited.
|
||||
*
|
||||
* @throws IllegalArgumentException if {@code shortcutInfoList} contains more than
|
||||
* {@link #getMaxDynamicShortcutCount()} shortcuts.
|
||||
*/
|
||||
public boolean setDynamicShortcuts(@NonNull List<ShortcutInfo> shortcutInfoList) {
|
||||
try {
|
||||
return mService.setDynamicShortcuts(mContext.getPackageName(),
|
||||
new ParceledListSlice(shortcutInfoList), injectMyUserId());
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all dynamic shortcuts from the caller application. The number of result items
|
||||
* will not exceed the value returned by {@link #getMaxDynamicShortcutCount()}.
|
||||
*/
|
||||
@NonNull
|
||||
public List<ShortcutInfo> getDynamicShortcuts() {
|
||||
try {
|
||||
return mService.getDynamicShortcuts(mContext.getPackageName(), injectMyUserId())
|
||||
.getList();
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Publish a single dynamic shortcut. If there's already dynamic or pinned shortcuts with
|
||||
* the same ID, they will all be updated.
|
||||
*
|
||||
* <p>This API will be rate-limited.
|
||||
*
|
||||
* @return {@code true} if the call has succeeded. {@code false} if the call is rate-limited.
|
||||
*
|
||||
* @throws IllegalArgumentException if the caller application has already published the
|
||||
* max number of dynamic shortcuts.
|
||||
*/
|
||||
public boolean addDynamicShortcut(@NonNull ShortcutInfo shortcutInfo) {
|
||||
try {
|
||||
return mService.addDynamicShortcut(
|
||||
mContext.getPackageName(), shortcutInfo, injectMyUserId());
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a single dynamic shortcut by ID.
|
||||
*/
|
||||
public void deleteDynamicShortcut(@NonNull String shortcutId) {
|
||||
try {
|
||||
mService.deleteDynamicShortcut(mContext.getPackageName(), shortcutId, injectMyUserId());
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete all dynamic shortcuts from the caller application.
|
||||
*/
|
||||
public void deleteAllDynamicShortcuts() {
|
||||
try {
|
||||
mService.deleteAllDynamicShortcuts(mContext.getPackageName(), injectMyUserId());
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all pinned shortcuts from the caller application.
|
||||
*/
|
||||
@NonNull
|
||||
public List<ShortcutInfo> getPinnedShortcuts() {
|
||||
try {
|
||||
return mService.getPinnedShortcuts(mContext.getPackageName(), injectMyUserId())
|
||||
.getList();
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update all existing shortcuts with the same IDs. Shortcuts may be pinned and/or dynamic.
|
||||
*
|
||||
* <p>This API will be rate-limited.
|
||||
*
|
||||
* @return {@code true} if the call has succeeded. {@code false} if the call is rate-limited.
|
||||
*/
|
||||
public boolean updateShortcuts(List<ShortcutInfo> shortcutInfoList) {
|
||||
try {
|
||||
return mService.updateShortcuts(mContext.getPackageName(),
|
||||
new ParceledListSlice(shortcutInfoList), injectMyUserId());
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the max number of dynamic shortcuts that each application can have at a time.
|
||||
*/
|
||||
public int getMaxDynamicShortcutCount() {
|
||||
try {
|
||||
return mService.getMaxDynamicShortcutCount(mContext.getPackageName(), injectMyUserId());
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of times the caller application can call the rate-limited APIs
|
||||
* before the rate limit counter is reset.
|
||||
*
|
||||
* @see #getRateLimitResetTime()
|
||||
*/
|
||||
public int getRemainingCallCount() {
|
||||
try {
|
||||
return mService.getRemainingCallCount(mContext.getPackageName(), injectMyUserId());
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return when the rate limit count will be reset next time, in milliseconds since the epoch.
|
||||
*
|
||||
* @see #getRemainingCallCount()
|
||||
* @see System#currentTimeMillis()
|
||||
*/
|
||||
public long getRateLimitResetTime() {
|
||||
try {
|
||||
return mService.getRateLimitResetTime(mContext.getPackageName(), injectMyUserId());
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
|
||||
/** @hide injection point */
|
||||
@VisibleForTesting
|
||||
protected int injectMyUserId() {
|
||||
return UserHandle.myUserId();
|
||||
}
|
||||
}
|
||||
58
core/java/android/content/pm/ShortcutServiceInternal.java
Normal file
58
core/java/android/content/pm/ShortcutServiceInternal.java
Normal file
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright (C) 2016 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.content.pm;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.UserIdInt;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.LauncherApps.ShortcutQuery;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Entry points used by {@link LauncherApps}.
|
||||
*
|
||||
* <p>No permission / argument checks will be performed inside.
|
||||
* Callers must check the calling app permission and the calling package name.
|
||||
* @hide
|
||||
*/
|
||||
public abstract class ShortcutServiceInternal {
|
||||
public interface ShortcutChangeListener {
|
||||
void onShortcutChanged(@NonNull String packageName,
|
||||
@NonNull List<ShortcutInfo> shortcuts, @UserIdInt int userId);
|
||||
}
|
||||
|
||||
public abstract List<ShortcutInfo>
|
||||
getShortcuts(@NonNull String callingPackage, long changedSince,
|
||||
@Nullable String packageName, @Nullable ComponentName componentName,
|
||||
@ShortcutQuery.QueryFlags int flags,
|
||||
int userId);
|
||||
|
||||
public abstract List<ShortcutInfo>
|
||||
getShortcutInfo(@NonNull String callingPackage,
|
||||
@NonNull String packageName, @Nullable List<String> ids, int userId);
|
||||
|
||||
public abstract void pinShortcuts(@NonNull String callingPackage, @NonNull String packageName,
|
||||
@NonNull List<String> shortcutIds, int userId);
|
||||
|
||||
public abstract Intent createShortcutIntent(@NonNull String callingPackage,
|
||||
@NonNull ShortcutInfo shortcut, int userId);
|
||||
|
||||
public abstract void addListener(@NonNull ShortcutChangeListener listener);
|
||||
}
|
||||
@@ -235,6 +235,12 @@ public class BaseBundle {
|
||||
return mParcelledData != null;
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
ArrayMap<String, Object> getMap() {
|
||||
unparcel();
|
||||
return mMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of mappings contained in this Bundle.
|
||||
*
|
||||
|
||||
@@ -24,9 +24,6 @@ import org.xmlpull.v1.XmlPullParserException;
|
||||
import org.xmlpull.v1.XmlSerializer;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* A mapping from String values to various types that can be saved to persistent and later
|
||||
@@ -82,6 +79,18 @@ public final class PersistableBundle extends BaseBundle implements Cloneable, Pa
|
||||
super(b);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Constructs a PersistableBundle from a Bundle.
|
||||
*
|
||||
* @param b a Bundle to be copied.
|
||||
*
|
||||
* @throws IllegalArgumentException if any element of {@code b} cannot be persisted.
|
||||
*/
|
||||
public PersistableBundle(Bundle b) {
|
||||
this(b.getMap());
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a PersistableBundle containing the mappings passed in.
|
||||
*
|
||||
@@ -101,6 +110,8 @@ public final class PersistableBundle extends BaseBundle implements Cloneable, Pa
|
||||
if (value instanceof ArrayMap) {
|
||||
// Fix up any Maps by replacing them with PersistableBundles.
|
||||
mMap.setValueAt(i, new PersistableBundle((ArrayMap<String, Object>) value));
|
||||
} else if (value instanceof Bundle) {
|
||||
mMap.setValueAt(i, new PersistableBundle(((Bundle) value)));
|
||||
} else if (!isValidType(value)) {
|
||||
throw new IllegalArgumentException("Bad value in PersistableBundle key="
|
||||
+ mMap.keyAt(i) + " value=" + value);
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
package com.android.server.pm;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.UserIdInt;
|
||||
import android.app.AppGlobals;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
@@ -27,8 +29,12 @@ import android.content.pm.IOnAppsChangedListener;
|
||||
import android.content.pm.IPackageManager;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.PackageManager.NameNotFoundException;
|
||||
import android.content.pm.ParceledListSlice;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.content.pm.ShortcutInfo;
|
||||
import android.content.pm.ShortcutServiceInternal;
|
||||
import android.content.pm.ShortcutServiceInternal.ShortcutChangeListener;
|
||||
import android.content.pm.UserInfo;
|
||||
import android.graphics.Rect;
|
||||
import android.net.Uri;
|
||||
@@ -44,15 +50,16 @@ import android.util.Log;
|
||||
import android.util.Slog;
|
||||
|
||||
import com.android.internal.content.PackageMonitor;
|
||||
import com.android.internal.util.Preconditions;
|
||||
import com.android.server.LocalServices;
|
||||
import com.android.server.SystemService;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Service that manages requests and callbacks for launchers that support
|
||||
* managed profiles.
|
||||
* managed profiles.
|
||||
*/
|
||||
|
||||
public class LauncherAppsService extends SystemService {
|
||||
|
||||
private final LauncherAppsImpl mLauncherAppsImpl;
|
||||
@@ -67,21 +74,25 @@ public class LauncherAppsService extends SystemService {
|
||||
publishBinderService(Context.LAUNCHER_APPS_SERVICE, mLauncherAppsImpl);
|
||||
}
|
||||
|
||||
class LauncherAppsImpl extends ILauncherApps.Stub {
|
||||
static class LauncherAppsImpl extends ILauncherApps.Stub {
|
||||
private static final boolean DEBUG = false;
|
||||
private static final String TAG = "LauncherAppsService";
|
||||
private final Context mContext;
|
||||
private final PackageManager mPm;
|
||||
private final UserManager mUm;
|
||||
private final ShortcutServiceInternal mShortcutServiceInternal;
|
||||
private final PackageCallbackList<IOnAppsChangedListener> mListeners
|
||||
= new PackageCallbackList<IOnAppsChangedListener>();
|
||||
|
||||
private MyPackageMonitor mPackageMonitor = new MyPackageMonitor();
|
||||
private final MyPackageMonitor mPackageMonitor = new MyPackageMonitor();
|
||||
|
||||
public LauncherAppsImpl(Context context) {
|
||||
mContext = context;
|
||||
mPm = mContext.getPackageManager();
|
||||
mUm = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
|
||||
mShortcutServiceInternal = Preconditions.checkNotNull(
|
||||
LocalServices.getService(ShortcutServiceInternal.class));
|
||||
mShortcutServiceInternal.addListener(mPackageMonitor);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -174,6 +185,20 @@ public class LauncherAppsService extends SystemService {
|
||||
}
|
||||
}
|
||||
|
||||
private void verifyCallingPackage(String callingPackage) {
|
||||
int packageUid = -1;
|
||||
try {
|
||||
packageUid = mPm.getPackageUid(callingPackage,
|
||||
PackageManager.MATCH_ENCRYPTION_AWARE_AND_UNAWARE
|
||||
| PackageManager.MATCH_UNINSTALLED_PACKAGES);
|
||||
} catch (NameNotFoundException e) {
|
||||
Log.e(TAG, "Package not found: " + callingPackage);
|
||||
}
|
||||
if (packageUid != Binder.getCallingUid()) {
|
||||
throw new SecurityException("Calling package name mismatch");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the user is enabled.
|
||||
*/
|
||||
@@ -264,6 +289,57 @@ public class LauncherAppsService extends SystemService {
|
||||
}
|
||||
}
|
||||
|
||||
private void enforceShortcutPermission(UserHandle user) {
|
||||
ensureInUserProfiles(user, "Cannot start activity for unrelated profile " + user);
|
||||
// STOPSHIP Implement it
|
||||
}
|
||||
|
||||
@Override
|
||||
public ParceledListSlice getShortcuts(String callingPackage, long changedSince,
|
||||
String packageName, ComponentName componentName, int flags, UserHandle user)
|
||||
throws RemoteException {
|
||||
enforceShortcutPermission(user);
|
||||
verifyCallingPackage(callingPackage);
|
||||
|
||||
return new ParceledListSlice<>(
|
||||
mShortcutServiceInternal.getShortcuts(callingPackage, changedSince, packageName,
|
||||
componentName, flags, user.getIdentifier()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ParceledListSlice getShortcutInfo(String callingPackage, String packageName,
|
||||
List<String> ids, UserHandle user) throws RemoteException {
|
||||
enforceShortcutPermission(user);
|
||||
verifyCallingPackage(callingPackage);
|
||||
|
||||
return new ParceledListSlice<>(
|
||||
mShortcutServiceInternal.getShortcutInfo(callingPackage, packageName,
|
||||
ids, user.getIdentifier()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void pinShortcuts(String callingPackage, String packageName, List<String> ids,
|
||||
UserHandle user) throws RemoteException {
|
||||
enforceShortcutPermission(user);
|
||||
verifyCallingPackage(callingPackage);
|
||||
|
||||
mShortcutServiceInternal.pinShortcuts(callingPackage, packageName,
|
||||
ids, user.getIdentifier());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startShortcut(String callingPackage, ShortcutInfo shortcut, Rect sourceBounds,
|
||||
Bundle startActivityOptions, UserHandle user) throws RemoteException {
|
||||
enforceShortcutPermission(user);
|
||||
verifyCallingPackage(callingPackage);
|
||||
|
||||
final Intent intent = mShortcutServiceInternal.createShortcutIntent(callingPackage,
|
||||
shortcut, user.getIdentifier());
|
||||
// TODO
|
||||
Slog.e(TAG, "startShortcut() not implemented yet, but the intent is " + intent);
|
||||
throw new RuntimeException("not implemented yet");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isActivityEnabled(ComponentName component, UserHandle user)
|
||||
throws RemoteException {
|
||||
@@ -355,7 +431,7 @@ public class LauncherAppsService extends SystemService {
|
||||
}
|
||||
|
||||
|
||||
private class MyPackageMonitor extends PackageMonitor {
|
||||
private class MyPackageMonitor extends PackageMonitor implements ShortcutChangeListener {
|
||||
|
||||
/** Checks if user is a profile of or same as listeningUser.
|
||||
* and the user is enabled. */
|
||||
@@ -390,6 +466,8 @@ public class LauncherAppsService extends SystemService {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO Simplify with lambdas.
|
||||
|
||||
@Override
|
||||
public void onPackageAdded(String packageName, int uid) {
|
||||
UserHandle user = new UserHandle(getChangingUserId());
|
||||
@@ -523,6 +601,25 @@ public class LauncherAppsService extends SystemService {
|
||||
super.onPackagesUnsuspended(packages);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onShortcutChanged(@NonNull String packageName,
|
||||
@NonNull List<ShortcutInfo> shortcuts, @UserIdInt int userId) {
|
||||
final UserHandle user = UserHandle.of(userId);
|
||||
|
||||
final int n = mListeners.beginBroadcast();
|
||||
for (int i = 0; i < n; i++) {
|
||||
IOnAppsChangedListener listener = mListeners.getBroadcastItem(i);
|
||||
UserHandle listeningUser = (UserHandle) mListeners.getBroadcastCookie(i);
|
||||
if (!isEnabledProfileOf(user, listeningUser, "onShortcutChanged")) continue;
|
||||
try {
|
||||
listener.onShortcutChanged(user, packageName,
|
||||
new ParceledListSlice<>(shortcuts));
|
||||
} catch (RemoteException re) {
|
||||
Slog.d(TAG, "Callback failed ", re);
|
||||
}
|
||||
}
|
||||
mListeners.finishBroadcast();
|
||||
}
|
||||
}
|
||||
|
||||
class PackageCallbackList<T extends IInterface> extends RemoteCallbackList<T> {
|
||||
|
||||
1529
services/core/java/com/android/server/pm/ShortcutService.java
Normal file
1529
services/core/java/com/android/server/pm/ShortcutService.java
Normal file
File diff suppressed because it is too large
Load Diff
@@ -494,7 +494,6 @@ class Owners {
|
||||
abstract void writeInner(XmlSerializer out) throws IOException;
|
||||
|
||||
abstract boolean readInner(XmlPullParser parser, int depth, String tag);
|
||||
|
||||
}
|
||||
|
||||
private class DeviceOwnerReadWriter extends FileReadWriter {
|
||||
|
||||
@@ -83,6 +83,7 @@ import com.android.server.pm.Installer;
|
||||
import com.android.server.pm.LauncherAppsService;
|
||||
import com.android.server.pm.OtaDexoptService;
|
||||
import com.android.server.pm.PackageManagerService;
|
||||
import com.android.server.pm.ShortcutService;
|
||||
import com.android.server.pm.UserManagerService;
|
||||
import com.android.server.power.PowerManagerService;
|
||||
import com.android.server.power.ShutdownThread;
|
||||
@@ -726,6 +727,9 @@ public final class SystemServer {
|
||||
// Always start the Device Policy Manager, so that the API is compatible with
|
||||
// API8.
|
||||
mSystemServiceManager.startService(DevicePolicyManagerService.Lifecycle.class);
|
||||
|
||||
// TODO is this a good place?
|
||||
mSystemServiceManager.startService(ShortcutService.Lifecycle.class);
|
||||
}
|
||||
|
||||
if (!disableSystemUI) {
|
||||
|
||||
@@ -106,6 +106,10 @@
|
||||
|
||||
<service android:name="com.android.server.job.MockPriorityJobService"
|
||||
android:permission="android.permission.BIND_JOB_SERVICE" />
|
||||
|
||||
<activity android:name="com.android.server.pm.ShortcutManagerTest$ShortcutActivity" />
|
||||
<activity android:name="com.android.server.pm.ShortcutManagerTest$ShortcutActivity2" />
|
||||
<activity android:name="com.android.server.pm.ShortcutManagerTest$ShortcutActivity3" />
|
||||
</application>
|
||||
|
||||
<instrumentation
|
||||
|
||||
BIN
services/tests/servicestests/res/drawable/icon1.png
Normal file
BIN
services/tests/servicestests/res/drawable/icon1.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 5.7 KiB |
BIN
services/tests/servicestests/res/drawable/icon2.png
Normal file
BIN
services/tests/servicestests/res/drawable/icon2.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.1 KiB |
@@ -0,0 +1,44 @@
|
||||
|
||||
/*
|
||||
* Copyright (C) 2016 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.android.server.pm;
|
||||
|
||||
import android.content.pm.ShortcutInfo;
|
||||
import android.test.AndroidTestCase;
|
||||
|
||||
import com.android.server.testutis.TestUtils;
|
||||
|
||||
/**
|
||||
* Tests for {@link ShortcutInfo}.
|
||||
|
||||
m FrameworksServicesTests &&
|
||||
adb install \
|
||||
-r -g ${ANDROID_PRODUCT_OUT}/data/app/FrameworksServicesTests/FrameworksServicesTests.apk &&
|
||||
adb shell am instrument -e class com.android.server.pm.ShortcutInfoTest \
|
||||
-w com.android.frameworks.servicestests/android.support.test.runner.AndroidJUnitRunner
|
||||
|
||||
*/
|
||||
public class ShortcutInfoTest extends AndroidTestCase {
|
||||
|
||||
public void testNoId() {
|
||||
TestUtils.assertExpectException(
|
||||
IllegalArgumentException.class,
|
||||
"ID must be provided",
|
||||
() -> new ShortcutInfo.Builder(mContext).build());
|
||||
}
|
||||
|
||||
// TODO Add more tests.
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (C) 2016 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.android.server.testutis;
|
||||
|
||||
import android.test.MoreAsserts;
|
||||
|
||||
import junit.framework.Assert;
|
||||
|
||||
public class TestUtils {
|
||||
private TestUtils() {
|
||||
}
|
||||
|
||||
public static void assertExpectException(Class<? extends Throwable> expectedExceptionType,
|
||||
Runnable r) {
|
||||
assertExpectException(expectedExceptionType, null, r);
|
||||
}
|
||||
|
||||
public static void assertExpectException(Class<? extends Throwable> expectedExceptionType,
|
||||
String expectedExceptionMessageRegex, Runnable r) {
|
||||
try {
|
||||
r.run();
|
||||
Assert.fail("Expected exception type " + expectedExceptionType.getClass().getName()
|
||||
+ " was not thrown");
|
||||
} catch (Throwable e) {
|
||||
Assert.assertTrue(
|
||||
"Expected exception type was " + expectedExceptionType.getClass().getName()
|
||||
+ " but caught " + e.getClass().getName(),
|
||||
expectedExceptionType.isAssignableFrom(e.getClass()));
|
||||
if (expectedExceptionMessageRegex != null) {
|
||||
MoreAsserts.assertContainsRegex(expectedExceptionMessageRegex, e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user