From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A1s=20Kurucz?= Date: Fri, 21 Apr 2023 09:45:07 +0000 Subject: [PATCH] Truncate ShortcutInfo Id Creating Conversation with a ShortcutId longer than 65_535 (max unsigned short), we did not save the conversation settings into the notification_policy.xml due to a restriction in FastDataOutput. This put us to a state where the user changing the importance or turning off the notifications for the given conversation had no effect on notification behavior. Fixes: 273729476 Test: atest ShortcutManagerTest2 Test: Create a test app which creates a Conversation with a long shortcutId. Go to the Conversation Settings and turn off Notifications. Post a new Notification to this Conversation and see if it is displayed. (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:f31df6234091b5b1de258a01dd4b2d8e5415ee2e) Merged-In: I2617de6f9e8a7dbfd8fbeff589a7d592f00d87c5 Change-Id: I2617de6f9e8a7dbfd8fbeff589a7d592f00d87c5 --- .../java/android/content/pm/ShortcutInfo.java | 20 ++++++++++++++++--- .../server/pm/ShortcutManagerTest2.java | 10 ++++++++++ 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/core/java/android/content/pm/ShortcutInfo.java b/core/java/android/content/pm/ShortcutInfo.java index ea476b0abf33..cddad1798219 100644 --- a/core/java/android/content/pm/ShortcutInfo.java +++ b/core/java/android/content/pm/ShortcutInfo.java @@ -214,6 +214,12 @@ public final class ShortcutInfo implements Parcelable { */ public static final int DISABLED_REASON_OTHER_RESTORE_ISSUE = 103; + /** + * The maximum length of Shortcut ID. IDs will be truncated at this limit. + * @hide + */ + public static final int MAX_ID_LENGTH = 1000; + /** @hide */ @IntDef(prefix = { "DISABLED_REASON_" }, value = { DISABLED_REASON_NOT_DISABLED, @@ -380,8 +386,7 @@ public final class ShortcutInfo implements Parcelable { private ShortcutInfo(Builder b) { mUserId = b.mContext.getUserId(); - - mId = Preconditions.checkStringNotEmpty(b.mId, "Shortcut ID must be provided"); + mId = getSafeId(Preconditions.checkStringNotEmpty(b.mId, "Shortcut ID must be provided")); // Note we can't do other null checks here because SM.updateShortcuts() takes partial // information. @@ -463,6 +468,14 @@ public final class ShortcutInfo implements Parcelable { return ret; } + @NonNull + private static String getSafeId(@NonNull String id) { + if (id.length() > MAX_ID_LENGTH) { + return id.substring(0, MAX_ID_LENGTH); + } + return id; + } + /** * Throws if any of the mandatory fields is not set. * @@ -1851,7 +1864,8 @@ public final class ShortcutInfo implements Parcelable { final ClassLoader cl = getClass().getClassLoader(); mUserId = source.readInt(); - mId = source.readString(); + mId = getSafeId(Preconditions.checkStringNotEmpty(source.readString(), + "Shortcut ID must be provided")); mPackageName = source.readString(); mActivity = source.readParcelable(cl); mFlags = source.readInt(); diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java index fcdadaccd2ac..464f563640c1 100644 --- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java +++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java @@ -53,6 +53,7 @@ import java.io.IOException; import java.io.PrintWriter; import java.io.StringWriter; import java.io.Writer; +import java.util.Collections; import java.util.Locale; /** @@ -223,6 +224,15 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest { }); } + public void testShortcutIdTruncated() { + ShortcutInfo si = new ShortcutInfo.Builder(getTestContext(), + String.join("", Collections.nCopies(Short.MAX_VALUE, "s"))).build(); + + assertTrue( + "id must be truncated to MAX_ID_LENGTH", + si.getId().length() <= ShortcutInfo.MAX_ID_LENGTH); + } + public void testShortcutInfoParcel() { setCaller(CALLING_PACKAGE_1, USER_10); ShortcutInfo si = parceled(new ShortcutInfo.Builder(mClientContext)