Loading api/current.txt +8 −0 Original line number Diff line number Diff line Loading @@ -11000,6 +11000,7 @@ package android.content.pm { method public android.content.ComponentName getActivity(); method public java.util.Set<java.lang.String> getCategories(); method public java.lang.CharSequence getDisabledMessage(); method public int getDisabledReason(); method public android.os.PersistableBundle getExtras(); method public java.lang.String getId(); method public android.content.Intent getIntent(); Loading @@ -11018,6 +11019,13 @@ package android.content.pm { method public boolean isPinned(); method public void writeToParcel(android.os.Parcel, int); field public static final android.os.Parcelable.Creator<android.content.pm.ShortcutInfo> CREATOR; field public static final int DISABLED_REASON_APP_CHANGED = 2; // 0x2 field public static final int DISABLED_REASON_BACKUP_NOT_SUPPORTED = 101; // 0x65 field public static final int DISABLED_REASON_BY_APP = 1; // 0x1 field public static final int DISABLED_REASON_NOT_DISABLED = 0; // 0x0 field public static final int DISABLED_REASON_OTHER_RESTORE_ISSUE = 103; // 0x67 field public static final int DISABLED_REASON_SIGNATURE_MISMATCH = 102; // 0x66 field public static final int DISABLED_REASON_VERSION_LOWER = 100; // 0x64 field public static final java.lang.String SHORTCUT_CATEGORY_CONVERSATION = "android.shortcut.conversation"; } api/system-current.txt +8 −0 Original line number Diff line number Diff line Loading @@ -11723,6 +11723,7 @@ package android.content.pm { method public android.content.ComponentName getActivity(); method public java.util.Set<java.lang.String> getCategories(); method public java.lang.CharSequence getDisabledMessage(); method public int getDisabledReason(); method public android.os.PersistableBundle getExtras(); method public java.lang.String getId(); method public android.content.Intent getIntent(); Loading @@ -11741,6 +11742,13 @@ package android.content.pm { method public boolean isPinned(); method public void writeToParcel(android.os.Parcel, int); field public static final android.os.Parcelable.Creator<android.content.pm.ShortcutInfo> CREATOR; field public static final int DISABLED_REASON_APP_CHANGED = 2; // 0x2 field public static final int DISABLED_REASON_BACKUP_NOT_SUPPORTED = 101; // 0x65 field public static final int DISABLED_REASON_BY_APP = 1; // 0x1 field public static final int DISABLED_REASON_NOT_DISABLED = 0; // 0x0 field public static final int DISABLED_REASON_OTHER_RESTORE_ISSUE = 103; // 0x67 field public static final int DISABLED_REASON_SIGNATURE_MISMATCH = 102; // 0x66 field public static final int DISABLED_REASON_VERSION_LOWER = 100; // 0x64 field public static final java.lang.String SHORTCUT_CATEGORY_CONVERSATION = "android.shortcut.conversation"; } api/test-current.txt +9 −0 Original line number Diff line number Diff line Loading @@ -11081,6 +11081,7 @@ package android.content.pm { method public android.content.ComponentName getActivity(); method public java.util.Set<java.lang.String> getCategories(); method public java.lang.CharSequence getDisabledMessage(); method public int getDisabledReason(); method public android.os.PersistableBundle getExtras(); method public java.lang.String getId(); method public android.content.Intent getIntent(); Loading @@ -11097,8 +11098,16 @@ package android.content.pm { method public boolean isEnabled(); method public boolean isImmutable(); method public boolean isPinned(); method public boolean isVisibleToPublisher(); method public void writeToParcel(android.os.Parcel, int); field public static final android.os.Parcelable.Creator<android.content.pm.ShortcutInfo> CREATOR; field public static final int DISABLED_REASON_APP_CHANGED = 2; // 0x2 field public static final int DISABLED_REASON_BACKUP_NOT_SUPPORTED = 101; // 0x65 field public static final int DISABLED_REASON_BY_APP = 1; // 0x1 field public static final int DISABLED_REASON_NOT_DISABLED = 0; // 0x0 field public static final int DISABLED_REASON_OTHER_RESTORE_ISSUE = 103; // 0x67 field public static final int DISABLED_REASON_SIGNATURE_MISMATCH = 102; // 0x66 field public static final int DISABLED_REASON_VERSION_LOWER = 100; // 0x64 field public static final java.lang.String SHORTCUT_CATEGORY_CONVERSATION = "android.shortcut.conversation"; } core/java/android/content/pm/ShortcutInfo.java +169 −5 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ package android.content.pm; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.TestApi; import android.annotation.UserIdInt; import android.app.TaskStackBuilder; import android.content.ComponentName; Loading Loading @@ -100,6 +101,13 @@ public final class ShortcutInfo implements Parcelable { /** @hide When this is set, the bitmap icon is waiting to be saved. */ public static final int FLAG_ICON_FILE_PENDING_SAVE = 1 << 11; /** * "Shadow" shortcuts are the ones that are restored, but the owner package hasn't been * installed yet. * @hide */ public static final int FLAG_SHADOW = 1 << 12; /** @hide */ @IntDef(flag = true, value = { Loading Loading @@ -157,6 +165,91 @@ public final class ShortcutInfo implements Parcelable { @Retention(RetentionPolicy.SOURCE) public @interface CloneFlags {} /** * Shortcut is not disabled. */ public static final int DISABLED_REASON_NOT_DISABLED = 0; /** * Shortcut has been disabled by the publisher app with the * {@link ShortcutManager#disableShortcuts(List)} API. */ public static final int DISABLED_REASON_BY_APP = 1; /** * Shortcut has been disabled due to changes to the publisher app. (e.g. a manifest shortcut * no longer exists.) */ public static final int DISABLED_REASON_APP_CHANGED = 2; /** * A disabled reason that's equal to or bigger than this is due to backup and restore issue. * A shortcut with such a reason wil be visible to the launcher, but not to the publisher. * ({@link #isVisibleToPublisher()} will be false.) */ private static final int DISABLED_REASON_RESTORE_ISSUE_START = 100; /** * Shortcut has been restored from the previous device, but the publisher app on the current * device is of a lower version. The shortcut will not be usable until the app is upgraded to * the same version or higher. */ public static final int DISABLED_REASON_VERSION_LOWER = 100; /** * Shortcut has not been restored because the publisher app does not support backup and restore. */ public static final int DISABLED_REASON_BACKUP_NOT_SUPPORTED = 101; /** * Shortcut has not been restored because the publisher app's signature has changed. */ public static final int DISABLED_REASON_SIGNATURE_MISMATCH = 102; /** * Shortcut has not been restored for unknown reason. */ public static final int DISABLED_REASON_OTHER_RESTORE_ISSUE = 103; /** @hide */ @IntDef(value = { DISABLED_REASON_NOT_DISABLED, DISABLED_REASON_BY_APP, DISABLED_REASON_APP_CHANGED, DISABLED_REASON_VERSION_LOWER, DISABLED_REASON_BACKUP_NOT_SUPPORTED, DISABLED_REASON_SIGNATURE_MISMATCH, DISABLED_REASON_OTHER_RESTORE_ISSUE, }) @Retention(RetentionPolicy.SOURCE) public @interface DisabledReason{} /** @hide */ public static String getDisabledReasonLabel(@DisabledReason int disabledReason) { switch (disabledReason) { case DISABLED_REASON_NOT_DISABLED: return "[Not disabled]"; case DISABLED_REASON_BY_APP: return "[Disabled: by app]"; case DISABLED_REASON_APP_CHANGED: return "[Disabled: app changed]"; case DISABLED_REASON_VERSION_LOWER: return "[Disabled: lower version]"; case DISABLED_REASON_BACKUP_NOT_SUPPORTED: return "[Disabled: backup not supported]"; case DISABLED_REASON_SIGNATURE_MISMATCH: return "[Disabled: signature mismatch]"; case DISABLED_REASON_OTHER_RESTORE_ISSUE: return "[Disabled: unknown restore issue]"; } return "[Disabled: unknown reason:" + disabledReason + "]"; } /** @hide */ public static boolean isDisabledForRestoreIssue(@DisabledReason int disabledReason) { return disabledReason >= DISABLED_REASON_RESTORE_ISSUE_START; } /** * Shortcut category for messaging related actions, such as chat. */ Loading Loading @@ -240,6 +333,11 @@ public final class ShortcutInfo implements Parcelable { private final int mUserId; /** @hide */ public static final int VERSION_CODE_UNKNOWN = -1; private int mDisabledReason; private ShortcutInfo(Builder b) { mUserId = b.mContext.getUserId(); Loading Loading @@ -352,6 +450,7 @@ public final class ShortcutInfo implements Parcelable { mActivity = source.mActivity; mFlags = source.mFlags; mLastChangedTimestamp = source.mLastChangedTimestamp; mDisabledReason = source.mDisabledReason; // Just always keep it since it's cheep. mIconResId = source.mIconResId; Loading Loading @@ -615,14 +714,24 @@ public final class ShortcutInfo implements Parcelable { /** * @hide * * @isUpdating set true if it's "update", as opposed to "replace". */ public void ensureUpdatableWith(ShortcutInfo source) { public void ensureUpdatableWith(ShortcutInfo source, boolean isUpdating) { if (isUpdating) { Preconditions.checkState(isVisibleToPublisher(), "[Framework BUG] Invisible shortcuts can't be updated"); } Preconditions.checkState(mUserId == source.mUserId, "Owner User ID must match"); Preconditions.checkState(mId.equals(source.mId), "ID must match"); Preconditions.checkState(mPackageName.equals(source.mPackageName), "Package name must match"); if (isVisibleToPublisher()) { // Don't do this check for restore-blocked shortcuts. Preconditions.checkState(!isImmutable(), "Target ShortcutInfo is immutable"); } } /** * Copy non-null/zero fields from another {@link ShortcutInfo}. Only "public" information Loading @@ -638,7 +747,7 @@ public final class ShortcutInfo implements Parcelable { * @hide */ public void copyNonNullFieldsFrom(ShortcutInfo source) { ensureUpdatableWith(source); ensureUpdatableWith(source, /*isUpdating=*/ true); if (source.mActivity != null) { mActivity = source.mActivity; Loading Loading @@ -1169,6 +1278,19 @@ public final class ShortcutInfo implements Parcelable { return mDisabledMessageResId; } /** @hide */ public void setDisabledReason(@DisabledReason int reason) { mDisabledReason = reason; } /** * Returns why a shortcut has been disabled. */ @DisabledReason public int getDisabledReason() { return mDisabledReason; } /** * Return the shortcut's categories. * Loading Loading @@ -1403,6 +1525,21 @@ public final class ShortcutInfo implements Parcelable { return hasFlags(FLAG_IMMUTABLE); } /** @hide */ public boolean isDynamicVisible() { return isDynamic() && isVisibleToPublisher(); } /** @hide */ public boolean isPinnedVisible() { return isPinned() && isVisibleToPublisher(); } /** @hide */ public boolean isManifestVisible() { return isDeclaredInManifest() && isVisibleToPublisher(); } /** * Return if a shortcut is immutable, in which case it cannot be modified with any of * {@link ShortcutManager} APIs. Loading Loading @@ -1490,6 +1627,18 @@ public final class ShortcutInfo implements Parcelable { clearFlags(FLAG_ICON_FILE_PENDING_SAVE); } /** * When the system wasn't able to restore a shortcut, it'll still be registered to the system * but disabled, and such shortcuts will not be visible to the publisher. They're still visible * to launchers though. * * @hide */ @TestApi public boolean isVisibleToPublisher() { return !isDisabledForRestoreIssue(mDisabledReason); } /** * Return whether a shortcut only contains "key" information only or not. If true, only the * following fields are available. Loading Loading @@ -1668,6 +1817,7 @@ public final class ShortcutInfo implements Parcelable { mFlags = source.readInt(); mIconResId = source.readInt(); mLastChangedTimestamp = source.readLong(); mDisabledReason = source.readInt(); if (source.readInt() == 0) { return; // key information only. Loading Loading @@ -1711,6 +1861,7 @@ public final class ShortcutInfo implements Parcelable { dest.writeInt(mFlags); dest.writeInt(mIconResId); dest.writeLong(mLastChangedTimestamp); dest.writeInt(mDisabledReason); if (hasKeyFieldsOnly()) { dest.writeInt(0); Loading Loading @@ -1808,6 +1959,11 @@ public final class ShortcutInfo implements Parcelable { sb.append(", flags=0x"); sb.append(Integer.toHexString(mFlags)); sb.append(" ["); if ((mFlags & FLAG_SHADOW) != 0) { // Note the shadow flag isn't actually used anywhere and it's just for dumpsys, so // we don't have an isXxx for this. sb.append("Sdw"); } if (!isEnabled()) { sb.append("Dis"); } Loading Loading @@ -1848,7 +2004,9 @@ public final class ShortcutInfo implements Parcelable { sb.append("packageName="); sb.append(mPackageName); sb.append(", activity="); addIndentOrComma(sb, indent); sb.append("activity="); sb.append(mActivity); addIndentOrComma(sb, indent); Loading Loading @@ -1883,6 +2041,11 @@ public final class ShortcutInfo implements Parcelable { addIndentOrComma(sb, indent); sb.append("disabledReason="); sb.append(getDisabledReasonLabel(mDisabledReason)); addIndentOrComma(sb, indent); sb.append("categories="); sb.append(mCategories); Loading Loading @@ -1953,7 +2116,7 @@ public final class ShortcutInfo implements Parcelable { CharSequence disabledMessage, int disabledMessageResId, String disabledMessageResName, Set<String> categories, Intent[] intentsWithExtras, int rank, PersistableBundle extras, long lastChangedTimestamp, int flags, int iconResId, String iconResName, String bitmapPath) { int flags, int iconResId, String iconResName, String bitmapPath, int disabledReason) { mUserId = userId; mId = id; mPackageName = packageName; Loading @@ -1978,5 +2141,6 @@ public final class ShortcutInfo implements Parcelable { mIconResId = iconResId; mIconResName = iconResName; mBitmapPath = bitmapPath; mDisabledReason = disabledReason; } } services/core/java/com/android/server/pm/ShortcutLauncher.java +37 −16 Original line number Diff line number Diff line Loading @@ -83,11 +83,16 @@ class ShortcutLauncher extends ShortcutPackageItem { return mOwnerUserId; } @Override protected boolean canRestoreAnyVersion() { // Launcher's pinned shortcuts can be restored to an older version. return true; } /** * Called when the new package can't receive the backup, due to signature or version mismatch. */ @Override protected void onRestoreBlocked() { private void onRestoreBlocked() { final ArrayList<PackageWithUser> pinnedPackages = new ArrayList<>(mPinnedShortcuts.keySet()); mPinnedShortcuts.clear(); Loading @@ -101,15 +106,21 @@ class ShortcutLauncher extends ShortcutPackageItem { } @Override protected void onRestored() { // Nothing to do. protected void onRestored(int restoreBlockReason) { // For launcher, possible reasons here are DISABLED_REASON_SIGNATURE_MISMATCH or // DISABLED_REASON_BACKUP_NOT_SUPPORTED. // DISABLED_REASON_VERSION_LOWER will NOT happen because we don't check version // code for launchers. if (restoreBlockReason != ShortcutInfo.DISABLED_REASON_NOT_DISABLED) { onRestoreBlocked(); } } /** * Pin the given shortcuts, replacing the current pinned ones. */ public void pinShortcuts(@UserIdInt int packageUserId, @NonNull String packageName, @NonNull List<String> ids) { @NonNull String packageName, @NonNull List<String> ids, boolean forPinRequest) { final ShortcutPackage packageShortcuts = mShortcutUser.getPackageShortcutsIfExists(packageName); if (packageShortcuts == null) { Loading @@ -124,8 +135,12 @@ class ShortcutLauncher extends ShortcutPackageItem { } else { final ArraySet<String> prevSet = mPinnedShortcuts.get(pu); // Pin shortcuts. Make sure only pin the ones that were visible to the caller. // i.e. a non-dynamic, pinned shortcut by *other launchers* shouldn't be pinned here. // Actually pin shortcuts. // This logic here is to make sure a launcher cannot pin a shortcut that is floating // (i.e. not dynamic nor manifest but is pinned) and pinned by another launcher. // In this case, technically the shortcut doesn't exist to this launcher, so it can't // pin it. // (Maybe unnecessarily strict...) final ArraySet<String> newSet = new ArraySet<>(); Loading @@ -135,8 +150,10 @@ class ShortcutLauncher extends ShortcutPackageItem { if (si == null) { continue; } if (si.isDynamic() || si.isManifestShortcut() || (prevSet != null && prevSet.contains(id))) { if (si.isDynamic() || si.isManifestShortcut() || (prevSet != null && prevSet.contains(id)) || forPinRequest) { newSet.add(id); } } Loading @@ -155,7 +172,7 @@ class ShortcutLauncher extends ShortcutPackageItem { } /** * Return true if the given shortcut is pinned by this launcher. * Return true if the given shortcut is pinned by this launcher.<code></code> */ public boolean hasPinned(ShortcutInfo shortcut) { final ArraySet<String> pinned = Loading @@ -164,10 +181,10 @@ class ShortcutLauncher extends ShortcutPackageItem { } /** * Additionally pin a shortcut. c.f. {@link #pinShortcuts(int, String, List)} * Additionally pin a shortcut. c.f. {@link #pinShortcuts(int, String, List, boolean)} */ public void addPinnedShortcut(@NonNull String packageName, @UserIdInt int packageUserId, String id) { String id, boolean forPinRequest) { final ArraySet<String> pinnedSet = getPinnedShortcutIds(packageName, packageUserId); final ArrayList<String> pinnedList; if (pinnedSet != null) { Loading @@ -178,21 +195,21 @@ class ShortcutLauncher extends ShortcutPackageItem { } pinnedList.add(id); pinShortcuts(packageUserId, packageName, pinnedList); pinShortcuts(packageUserId, packageName, pinnedList, forPinRequest); } boolean cleanUpPackage(String packageName, @UserIdInt int packageUserId) { return mPinnedShortcuts.remove(PackageWithUser.of(packageUserId, packageName)) != null; } public void ensureVersionInfo() { public void ensurePackageInfo() { final PackageInfo pi = mShortcutUser.mService.getPackageInfoWithSignatures( getPackageName(), getPackageUserId()); if (pi == null) { Slog.w(TAG, "Package not found: " + getPackageName()); return; } getPackageInfo().updateVersionInfo(pi); getPackageInfo().updateFromPackageInfo(pi); } /** Loading @@ -201,6 +218,10 @@ class ShortcutLauncher extends ShortcutPackageItem { @Override public void saveToXml(XmlSerializer out, boolean forBackup) throws IOException { if (forBackup && !getPackageInfo().isBackupAllowed()) { // If an launcher app doesn't support backup&restore, then nothing to do. return; } final int size = mPinnedShortcuts.size(); if (size == 0) { return; // Nothing to write. Loading @@ -209,7 +230,7 @@ class ShortcutLauncher extends ShortcutPackageItem { out.startTag(null, TAG_ROOT); ShortcutService.writeAttr(out, ATTR_PACKAGE_NAME, getPackageName()); ShortcutService.writeAttr(out, ATTR_LAUNCHER_USER_ID, getPackageUserId()); getPackageInfo().saveToXml(out); getPackageInfo().saveToXml(out, forBackup); for (int i = 0; i < size; i++) { final PackageWithUser pu = mPinnedShortcuts.keyAt(i); Loading Loading
api/current.txt +8 −0 Original line number Diff line number Diff line Loading @@ -11000,6 +11000,7 @@ package android.content.pm { method public android.content.ComponentName getActivity(); method public java.util.Set<java.lang.String> getCategories(); method public java.lang.CharSequence getDisabledMessage(); method public int getDisabledReason(); method public android.os.PersistableBundle getExtras(); method public java.lang.String getId(); method public android.content.Intent getIntent(); Loading @@ -11018,6 +11019,13 @@ package android.content.pm { method public boolean isPinned(); method public void writeToParcel(android.os.Parcel, int); field public static final android.os.Parcelable.Creator<android.content.pm.ShortcutInfo> CREATOR; field public static final int DISABLED_REASON_APP_CHANGED = 2; // 0x2 field public static final int DISABLED_REASON_BACKUP_NOT_SUPPORTED = 101; // 0x65 field public static final int DISABLED_REASON_BY_APP = 1; // 0x1 field public static final int DISABLED_REASON_NOT_DISABLED = 0; // 0x0 field public static final int DISABLED_REASON_OTHER_RESTORE_ISSUE = 103; // 0x67 field public static final int DISABLED_REASON_SIGNATURE_MISMATCH = 102; // 0x66 field public static final int DISABLED_REASON_VERSION_LOWER = 100; // 0x64 field public static final java.lang.String SHORTCUT_CATEGORY_CONVERSATION = "android.shortcut.conversation"; }
api/system-current.txt +8 −0 Original line number Diff line number Diff line Loading @@ -11723,6 +11723,7 @@ package android.content.pm { method public android.content.ComponentName getActivity(); method public java.util.Set<java.lang.String> getCategories(); method public java.lang.CharSequence getDisabledMessage(); method public int getDisabledReason(); method public android.os.PersistableBundle getExtras(); method public java.lang.String getId(); method public android.content.Intent getIntent(); Loading @@ -11741,6 +11742,13 @@ package android.content.pm { method public boolean isPinned(); method public void writeToParcel(android.os.Parcel, int); field public static final android.os.Parcelable.Creator<android.content.pm.ShortcutInfo> CREATOR; field public static final int DISABLED_REASON_APP_CHANGED = 2; // 0x2 field public static final int DISABLED_REASON_BACKUP_NOT_SUPPORTED = 101; // 0x65 field public static final int DISABLED_REASON_BY_APP = 1; // 0x1 field public static final int DISABLED_REASON_NOT_DISABLED = 0; // 0x0 field public static final int DISABLED_REASON_OTHER_RESTORE_ISSUE = 103; // 0x67 field public static final int DISABLED_REASON_SIGNATURE_MISMATCH = 102; // 0x66 field public static final int DISABLED_REASON_VERSION_LOWER = 100; // 0x64 field public static final java.lang.String SHORTCUT_CATEGORY_CONVERSATION = "android.shortcut.conversation"; }
api/test-current.txt +9 −0 Original line number Diff line number Diff line Loading @@ -11081,6 +11081,7 @@ package android.content.pm { method public android.content.ComponentName getActivity(); method public java.util.Set<java.lang.String> getCategories(); method public java.lang.CharSequence getDisabledMessage(); method public int getDisabledReason(); method public android.os.PersistableBundle getExtras(); method public java.lang.String getId(); method public android.content.Intent getIntent(); Loading @@ -11097,8 +11098,16 @@ package android.content.pm { method public boolean isEnabled(); method public boolean isImmutable(); method public boolean isPinned(); method public boolean isVisibleToPublisher(); method public void writeToParcel(android.os.Parcel, int); field public static final android.os.Parcelable.Creator<android.content.pm.ShortcutInfo> CREATOR; field public static final int DISABLED_REASON_APP_CHANGED = 2; // 0x2 field public static final int DISABLED_REASON_BACKUP_NOT_SUPPORTED = 101; // 0x65 field public static final int DISABLED_REASON_BY_APP = 1; // 0x1 field public static final int DISABLED_REASON_NOT_DISABLED = 0; // 0x0 field public static final int DISABLED_REASON_OTHER_RESTORE_ISSUE = 103; // 0x67 field public static final int DISABLED_REASON_SIGNATURE_MISMATCH = 102; // 0x66 field public static final int DISABLED_REASON_VERSION_LOWER = 100; // 0x64 field public static final java.lang.String SHORTCUT_CATEGORY_CONVERSATION = "android.shortcut.conversation"; }
core/java/android/content/pm/ShortcutInfo.java +169 −5 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ package android.content.pm; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.TestApi; import android.annotation.UserIdInt; import android.app.TaskStackBuilder; import android.content.ComponentName; Loading Loading @@ -100,6 +101,13 @@ public final class ShortcutInfo implements Parcelable { /** @hide When this is set, the bitmap icon is waiting to be saved. */ public static final int FLAG_ICON_FILE_PENDING_SAVE = 1 << 11; /** * "Shadow" shortcuts are the ones that are restored, but the owner package hasn't been * installed yet. * @hide */ public static final int FLAG_SHADOW = 1 << 12; /** @hide */ @IntDef(flag = true, value = { Loading Loading @@ -157,6 +165,91 @@ public final class ShortcutInfo implements Parcelable { @Retention(RetentionPolicy.SOURCE) public @interface CloneFlags {} /** * Shortcut is not disabled. */ public static final int DISABLED_REASON_NOT_DISABLED = 0; /** * Shortcut has been disabled by the publisher app with the * {@link ShortcutManager#disableShortcuts(List)} API. */ public static final int DISABLED_REASON_BY_APP = 1; /** * Shortcut has been disabled due to changes to the publisher app. (e.g. a manifest shortcut * no longer exists.) */ public static final int DISABLED_REASON_APP_CHANGED = 2; /** * A disabled reason that's equal to or bigger than this is due to backup and restore issue. * A shortcut with such a reason wil be visible to the launcher, but not to the publisher. * ({@link #isVisibleToPublisher()} will be false.) */ private static final int DISABLED_REASON_RESTORE_ISSUE_START = 100; /** * Shortcut has been restored from the previous device, but the publisher app on the current * device is of a lower version. The shortcut will not be usable until the app is upgraded to * the same version or higher. */ public static final int DISABLED_REASON_VERSION_LOWER = 100; /** * Shortcut has not been restored because the publisher app does not support backup and restore. */ public static final int DISABLED_REASON_BACKUP_NOT_SUPPORTED = 101; /** * Shortcut has not been restored because the publisher app's signature has changed. */ public static final int DISABLED_REASON_SIGNATURE_MISMATCH = 102; /** * Shortcut has not been restored for unknown reason. */ public static final int DISABLED_REASON_OTHER_RESTORE_ISSUE = 103; /** @hide */ @IntDef(value = { DISABLED_REASON_NOT_DISABLED, DISABLED_REASON_BY_APP, DISABLED_REASON_APP_CHANGED, DISABLED_REASON_VERSION_LOWER, DISABLED_REASON_BACKUP_NOT_SUPPORTED, DISABLED_REASON_SIGNATURE_MISMATCH, DISABLED_REASON_OTHER_RESTORE_ISSUE, }) @Retention(RetentionPolicy.SOURCE) public @interface DisabledReason{} /** @hide */ public static String getDisabledReasonLabel(@DisabledReason int disabledReason) { switch (disabledReason) { case DISABLED_REASON_NOT_DISABLED: return "[Not disabled]"; case DISABLED_REASON_BY_APP: return "[Disabled: by app]"; case DISABLED_REASON_APP_CHANGED: return "[Disabled: app changed]"; case DISABLED_REASON_VERSION_LOWER: return "[Disabled: lower version]"; case DISABLED_REASON_BACKUP_NOT_SUPPORTED: return "[Disabled: backup not supported]"; case DISABLED_REASON_SIGNATURE_MISMATCH: return "[Disabled: signature mismatch]"; case DISABLED_REASON_OTHER_RESTORE_ISSUE: return "[Disabled: unknown restore issue]"; } return "[Disabled: unknown reason:" + disabledReason + "]"; } /** @hide */ public static boolean isDisabledForRestoreIssue(@DisabledReason int disabledReason) { return disabledReason >= DISABLED_REASON_RESTORE_ISSUE_START; } /** * Shortcut category for messaging related actions, such as chat. */ Loading Loading @@ -240,6 +333,11 @@ public final class ShortcutInfo implements Parcelable { private final int mUserId; /** @hide */ public static final int VERSION_CODE_UNKNOWN = -1; private int mDisabledReason; private ShortcutInfo(Builder b) { mUserId = b.mContext.getUserId(); Loading Loading @@ -352,6 +450,7 @@ public final class ShortcutInfo implements Parcelable { mActivity = source.mActivity; mFlags = source.mFlags; mLastChangedTimestamp = source.mLastChangedTimestamp; mDisabledReason = source.mDisabledReason; // Just always keep it since it's cheep. mIconResId = source.mIconResId; Loading Loading @@ -615,14 +714,24 @@ public final class ShortcutInfo implements Parcelable { /** * @hide * * @isUpdating set true if it's "update", as opposed to "replace". */ public void ensureUpdatableWith(ShortcutInfo source) { public void ensureUpdatableWith(ShortcutInfo source, boolean isUpdating) { if (isUpdating) { Preconditions.checkState(isVisibleToPublisher(), "[Framework BUG] Invisible shortcuts can't be updated"); } Preconditions.checkState(mUserId == source.mUserId, "Owner User ID must match"); Preconditions.checkState(mId.equals(source.mId), "ID must match"); Preconditions.checkState(mPackageName.equals(source.mPackageName), "Package name must match"); if (isVisibleToPublisher()) { // Don't do this check for restore-blocked shortcuts. Preconditions.checkState(!isImmutable(), "Target ShortcutInfo is immutable"); } } /** * Copy non-null/zero fields from another {@link ShortcutInfo}. Only "public" information Loading @@ -638,7 +747,7 @@ public final class ShortcutInfo implements Parcelable { * @hide */ public void copyNonNullFieldsFrom(ShortcutInfo source) { ensureUpdatableWith(source); ensureUpdatableWith(source, /*isUpdating=*/ true); if (source.mActivity != null) { mActivity = source.mActivity; Loading Loading @@ -1169,6 +1278,19 @@ public final class ShortcutInfo implements Parcelable { return mDisabledMessageResId; } /** @hide */ public void setDisabledReason(@DisabledReason int reason) { mDisabledReason = reason; } /** * Returns why a shortcut has been disabled. */ @DisabledReason public int getDisabledReason() { return mDisabledReason; } /** * Return the shortcut's categories. * Loading Loading @@ -1403,6 +1525,21 @@ public final class ShortcutInfo implements Parcelable { return hasFlags(FLAG_IMMUTABLE); } /** @hide */ public boolean isDynamicVisible() { return isDynamic() && isVisibleToPublisher(); } /** @hide */ public boolean isPinnedVisible() { return isPinned() && isVisibleToPublisher(); } /** @hide */ public boolean isManifestVisible() { return isDeclaredInManifest() && isVisibleToPublisher(); } /** * Return if a shortcut is immutable, in which case it cannot be modified with any of * {@link ShortcutManager} APIs. Loading Loading @@ -1490,6 +1627,18 @@ public final class ShortcutInfo implements Parcelable { clearFlags(FLAG_ICON_FILE_PENDING_SAVE); } /** * When the system wasn't able to restore a shortcut, it'll still be registered to the system * but disabled, and such shortcuts will not be visible to the publisher. They're still visible * to launchers though. * * @hide */ @TestApi public boolean isVisibleToPublisher() { return !isDisabledForRestoreIssue(mDisabledReason); } /** * Return whether a shortcut only contains "key" information only or not. If true, only the * following fields are available. Loading Loading @@ -1668,6 +1817,7 @@ public final class ShortcutInfo implements Parcelable { mFlags = source.readInt(); mIconResId = source.readInt(); mLastChangedTimestamp = source.readLong(); mDisabledReason = source.readInt(); if (source.readInt() == 0) { return; // key information only. Loading Loading @@ -1711,6 +1861,7 @@ public final class ShortcutInfo implements Parcelable { dest.writeInt(mFlags); dest.writeInt(mIconResId); dest.writeLong(mLastChangedTimestamp); dest.writeInt(mDisabledReason); if (hasKeyFieldsOnly()) { dest.writeInt(0); Loading Loading @@ -1808,6 +1959,11 @@ public final class ShortcutInfo implements Parcelable { sb.append(", flags=0x"); sb.append(Integer.toHexString(mFlags)); sb.append(" ["); if ((mFlags & FLAG_SHADOW) != 0) { // Note the shadow flag isn't actually used anywhere and it's just for dumpsys, so // we don't have an isXxx for this. sb.append("Sdw"); } if (!isEnabled()) { sb.append("Dis"); } Loading Loading @@ -1848,7 +2004,9 @@ public final class ShortcutInfo implements Parcelable { sb.append("packageName="); sb.append(mPackageName); sb.append(", activity="); addIndentOrComma(sb, indent); sb.append("activity="); sb.append(mActivity); addIndentOrComma(sb, indent); Loading Loading @@ -1883,6 +2041,11 @@ public final class ShortcutInfo implements Parcelable { addIndentOrComma(sb, indent); sb.append("disabledReason="); sb.append(getDisabledReasonLabel(mDisabledReason)); addIndentOrComma(sb, indent); sb.append("categories="); sb.append(mCategories); Loading Loading @@ -1953,7 +2116,7 @@ public final class ShortcutInfo implements Parcelable { CharSequence disabledMessage, int disabledMessageResId, String disabledMessageResName, Set<String> categories, Intent[] intentsWithExtras, int rank, PersistableBundle extras, long lastChangedTimestamp, int flags, int iconResId, String iconResName, String bitmapPath) { int flags, int iconResId, String iconResName, String bitmapPath, int disabledReason) { mUserId = userId; mId = id; mPackageName = packageName; Loading @@ -1978,5 +2141,6 @@ public final class ShortcutInfo implements Parcelable { mIconResId = iconResId; mIconResName = iconResName; mBitmapPath = bitmapPath; mDisabledReason = disabledReason; } }
services/core/java/com/android/server/pm/ShortcutLauncher.java +37 −16 Original line number Diff line number Diff line Loading @@ -83,11 +83,16 @@ class ShortcutLauncher extends ShortcutPackageItem { return mOwnerUserId; } @Override protected boolean canRestoreAnyVersion() { // Launcher's pinned shortcuts can be restored to an older version. return true; } /** * Called when the new package can't receive the backup, due to signature or version mismatch. */ @Override protected void onRestoreBlocked() { private void onRestoreBlocked() { final ArrayList<PackageWithUser> pinnedPackages = new ArrayList<>(mPinnedShortcuts.keySet()); mPinnedShortcuts.clear(); Loading @@ -101,15 +106,21 @@ class ShortcutLauncher extends ShortcutPackageItem { } @Override protected void onRestored() { // Nothing to do. protected void onRestored(int restoreBlockReason) { // For launcher, possible reasons here are DISABLED_REASON_SIGNATURE_MISMATCH or // DISABLED_REASON_BACKUP_NOT_SUPPORTED. // DISABLED_REASON_VERSION_LOWER will NOT happen because we don't check version // code for launchers. if (restoreBlockReason != ShortcutInfo.DISABLED_REASON_NOT_DISABLED) { onRestoreBlocked(); } } /** * Pin the given shortcuts, replacing the current pinned ones. */ public void pinShortcuts(@UserIdInt int packageUserId, @NonNull String packageName, @NonNull List<String> ids) { @NonNull String packageName, @NonNull List<String> ids, boolean forPinRequest) { final ShortcutPackage packageShortcuts = mShortcutUser.getPackageShortcutsIfExists(packageName); if (packageShortcuts == null) { Loading @@ -124,8 +135,12 @@ class ShortcutLauncher extends ShortcutPackageItem { } else { final ArraySet<String> prevSet = mPinnedShortcuts.get(pu); // Pin shortcuts. Make sure only pin the ones that were visible to the caller. // i.e. a non-dynamic, pinned shortcut by *other launchers* shouldn't be pinned here. // Actually pin shortcuts. // This logic here is to make sure a launcher cannot pin a shortcut that is floating // (i.e. not dynamic nor manifest but is pinned) and pinned by another launcher. // In this case, technically the shortcut doesn't exist to this launcher, so it can't // pin it. // (Maybe unnecessarily strict...) final ArraySet<String> newSet = new ArraySet<>(); Loading @@ -135,8 +150,10 @@ class ShortcutLauncher extends ShortcutPackageItem { if (si == null) { continue; } if (si.isDynamic() || si.isManifestShortcut() || (prevSet != null && prevSet.contains(id))) { if (si.isDynamic() || si.isManifestShortcut() || (prevSet != null && prevSet.contains(id)) || forPinRequest) { newSet.add(id); } } Loading @@ -155,7 +172,7 @@ class ShortcutLauncher extends ShortcutPackageItem { } /** * Return true if the given shortcut is pinned by this launcher. * Return true if the given shortcut is pinned by this launcher.<code></code> */ public boolean hasPinned(ShortcutInfo shortcut) { final ArraySet<String> pinned = Loading @@ -164,10 +181,10 @@ class ShortcutLauncher extends ShortcutPackageItem { } /** * Additionally pin a shortcut. c.f. {@link #pinShortcuts(int, String, List)} * Additionally pin a shortcut. c.f. {@link #pinShortcuts(int, String, List, boolean)} */ public void addPinnedShortcut(@NonNull String packageName, @UserIdInt int packageUserId, String id) { String id, boolean forPinRequest) { final ArraySet<String> pinnedSet = getPinnedShortcutIds(packageName, packageUserId); final ArrayList<String> pinnedList; if (pinnedSet != null) { Loading @@ -178,21 +195,21 @@ class ShortcutLauncher extends ShortcutPackageItem { } pinnedList.add(id); pinShortcuts(packageUserId, packageName, pinnedList); pinShortcuts(packageUserId, packageName, pinnedList, forPinRequest); } boolean cleanUpPackage(String packageName, @UserIdInt int packageUserId) { return mPinnedShortcuts.remove(PackageWithUser.of(packageUserId, packageName)) != null; } public void ensureVersionInfo() { public void ensurePackageInfo() { final PackageInfo pi = mShortcutUser.mService.getPackageInfoWithSignatures( getPackageName(), getPackageUserId()); if (pi == null) { Slog.w(TAG, "Package not found: " + getPackageName()); return; } getPackageInfo().updateVersionInfo(pi); getPackageInfo().updateFromPackageInfo(pi); } /** Loading @@ -201,6 +218,10 @@ class ShortcutLauncher extends ShortcutPackageItem { @Override public void saveToXml(XmlSerializer out, boolean forBackup) throws IOException { if (forBackup && !getPackageInfo().isBackupAllowed()) { // If an launcher app doesn't support backup&restore, then nothing to do. return; } final int size = mPinnedShortcuts.size(); if (size == 0) { return; // Nothing to write. Loading @@ -209,7 +230,7 @@ class ShortcutLauncher extends ShortcutPackageItem { out.startTag(null, TAG_ROOT); ShortcutService.writeAttr(out, ATTR_PACKAGE_NAME, getPackageName()); ShortcutService.writeAttr(out, ATTR_LAUNCHER_USER_ID, getPackageUserId()); getPackageInfo().saveToXml(out); getPackageInfo().saveToXml(out, forBackup); for (int i = 0; i < size; i++) { final PackageWithUser pu = mPinnedShortcuts.keyAt(i); Loading