Loading core/java/android/app/NotificationChannel.java +16 −7 Original line number Diff line number Diff line Loading @@ -124,8 +124,13 @@ public final class NotificationChannel implements Parcelable { /** * The maximum length for text fields in a NotificationChannel. Fields will be truncated at this * limit. * @hide */ private static final int MAX_TEXT_LENGTH = 1000; public static final int MAX_TEXT_LENGTH = 1000; /** * @hide */ public static final int MAX_VIBRATION_LENGTH = 1000; private static final String TAG_CHANNEL = "channel"; private static final String ATT_NAME = "name"; Loading Loading @@ -284,17 +289,17 @@ public final class NotificationChannel implements Parcelable { */ protected NotificationChannel(Parcel in) { if (in.readByte() != 0) { mId = in.readString(); mId = getTrimmedString(in.readString()); } else { mId = null; } if (in.readByte() != 0) { mName = in.readString(); mName = getTrimmedString(in.readString()); } else { mName = null; } if (in.readByte() != 0) { mDesc = in.readString(); mDesc = getTrimmedString(in.readString()); } else { mDesc = null; } Loading @@ -303,18 +308,22 @@ public final class NotificationChannel implements Parcelable { mLockscreenVisibility = in.readInt(); if (in.readByte() != 0) { mSound = Uri.CREATOR.createFromParcel(in); mSound = Uri.parse(getTrimmedString(mSound.toString())); } else { mSound = null; } mLights = in.readByte() != 0; mVibration = in.createLongArray(); if (mVibration != null && mVibration.length > MAX_VIBRATION_LENGTH) { mVibration = Arrays.copyOf(mVibration, MAX_VIBRATION_LENGTH); } mUserLockedFields = in.readInt(); mFgServiceShown = in.readByte() != 0; mVibrationEnabled = in.readByte() != 0; mShowBadge = in.readByte() != 0; mDeleted = in.readByte() != 0; if (in.readByte() != 0) { mGroup = in.readString(); mGroup = getTrimmedString(in.readString()); } else { mGroup = null; } Loading @@ -324,8 +333,8 @@ public final class NotificationChannel implements Parcelable { mAllowBubbles = in.readInt(); mImportanceLockedByOEM = in.readBoolean(); mOriginalImportance = in.readInt(); mParentId = in.readString(); mConversationId = in.readString(); mParentId = getTrimmedString(in.readString()); mConversationId = getTrimmedString(in.readString()); mDemoted = in.readBoolean(); mImportantConvo = in.readBoolean(); mDeletedTime = in.readLong(); Loading core/java/android/app/NotificationChannelGroup.java +15 −5 Original line number Diff line number Diff line Loading @@ -43,8 +43,9 @@ public final class NotificationChannelGroup implements Parcelable { /** * The maximum length for text fields in a NotificationChannelGroup. Fields will be truncated at * this limit. * @hide */ private static final int MAX_TEXT_LENGTH = 1000; public static final int MAX_TEXT_LENGTH = 1000; private static final String TAG_GROUP = "channelGroup"; private static final String ATT_NAME = "name"; Loading Loading @@ -90,13 +91,17 @@ public final class NotificationChannelGroup implements Parcelable { */ protected NotificationChannelGroup(Parcel in) { if (in.readByte() != 0) { mId = in.readString(); mId = getTrimmedString(in.readString()); } else { mId = null; } mName = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in); if (in.readByte() != 0) { mDescription = in.readString(); mName = getTrimmedString(in.readString()); } else { mName = ""; } if (in.readByte() != 0) { mDescription = getTrimmedString(in.readString()); } else { mDescription = null; } Loading @@ -120,7 +125,12 @@ public final class NotificationChannelGroup implements Parcelable { } else { dest.writeByte((byte) 0); } TextUtils.writeToParcel(mName, dest, flags); if (mName != null) { dest.writeByte((byte) 1); dest.writeString(mName.toString()); } else { dest.writeByte((byte) 0); } if (mDescription != null) { dest.writeByte((byte) 1); dest.writeString(mDescription); Loading core/java/android/appwidget/AppWidgetManager.java +3 −1 Original line number Diff line number Diff line Loading @@ -1130,7 +1130,9 @@ public class AppWidgetManager { * @param intent The intent of the service which will be providing the data to the * RemoteViewsAdapter. * @param connection The callback interface to be notified when a connection is made or lost. * @param flags Flags used for binding to the service * @param flags Flags used for binding to the service. Currently only * {@link Context#BIND_AUTO_CREATE} and * {@link Context#BIND_FOREGROUND_SERVICE_WHILE_AWAKE} are supported. * * @see Context#getServiceDispatcher(ServiceConnection, Handler, int) * @hide Loading core/java/android/service/notification/Condition.java +34 −4 Original line number Diff line number Diff line Loading @@ -90,6 +90,12 @@ public final class Condition implements Parcelable { public final int flags; public final int icon; /** * The maximum string length for any string contained in this condition. * @hide */ public static final int MAX_STRING_LENGTH = 1000; /** * An object representing the current state of a {@link android.app.AutomaticZenRule}. * @param id the {@link android.app.AutomaticZenRule#getConditionId()} of the zen rule Loading @@ -104,16 +110,19 @@ public final class Condition implements Parcelable { if (id == null) throw new IllegalArgumentException("id is required"); if (summary == null) throw new IllegalArgumentException("summary is required"); if (!isValidState(state)) throw new IllegalArgumentException("state is invalid: " + state); this.id = id; this.summary = summary; this.line1 = line1; this.line2 = line2; this.id = getTrimmedUri(id); this.summary = getTrimmedString(summary); this.line1 = getTrimmedString(line1); this.line2 = getTrimmedString(line2); this.icon = icon; this.state = state; this.flags = flags; } public Condition(Parcel source) { // This constructor passes all fields directly into the constructor that takes all the // fields as arguments; that constructor will trim each of the input strings to // max length if necessary. this((Uri)source.readParcelable(Condition.class.getClassLoader()), source.readString(), source.readString(), Loading Loading @@ -240,4 +249,25 @@ public final class Condition implements Parcelable { return new Condition[size]; } }; /** * Returns a truncated copy of the string if the string is longer than MAX_STRING_LENGTH. */ private static String getTrimmedString(String input) { if (input != null && input.length() > MAX_STRING_LENGTH) { return input.substring(0, MAX_STRING_LENGTH); } return input; } /** * Returns a truncated copy of the Uri by trimming the string representation to the maximum * string length. */ private static Uri getTrimmedUri(Uri input) { if (input != null && input.toString().length() > MAX_STRING_LENGTH) { return Uri.parse(getTrimmedString(input.toString())); } return input; } } core/tests/coretests/src/android/app/NotificationChannelGroupTest.java 0 → 100644 +89 −0 Original line number Diff line number Diff line /* * Copyright (C) 2022 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.app; import static junit.framework.TestCase.assertEquals; import static junit.framework.TestCase.assertTrue; import android.os.Parcel; import android.test.AndroidTestCase; import android.text.TextUtils; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; import com.google.common.base.Strings; import org.junit.Test; import org.junit.runner.RunWith; import java.lang.reflect.Field; @RunWith(AndroidJUnit4.class) @SmallTest public class NotificationChannelGroupTest { private final String CLASS = "android.app.NotificationChannelGroup"; @Test public void testLongStringFields() { NotificationChannelGroup group = new NotificationChannelGroup("my_group_01", "groupName"); try { String longString = Strings.repeat("A", 65536); Field mName = Class.forName(CLASS).getDeclaredField("mName"); mName.setAccessible(true); mName.set(group, longString); Field mId = Class.forName(CLASS).getDeclaredField("mId"); mId.setAccessible(true); mId.set(group, longString); Field mDescription = Class.forName(CLASS).getDeclaredField("mDescription"); mDescription.setAccessible(true); mDescription.set(group, longString); } catch (NoSuchFieldException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } Parcel parcel = Parcel.obtain(); group.writeToParcel(parcel, 0); parcel.setDataPosition(0); NotificationChannelGroup fromParcel = NotificationChannelGroup.CREATOR.createFromParcel(parcel); assertEquals(NotificationChannelGroup.MAX_TEXT_LENGTH, fromParcel.getId().length()); assertEquals(NotificationChannelGroup.MAX_TEXT_LENGTH, fromParcel.getName().length()); assertEquals(NotificationChannelGroup.MAX_TEXT_LENGTH, fromParcel.getDescription().length()); } @Test public void testNullableFields() { NotificationChannelGroup group = new NotificationChannelGroup("my_group_01", null); Parcel parcel = Parcel.obtain(); group.writeToParcel(parcel, 0); parcel.setDataPosition(0); NotificationChannelGroup fromParcel = NotificationChannelGroup.CREATOR.createFromParcel(parcel); assertEquals(group.getId(), fromParcel.getId()); assertTrue(TextUtils.isEmpty(fromParcel.getName())); } } Loading
core/java/android/app/NotificationChannel.java +16 −7 Original line number Diff line number Diff line Loading @@ -124,8 +124,13 @@ public final class NotificationChannel implements Parcelable { /** * The maximum length for text fields in a NotificationChannel. Fields will be truncated at this * limit. * @hide */ private static final int MAX_TEXT_LENGTH = 1000; public static final int MAX_TEXT_LENGTH = 1000; /** * @hide */ public static final int MAX_VIBRATION_LENGTH = 1000; private static final String TAG_CHANNEL = "channel"; private static final String ATT_NAME = "name"; Loading Loading @@ -284,17 +289,17 @@ public final class NotificationChannel implements Parcelable { */ protected NotificationChannel(Parcel in) { if (in.readByte() != 0) { mId = in.readString(); mId = getTrimmedString(in.readString()); } else { mId = null; } if (in.readByte() != 0) { mName = in.readString(); mName = getTrimmedString(in.readString()); } else { mName = null; } if (in.readByte() != 0) { mDesc = in.readString(); mDesc = getTrimmedString(in.readString()); } else { mDesc = null; } Loading @@ -303,18 +308,22 @@ public final class NotificationChannel implements Parcelable { mLockscreenVisibility = in.readInt(); if (in.readByte() != 0) { mSound = Uri.CREATOR.createFromParcel(in); mSound = Uri.parse(getTrimmedString(mSound.toString())); } else { mSound = null; } mLights = in.readByte() != 0; mVibration = in.createLongArray(); if (mVibration != null && mVibration.length > MAX_VIBRATION_LENGTH) { mVibration = Arrays.copyOf(mVibration, MAX_VIBRATION_LENGTH); } mUserLockedFields = in.readInt(); mFgServiceShown = in.readByte() != 0; mVibrationEnabled = in.readByte() != 0; mShowBadge = in.readByte() != 0; mDeleted = in.readByte() != 0; if (in.readByte() != 0) { mGroup = in.readString(); mGroup = getTrimmedString(in.readString()); } else { mGroup = null; } Loading @@ -324,8 +333,8 @@ public final class NotificationChannel implements Parcelable { mAllowBubbles = in.readInt(); mImportanceLockedByOEM = in.readBoolean(); mOriginalImportance = in.readInt(); mParentId = in.readString(); mConversationId = in.readString(); mParentId = getTrimmedString(in.readString()); mConversationId = getTrimmedString(in.readString()); mDemoted = in.readBoolean(); mImportantConvo = in.readBoolean(); mDeletedTime = in.readLong(); Loading
core/java/android/app/NotificationChannelGroup.java +15 −5 Original line number Diff line number Diff line Loading @@ -43,8 +43,9 @@ public final class NotificationChannelGroup implements Parcelable { /** * The maximum length for text fields in a NotificationChannelGroup. Fields will be truncated at * this limit. * @hide */ private static final int MAX_TEXT_LENGTH = 1000; public static final int MAX_TEXT_LENGTH = 1000; private static final String TAG_GROUP = "channelGroup"; private static final String ATT_NAME = "name"; Loading Loading @@ -90,13 +91,17 @@ public final class NotificationChannelGroup implements Parcelable { */ protected NotificationChannelGroup(Parcel in) { if (in.readByte() != 0) { mId = in.readString(); mId = getTrimmedString(in.readString()); } else { mId = null; } mName = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in); if (in.readByte() != 0) { mDescription = in.readString(); mName = getTrimmedString(in.readString()); } else { mName = ""; } if (in.readByte() != 0) { mDescription = getTrimmedString(in.readString()); } else { mDescription = null; } Loading @@ -120,7 +125,12 @@ public final class NotificationChannelGroup implements Parcelable { } else { dest.writeByte((byte) 0); } TextUtils.writeToParcel(mName, dest, flags); if (mName != null) { dest.writeByte((byte) 1); dest.writeString(mName.toString()); } else { dest.writeByte((byte) 0); } if (mDescription != null) { dest.writeByte((byte) 1); dest.writeString(mDescription); Loading
core/java/android/appwidget/AppWidgetManager.java +3 −1 Original line number Diff line number Diff line Loading @@ -1130,7 +1130,9 @@ public class AppWidgetManager { * @param intent The intent of the service which will be providing the data to the * RemoteViewsAdapter. * @param connection The callback interface to be notified when a connection is made or lost. * @param flags Flags used for binding to the service * @param flags Flags used for binding to the service. Currently only * {@link Context#BIND_AUTO_CREATE} and * {@link Context#BIND_FOREGROUND_SERVICE_WHILE_AWAKE} are supported. * * @see Context#getServiceDispatcher(ServiceConnection, Handler, int) * @hide Loading
core/java/android/service/notification/Condition.java +34 −4 Original line number Diff line number Diff line Loading @@ -90,6 +90,12 @@ public final class Condition implements Parcelable { public final int flags; public final int icon; /** * The maximum string length for any string contained in this condition. * @hide */ public static final int MAX_STRING_LENGTH = 1000; /** * An object representing the current state of a {@link android.app.AutomaticZenRule}. * @param id the {@link android.app.AutomaticZenRule#getConditionId()} of the zen rule Loading @@ -104,16 +110,19 @@ public final class Condition implements Parcelable { if (id == null) throw new IllegalArgumentException("id is required"); if (summary == null) throw new IllegalArgumentException("summary is required"); if (!isValidState(state)) throw new IllegalArgumentException("state is invalid: " + state); this.id = id; this.summary = summary; this.line1 = line1; this.line2 = line2; this.id = getTrimmedUri(id); this.summary = getTrimmedString(summary); this.line1 = getTrimmedString(line1); this.line2 = getTrimmedString(line2); this.icon = icon; this.state = state; this.flags = flags; } public Condition(Parcel source) { // This constructor passes all fields directly into the constructor that takes all the // fields as arguments; that constructor will trim each of the input strings to // max length if necessary. this((Uri)source.readParcelable(Condition.class.getClassLoader()), source.readString(), source.readString(), Loading Loading @@ -240,4 +249,25 @@ public final class Condition implements Parcelable { return new Condition[size]; } }; /** * Returns a truncated copy of the string if the string is longer than MAX_STRING_LENGTH. */ private static String getTrimmedString(String input) { if (input != null && input.length() > MAX_STRING_LENGTH) { return input.substring(0, MAX_STRING_LENGTH); } return input; } /** * Returns a truncated copy of the Uri by trimming the string representation to the maximum * string length. */ private static Uri getTrimmedUri(Uri input) { if (input != null && input.toString().length() > MAX_STRING_LENGTH) { return Uri.parse(getTrimmedString(input.toString())); } return input; } }
core/tests/coretests/src/android/app/NotificationChannelGroupTest.java 0 → 100644 +89 −0 Original line number Diff line number Diff line /* * Copyright (C) 2022 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.app; import static junit.framework.TestCase.assertEquals; import static junit.framework.TestCase.assertTrue; import android.os.Parcel; import android.test.AndroidTestCase; import android.text.TextUtils; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; import com.google.common.base.Strings; import org.junit.Test; import org.junit.runner.RunWith; import java.lang.reflect.Field; @RunWith(AndroidJUnit4.class) @SmallTest public class NotificationChannelGroupTest { private final String CLASS = "android.app.NotificationChannelGroup"; @Test public void testLongStringFields() { NotificationChannelGroup group = new NotificationChannelGroup("my_group_01", "groupName"); try { String longString = Strings.repeat("A", 65536); Field mName = Class.forName(CLASS).getDeclaredField("mName"); mName.setAccessible(true); mName.set(group, longString); Field mId = Class.forName(CLASS).getDeclaredField("mId"); mId.setAccessible(true); mId.set(group, longString); Field mDescription = Class.forName(CLASS).getDeclaredField("mDescription"); mDescription.setAccessible(true); mDescription.set(group, longString); } catch (NoSuchFieldException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } Parcel parcel = Parcel.obtain(); group.writeToParcel(parcel, 0); parcel.setDataPosition(0); NotificationChannelGroup fromParcel = NotificationChannelGroup.CREATOR.createFromParcel(parcel); assertEquals(NotificationChannelGroup.MAX_TEXT_LENGTH, fromParcel.getId().length()); assertEquals(NotificationChannelGroup.MAX_TEXT_LENGTH, fromParcel.getName().length()); assertEquals(NotificationChannelGroup.MAX_TEXT_LENGTH, fromParcel.getDescription().length()); } @Test public void testNullableFields() { NotificationChannelGroup group = new NotificationChannelGroup("my_group_01", null); Parcel parcel = Parcel.obtain(); group.writeToParcel(parcel, 0); parcel.setDataPosition(0); NotificationChannelGroup fromParcel = NotificationChannelGroup.CREATOR.createFromParcel(parcel); assertEquals(group.getId(), fromParcel.getId()); assertTrue(TextUtils.isEmpty(fromParcel.getName())); } }