From 303a97a99b75bae716c109b810e6bccb732483df Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Andr=C3=A1s=20Kurucz?= <kurucz@google.com>
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 a854b899a82af..3ac20ff39327b 100644
--- a/core/java/android/content/pm/ShortcutInfo.java
+++ b/core/java/android/content/pm/ShortcutInfo.java
@@ -128,6 +128,12 @@ public final class ShortcutInfo implements Parcelable {
     public static final int CLONE_REMOVE_FOR_LAUNCHER = CLONE_REMOVE_ICON | CLONE_REMOVE_INTENT
             | CLONE_REMOVE_RES_NAMES;
 
+    /**
+     * The maximum length of Shortcut ID. IDs will be truncated at this limit.
+     * @hide
+     */
+    public static final int MAX_ID_LENGTH = 1000;
+
     /** @hide */
     @IntDef(flag = true,
             value = {
@@ -226,8 +232,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.
@@ -309,6 +314,14 @@ private static PersistableBundle[] clonePersistableBundle(PersistableBundle[] bu
         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.
      *
@@ -1602,7 +1615,8 @@ private ShortcutInfo(Parcel source) {
         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 d25923c019cac..6b86ef0e0704c 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.PrintWriter;
 import java.io.StringWriter;
 import java.io.Writer;
+import java.util.Collections;
 import java.util.Locale;
 
 /**
@@ -223,6 +224,15 @@ public void testShortcutInfoMissingMandatoryFields() {
                 });
     }
 
+    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)
