Make notification getParcelable usages safer
Test: SystemUITests, CtsAppTestCases Fixes: 198825327 Change-Id: I7a4868a56bc2c9a69d2fb1eae5d53faa3c9dede0
This commit is contained in:
@@ -2813,8 +2813,8 @@ public class Notification implements Parcelable
|
||||
}
|
||||
|
||||
if (extras != null) {
|
||||
visitIconUri(visitor, extras.getParcelable(EXTRA_LARGE_ICON_BIG));
|
||||
visitIconUri(visitor, extras.getParcelable(EXTRA_PICTURE_ICON));
|
||||
visitIconUri(visitor, extras.getParcelable(EXTRA_LARGE_ICON_BIG, Icon.class));
|
||||
visitIconUri(visitor, extras.getParcelable(EXTRA_PICTURE_ICON, Icon.class));
|
||||
|
||||
// NOTE: The documentation of EXTRA_AUDIO_CONTENTS_URI explicitly says that it is a
|
||||
// String representation of a Uri, but the previous implementation (and unit test) of
|
||||
@@ -2838,7 +2838,7 @@ public class Notification implements Parcelable
|
||||
}
|
||||
}
|
||||
|
||||
final Person person = extras.getParcelable(EXTRA_MESSAGING_PERSON);
|
||||
final Person person = extras.getParcelable(EXTRA_MESSAGING_PERSON, Person.class);
|
||||
if (person != null) {
|
||||
visitor.accept(person.getIconUri());
|
||||
}
|
||||
@@ -6473,7 +6473,7 @@ public class Notification implements Parcelable
|
||||
public static Notification.Builder recoverBuilder(Context context, Notification n) {
|
||||
// Re-create notification context so we can access app resources.
|
||||
ApplicationInfo applicationInfo = n.extras.getParcelable(
|
||||
EXTRA_BUILDER_APPLICATION_INFO);
|
||||
EXTRA_BUILDER_APPLICATION_INFO, ApplicationInfo.class);
|
||||
Context builderContext;
|
||||
if (applicationInfo != null) {
|
||||
try {
|
||||
@@ -6925,9 +6925,8 @@ public class Notification implements Parcelable
|
||||
boolean isMediaStyle = (MediaStyle.class.equals(style)
|
||||
|| DecoratedMediaCustomViewStyle.class.equals(style));
|
||||
|
||||
boolean hasMediaSession = (extras.getParcelable(Notification.EXTRA_MEDIA_SESSION) != null
|
||||
&& extras.getParcelable(Notification.EXTRA_MEDIA_SESSION)
|
||||
instanceof MediaSession.Token);
|
||||
boolean hasMediaSession = extras.getParcelable(Notification.EXTRA_MEDIA_SESSION,
|
||||
MediaSession.Token.class) != null;
|
||||
|
||||
return isMediaStyle && hasMediaSession;
|
||||
}
|
||||
@@ -7522,7 +7521,7 @@ public class Notification implements Parcelable
|
||||
|
||||
if (extras.containsKey(EXTRA_LARGE_ICON_BIG)) {
|
||||
mBigLargeIconSet = true;
|
||||
mBigLargeIcon = extras.getParcelable(EXTRA_LARGE_ICON_BIG);
|
||||
mBigLargeIcon = extras.getParcelable(EXTRA_LARGE_ICON_BIG, Icon.class);
|
||||
}
|
||||
|
||||
if (extras.containsKey(EXTRA_PICTURE_CONTENT_DESCRIPTION)) {
|
||||
@@ -7542,11 +7541,11 @@ public class Notification implements Parcelable
|
||||
// When this style adds a picture, we only add one of the keys. If both were added,
|
||||
// it would most likely be a legacy app trying to override the picture in some way.
|
||||
// Because of that case it's better to give precedence to the legacy field.
|
||||
Bitmap bitmapPicture = extras.getParcelable(EXTRA_PICTURE);
|
||||
Bitmap bitmapPicture = extras.getParcelable(EXTRA_PICTURE, Bitmap.class);
|
||||
if (bitmapPicture != null) {
|
||||
return Icon.createWithBitmap(bitmapPicture);
|
||||
} else {
|
||||
return extras.getParcelable(EXTRA_PICTURE_ICON);
|
||||
return extras.getParcelable(EXTRA_PICTURE_ICON, Icon.class);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8165,7 +8164,7 @@ public class Notification implements Parcelable
|
||||
protected void restoreFromExtras(Bundle extras) {
|
||||
super.restoreFromExtras(extras);
|
||||
|
||||
mUser = extras.getParcelable(EXTRA_MESSAGING_PERSON);
|
||||
mUser = extras.getParcelable(EXTRA_MESSAGING_PERSON, Person.class);
|
||||
if (mUser == null) {
|
||||
CharSequence displayName = extras.getCharSequence(EXTRA_SELF_DISPLAY_NAME);
|
||||
mUser = new Person.Builder().setName(displayName).build();
|
||||
@@ -8177,7 +8176,7 @@ public class Notification implements Parcelable
|
||||
mHistoricMessages = Message.getMessagesFromBundleArray(histMessages);
|
||||
mIsGroupConversation = extras.getBoolean(EXTRA_IS_GROUP_CONVERSATION);
|
||||
mUnreadMessageCount = extras.getInt(EXTRA_CONVERSATION_UNREAD_MESSAGE_COUNT);
|
||||
mShortcutIcon = extras.getParcelable(EXTRA_CONVERSATION_ICON);
|
||||
mShortcutIcon = extras.getParcelable(EXTRA_CONVERSATION_ICON, Icon.class);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -8731,7 +8730,7 @@ public class Notification implements Parcelable
|
||||
return null;
|
||||
} else {
|
||||
|
||||
Person senderPerson = bundle.getParcelable(KEY_SENDER_PERSON);
|
||||
Person senderPerson = bundle.getParcelable(KEY_SENDER_PERSON, Person.class);
|
||||
if (senderPerson == null) {
|
||||
// Legacy apps that use compat don't actually provide the sender objects
|
||||
// We need to fix the compat version to provide people / use
|
||||
@@ -8748,7 +8747,7 @@ public class Notification implements Parcelable
|
||||
if (bundle.containsKey(KEY_DATA_MIME_TYPE) &&
|
||||
bundle.containsKey(KEY_DATA_URI)) {
|
||||
message.setData(bundle.getString(KEY_DATA_MIME_TYPE),
|
||||
(Uri) bundle.getParcelable(KEY_DATA_URI));
|
||||
bundle.getParcelable(KEY_DATA_URI, Uri.class));
|
||||
}
|
||||
if (bundle.containsKey(KEY_EXTRAS_BUNDLE)) {
|
||||
message.getExtras().putAll(bundle.getBundle(KEY_EXTRAS_BUNDLE));
|
||||
@@ -9154,7 +9153,7 @@ public class Notification implements Parcelable
|
||||
super.restoreFromExtras(extras);
|
||||
|
||||
if (extras.containsKey(EXTRA_MEDIA_SESSION)) {
|
||||
mToken = extras.getParcelable(EXTRA_MEDIA_SESSION);
|
||||
mToken = extras.getParcelable(EXTRA_MEDIA_SESSION, MediaSession.Token.class);
|
||||
}
|
||||
if (extras.containsKey(EXTRA_COMPACT_ACTIONS)) {
|
||||
mActionsToShowInCompact = extras.getIntArray(EXTRA_COMPACT_ACTIONS);
|
||||
@@ -9166,7 +9165,8 @@ public class Notification implements Parcelable
|
||||
mDeviceIcon = extras.getInt(EXTRA_MEDIA_REMOTE_ICON);
|
||||
}
|
||||
if (extras.containsKey(EXTRA_MEDIA_REMOTE_INTENT)) {
|
||||
mDeviceIntent = extras.getParcelable(EXTRA_MEDIA_REMOTE_INTENT);
|
||||
mDeviceIntent = extras.getParcelable(
|
||||
EXTRA_MEDIA_REMOTE_INTENT, PendingIntent.class);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9758,12 +9758,12 @@ public class Notification implements Parcelable
|
||||
super.restoreFromExtras(extras);
|
||||
mCallType = extras.getInt(EXTRA_CALL_TYPE);
|
||||
mIsVideo = extras.getBoolean(EXTRA_CALL_IS_VIDEO);
|
||||
mPerson = extras.getParcelable(EXTRA_CALL_PERSON);
|
||||
mPerson = extras.getParcelable(EXTRA_CALL_PERSON, Person.class);
|
||||
mVerificationIcon = extras.getParcelable(EXTRA_VERIFICATION_ICON);
|
||||
mVerificationText = extras.getCharSequence(EXTRA_VERIFICATION_TEXT);
|
||||
mAnswerIntent = extras.getParcelable(EXTRA_ANSWER_INTENT);
|
||||
mDeclineIntent = extras.getParcelable(EXTRA_DECLINE_INTENT);
|
||||
mHangUpIntent = extras.getParcelable(EXTRA_HANG_UP_INTENT);
|
||||
mAnswerIntent = extras.getParcelable(EXTRA_ANSWER_INTENT, PendingIntent.class);
|
||||
mDeclineIntent = extras.getParcelable(EXTRA_DECLINE_INTENT, PendingIntent.class);
|
||||
mHangUpIntent = extras.getParcelable(EXTRA_HANG_UP_INTENT, PendingIntent.class);
|
||||
mAnswerButtonColor = extras.containsKey(EXTRA_ANSWER_COLOR)
|
||||
? extras.getInt(EXTRA_ANSWER_COLOR) : null;
|
||||
mDeclineButtonColor = extras.containsKey(EXTRA_DECLINE_COLOR)
|
||||
@@ -10824,9 +10824,9 @@ public class Notification implements Parcelable
|
||||
// Keys within EXTRA_WEARABLE_EXTENSIONS for wearable options.
|
||||
private static final String KEY_ACTIONS = "actions";
|
||||
private static final String KEY_FLAGS = "flags";
|
||||
private static final String KEY_DISPLAY_INTENT = "displayIntent";
|
||||
static final String KEY_DISPLAY_INTENT = "displayIntent";
|
||||
private static final String KEY_PAGES = "pages";
|
||||
private static final String KEY_BACKGROUND = "background";
|
||||
static final String KEY_BACKGROUND = "background";
|
||||
private static final String KEY_CONTENT_ICON = "contentIcon";
|
||||
private static final String KEY_CONTENT_ICON_GRAVITY = "contentIconGravity";
|
||||
private static final String KEY_CONTENT_ACTION_INDEX = "contentActionIndex";
|
||||
@@ -10883,7 +10883,8 @@ public class Notification implements Parcelable
|
||||
}
|
||||
|
||||
mFlags = wearableBundle.getInt(KEY_FLAGS, DEFAULT_FLAGS);
|
||||
mDisplayIntent = wearableBundle.getParcelable(KEY_DISPLAY_INTENT);
|
||||
mDisplayIntent = wearableBundle.getParcelable(
|
||||
KEY_DISPLAY_INTENT, PendingIntent.class);
|
||||
|
||||
Notification[] pages = getParcelableArrayFromBundle(
|
||||
wearableBundle, KEY_PAGES, Notification.class);
|
||||
@@ -10891,7 +10892,7 @@ public class Notification implements Parcelable
|
||||
Collections.addAll(mPages, pages);
|
||||
}
|
||||
|
||||
mBackground = wearableBundle.getParcelable(KEY_BACKGROUND);
|
||||
mBackground = wearableBundle.getParcelable(KEY_BACKGROUND, Bitmap.class);
|
||||
mContentIcon = wearableBundle.getInt(KEY_CONTENT_ICON);
|
||||
mContentIconGravity = wearableBundle.getInt(KEY_CONTENT_ICON_GRAVITY,
|
||||
DEFAULT_CONTENT_ICON_GRAVITY);
|
||||
@@ -11604,7 +11605,7 @@ public class Notification implements Parcelable
|
||||
Bundle carBundle = notif.extras == null ?
|
||||
null : notif.extras.getBundle(EXTRA_CAR_EXTENDER);
|
||||
if (carBundle != null) {
|
||||
mLargeIcon = carBundle.getParcelable(EXTRA_LARGE_ICON);
|
||||
mLargeIcon = carBundle.getParcelable(EXTRA_LARGE_ICON, Bitmap.class);
|
||||
mColor = carBundle.getInt(EXTRA_COLOR, Notification.COLOR_DEFAULT);
|
||||
|
||||
Bundle b = carBundle.getBundle(EXTRA_CONVERSATION);
|
||||
@@ -11710,9 +11711,9 @@ public class Notification implements Parcelable
|
||||
private static final String KEY_AUTHOR = "author";
|
||||
private static final String KEY_TEXT = "text";
|
||||
private static final String KEY_MESSAGES = "messages";
|
||||
private static final String KEY_REMOTE_INPUT = "remote_input";
|
||||
private static final String KEY_ON_REPLY = "on_reply";
|
||||
private static final String KEY_ON_READ = "on_read";
|
||||
static final String KEY_REMOTE_INPUT = "remote_input";
|
||||
static final String KEY_ON_REPLY = "on_reply";
|
||||
static final String KEY_ON_READ = "on_read";
|
||||
private static final String KEY_PARTICIPANTS = "participants";
|
||||
private static final String KEY_TIMESTAMP = "timestamp";
|
||||
|
||||
@@ -11837,10 +11838,10 @@ public class Notification implements Parcelable
|
||||
}
|
||||
}
|
||||
|
||||
PendingIntent onRead = b.getParcelable(KEY_ON_READ);
|
||||
PendingIntent onReply = b.getParcelable(KEY_ON_REPLY);
|
||||
PendingIntent onRead = b.getParcelable(KEY_ON_READ, PendingIntent.class);
|
||||
PendingIntent onReply = b.getParcelable(KEY_ON_REPLY, PendingIntent.class);
|
||||
|
||||
RemoteInput remoteInput = b.getParcelable(KEY_REMOTE_INPUT);
|
||||
RemoteInput remoteInput = b.getParcelable(KEY_REMOTE_INPUT, RemoteInput.class);
|
||||
|
||||
String[] participants = b.getStringArray(KEY_PARTICIPANTS);
|
||||
if (participants == null || participants.length != 1) {
|
||||
@@ -11982,8 +11983,8 @@ public class Notification implements Parcelable
|
||||
|
||||
private static final String EXTRA_TV_EXTENDER = "android.tv.EXTENSIONS";
|
||||
private static final String EXTRA_FLAGS = "flags";
|
||||
private static final String EXTRA_CONTENT_INTENT = "content_intent";
|
||||
private static final String EXTRA_DELETE_INTENT = "delete_intent";
|
||||
static final String EXTRA_CONTENT_INTENT = "content_intent";
|
||||
static final String EXTRA_DELETE_INTENT = "delete_intent";
|
||||
private static final String EXTRA_CHANNEL_ID = "channel_id";
|
||||
private static final String EXTRA_SUPPRESS_SHOW_OVER_APPS = "suppressShowOverApps";
|
||||
|
||||
@@ -12015,8 +12016,8 @@ public class Notification implements Parcelable
|
||||
mFlags = bundle.getInt(EXTRA_FLAGS);
|
||||
mChannelId = bundle.getString(EXTRA_CHANNEL_ID);
|
||||
mSuppressShowOverApps = bundle.getBoolean(EXTRA_SUPPRESS_SHOW_OVER_APPS);
|
||||
mContentIntent = bundle.getParcelable(EXTRA_CONTENT_INTENT);
|
||||
mDeleteIntent = bundle.getParcelable(EXTRA_DELETE_INTENT);
|
||||
mContentIntent = bundle.getParcelable(EXTRA_CONTENT_INTENT, PendingIntent.class);
|
||||
mDeleteIntent = bundle.getParcelable(EXTRA_DELETE_INTENT, PendingIntent.class);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -17,6 +17,30 @@
|
||||
package android.app;
|
||||
|
||||
import static android.app.Notification.Builder.ensureColorSpanContrast;
|
||||
import static android.app.Notification.CarExtender.UnreadConversation.KEY_ON_READ;
|
||||
import static android.app.Notification.CarExtender.UnreadConversation.KEY_ON_REPLY;
|
||||
import static android.app.Notification.CarExtender.UnreadConversation.KEY_REMOTE_INPUT;
|
||||
import static android.app.Notification.EXTRA_ANSWER_INTENT;
|
||||
import static android.app.Notification.EXTRA_BUILDER_APPLICATION_INFO;
|
||||
import static android.app.Notification.EXTRA_CALL_PERSON;
|
||||
import static android.app.Notification.EXTRA_CONVERSATION_ICON;
|
||||
import static android.app.Notification.EXTRA_DECLINE_INTENT;
|
||||
import static android.app.Notification.EXTRA_HANG_UP_INTENT;
|
||||
import static android.app.Notification.EXTRA_LARGE_ICON;
|
||||
import static android.app.Notification.EXTRA_LARGE_ICON_BIG;
|
||||
import static android.app.Notification.EXTRA_MEDIA_REMOTE_INTENT;
|
||||
import static android.app.Notification.EXTRA_MEDIA_SESSION;
|
||||
import static android.app.Notification.EXTRA_MESSAGING_PERSON;
|
||||
import static android.app.Notification.EXTRA_PICTURE;
|
||||
import static android.app.Notification.EXTRA_PICTURE_ICON;
|
||||
import static android.app.Notification.MessagingStyle.Message.KEY_DATA_URI;
|
||||
import static android.app.Notification.MessagingStyle.Message.KEY_SENDER_PERSON;
|
||||
import static android.app.Notification.MessagingStyle.Message.KEY_TEXT;
|
||||
import static android.app.Notification.MessagingStyle.Message.KEY_TIMESTAMP;
|
||||
import static android.app.Notification.TvExtender.EXTRA_CONTENT_INTENT;
|
||||
import static android.app.Notification.TvExtender.EXTRA_DELETE_INTENT;
|
||||
import static android.app.Notification.WearableExtender.KEY_BACKGROUND;
|
||||
import static android.app.Notification.WearableExtender.KEY_DISPLAY_INTENT;
|
||||
|
||||
import static com.android.compatibility.common.util.SystemUtil.runShellCommand;
|
||||
import static com.android.internal.util.ContrastColorUtilTest.assertContrastIsAtLeast;
|
||||
@@ -32,6 +56,7 @@ import static org.junit.Assert.assertNotSame;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertSame;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.Mockito.spy;
|
||||
|
||||
import android.annotation.Nullable;
|
||||
import android.content.Context;
|
||||
@@ -43,6 +68,7 @@ import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.drawable.Icon;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Parcel;
|
||||
@@ -170,7 +196,7 @@ public class NotificationTest {
|
||||
assertNotSame(q.getLargeIcon(), n.getLargeIcon());
|
||||
|
||||
assertTrue(q.getLargeIcon().getBitmap().sameAs(n.getLargeIcon().getBitmap()));
|
||||
assertSame(q.getLargeIcon(), q.extras.getParcelable(Notification.EXTRA_LARGE_ICON));
|
||||
assertSame(q.getLargeIcon(), q.extras.getParcelable(EXTRA_LARGE_ICON));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -179,12 +205,12 @@ public class NotificationTest {
|
||||
mContext.getResources(), com.android.frameworks.coretests.R.drawable.test128x96));
|
||||
|
||||
Notification n = new Notification.Builder(mContext).build();
|
||||
n.extras.putParcelable(Notification.EXTRA_LARGE_ICON, originalIcon);
|
||||
n.extras.putParcelable(EXTRA_LARGE_ICON, originalIcon);
|
||||
assertSame(n.getLargeIcon(), null);
|
||||
|
||||
Notification q = writeAndReadParcelable(n);
|
||||
assertSame(q.getLargeIcon(), null);
|
||||
assertTrue(((Icon) q.extras.getParcelable(Notification.EXTRA_LARGE_ICON)).getBitmap()
|
||||
assertTrue(((Icon) q.extras.getParcelable(EXTRA_LARGE_ICON)).getBitmap()
|
||||
.sameAs(originalIcon.getBitmap()));
|
||||
}
|
||||
|
||||
@@ -641,7 +667,7 @@ public class NotificationTest {
|
||||
public void testIsMediaNotification_invalidSession_returnsFalse() {
|
||||
// Extra was set manually to an invalid type
|
||||
Bundle extras = new Bundle();
|
||||
extras.putParcelable(Notification.EXTRA_MEDIA_SESSION, new Intent());
|
||||
extras.putParcelable(EXTRA_MEDIA_SESSION, new Intent());
|
||||
Notification.MediaStyle mediaStyle = new Notification.MediaStyle();
|
||||
Notification notification = new Notification.Builder(mContext, "test id")
|
||||
.setStyle(mediaStyle)
|
||||
@@ -650,6 +676,7 @@ public class NotificationTest {
|
||||
assertFalse(notification.isMediaNotification());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void validateColorizedPaletteForColor(int rawColor) {
|
||||
Notification.Colors cDay = new Notification.Colors();
|
||||
Notification.Colors cNight = new Notification.Colors();
|
||||
@@ -681,6 +708,174 @@ public class NotificationTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testVisitUris_invalidExtra_noCrash() {
|
||||
Notification n = new Notification.Builder(mContext, "test")
|
||||
.setSmallIcon(0)
|
||||
.build();
|
||||
Bundle fakeTypes = new Bundle();
|
||||
fakeTypes.putParcelable(EXTRA_LARGE_ICON_BIG, new Bundle());
|
||||
fakeTypes.putParcelable(EXTRA_PICTURE_ICON, new Bundle());
|
||||
fakeTypes.putParcelable(EXTRA_MESSAGING_PERSON, new Bundle());
|
||||
|
||||
Consumer<Uri> visitor = (Consumer<Uri>) spy(Consumer.class);
|
||||
n.visitUris(visitor);
|
||||
|
||||
// no crash, good
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRecoverBuilder_invalidExtra_noCrash() {
|
||||
Notification n = new Notification.Builder(mContext, "test")
|
||||
.setSmallIcon(0)
|
||||
.build();
|
||||
Bundle fakeTypes = new Bundle();
|
||||
fakeTypes.putParcelable(EXTRA_BUILDER_APPLICATION_INFO, new Bundle());
|
||||
|
||||
Notification.Builder.recoverBuilder(mContext, n);
|
||||
|
||||
// no crash, good
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsMediaNotification_invalidExtra_noCrash() {
|
||||
Notification n = new Notification.Builder(mContext, "test")
|
||||
.setSmallIcon(0)
|
||||
.setStyle(new Notification.MediaStyle())
|
||||
.build();
|
||||
Bundle fakeTypes = new Bundle();
|
||||
fakeTypes.putParcelable(EXTRA_MEDIA_SESSION, new Bundle());
|
||||
|
||||
n.isMediaNotification();
|
||||
|
||||
// no crash, good
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRestoreFromExtras_BigText_invalidExtra_noCrash() {
|
||||
Notification.Style style = new Notification.BigTextStyle();
|
||||
Bundle fakeTypes = new Bundle();
|
||||
fakeTypes.putParcelable(EXTRA_LARGE_ICON_BIG, new Bundle());
|
||||
|
||||
style.restoreFromExtras(fakeTypes);
|
||||
|
||||
// no crash, good
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRestoreFromExtras_Messaging_invalidExtra_noCrash() {
|
||||
Notification.Style style = new Notification.MessagingStyle();
|
||||
Bundle fakeTypes = new Bundle();
|
||||
fakeTypes.putParcelable(EXTRA_MESSAGING_PERSON, new Bundle());
|
||||
fakeTypes.putParcelable(EXTRA_CONVERSATION_ICON, new Bundle());
|
||||
|
||||
style.restoreFromExtras(fakeTypes);
|
||||
|
||||
// no crash, good
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRestoreFromExtras_Media_invalidExtra_noCrash() {
|
||||
Notification.Style style = new Notification.MediaStyle();
|
||||
Bundle fakeTypes = new Bundle();
|
||||
fakeTypes.putParcelable(EXTRA_MEDIA_SESSION, new Bundle());
|
||||
fakeTypes.putParcelable(EXTRA_MEDIA_REMOTE_INTENT, new Bundle());
|
||||
|
||||
style.restoreFromExtras(fakeTypes);
|
||||
|
||||
// no crash, good
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRestoreFromExtras_Call_invalidExtra_noCrash() {
|
||||
Notification.Style style = new Notification.CallStyle();
|
||||
Bundle fakeTypes = new Bundle();
|
||||
fakeTypes.putParcelable(EXTRA_CALL_PERSON, new Bundle());
|
||||
fakeTypes.putParcelable(EXTRA_ANSWER_INTENT, new Bundle());
|
||||
fakeTypes.putParcelable(EXTRA_DECLINE_INTENT, new Bundle());
|
||||
fakeTypes.putParcelable(EXTRA_HANG_UP_INTENT, new Bundle());
|
||||
|
||||
style.restoreFromExtras(fakeTypes);
|
||||
|
||||
// no crash, good
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetPictureIcon_invalidExtra_noCrash() {
|
||||
Bundle fakeTypes = new Bundle();
|
||||
fakeTypes.putParcelable(EXTRA_PICTURE, new Bundle());
|
||||
fakeTypes.putParcelable(EXTRA_PICTURE_ICON, new Bundle());
|
||||
|
||||
Notification.BigPictureStyle.getPictureIcon(fakeTypes);
|
||||
|
||||
// no crash, good
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWearableExtender_invalidExtra_noCrash() {
|
||||
Notification n = new Notification.Builder(mContext, "test")
|
||||
.setSmallIcon(0)
|
||||
.setStyle(new Notification.MediaStyle())
|
||||
.build();
|
||||
Bundle fakeTypes = new Bundle();
|
||||
fakeTypes.putParcelable(KEY_DISPLAY_INTENT, new Bundle());
|
||||
fakeTypes.putParcelable(KEY_BACKGROUND, new Bundle());
|
||||
Notification.WearableExtender extender = new Notification.WearableExtender(n);
|
||||
|
||||
// no crash, good
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCarExtender_invalidExtra_noCrash() {
|
||||
Notification n = new Notification.Builder(mContext, "test")
|
||||
.setSmallIcon(0)
|
||||
.setStyle(new Notification.MediaStyle())
|
||||
.build();
|
||||
Bundle fakeTypes = new Bundle();
|
||||
fakeTypes.putParcelable(EXTRA_LARGE_ICON, new Bundle());
|
||||
Notification.CarExtender extender = new Notification.CarExtender(n);
|
||||
|
||||
// no crash, good
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTvExtender_invalidExtra_noCrash() {
|
||||
Notification n = new Notification.Builder(mContext, "test")
|
||||
.setSmallIcon(0)
|
||||
.setStyle(new Notification.MediaStyle())
|
||||
.build();
|
||||
Bundle fakeTypes = new Bundle();
|
||||
fakeTypes.putParcelable(EXTRA_CONTENT_INTENT, new Bundle());
|
||||
fakeTypes.putParcelable(EXTRA_DELETE_INTENT, new Bundle());
|
||||
Notification.TvExtender extender = new Notification.TvExtender(n);
|
||||
|
||||
// no crash, good
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetUnreadConversationFromBundle_invalidExtra_noCrash() {
|
||||
Bundle fakeTypes = new Bundle();
|
||||
fakeTypes.putParcelable(KEY_ON_READ, new Bundle());
|
||||
fakeTypes.putParcelable(KEY_ON_REPLY, new Bundle());
|
||||
fakeTypes.putParcelable(KEY_REMOTE_INPUT, new Bundle());
|
||||
Notification.CarExtender.UnreadConversation.getUnreadConversationFromBundle(fakeTypes);
|
||||
|
||||
// no crash, good
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetMessageFromBundle_invalidExtra_noCrash() {
|
||||
Bundle fakeTypes = new Bundle();
|
||||
fakeTypes.putParcelable(KEY_SENDER_PERSON, new Bundle());
|
||||
fakeTypes.putString(KEY_TEXT, "text");
|
||||
fakeTypes.putLong(KEY_TIMESTAMP, 0);
|
||||
fakeTypes.putParcelable(KEY_REMOTE_INPUT, new Bundle());
|
||||
fakeTypes.putParcelable(KEY_DATA_URI, new Bundle());
|
||||
Notification.MessagingStyle.Message.getMessageFromBundle(fakeTypes);
|
||||
|
||||
// no crash, good
|
||||
}
|
||||
|
||||
private void assertValid(Notification.Colors c) {
|
||||
// Assert that all colors are populated
|
||||
assertThat(c.getBackgroundColor()).isNotEqualTo(Notification.COLOR_INVALID);
|
||||
|
||||
@@ -601,14 +601,17 @@ class MediaDataManager(
|
||||
}
|
||||
}
|
||||
|
||||
private fun loadMediaDataInBg(
|
||||
fun loadMediaDataInBg(
|
||||
key: String,
|
||||
sbn: StatusBarNotification,
|
||||
oldKey: String?,
|
||||
logEvent: Boolean = false
|
||||
) {
|
||||
val token = sbn.notification.extras.getParcelable(Notification.EXTRA_MEDIA_SESSION)
|
||||
as MediaSession.Token?
|
||||
val token = sbn.notification.extras.getParcelable(
|
||||
Notification.EXTRA_MEDIA_SESSION, MediaSession.Token::class.java)
|
||||
if (token == null) {
|
||||
return
|
||||
}
|
||||
val mediaController = mediaControllerFactory.create(token)
|
||||
val metadata = mediaController.metadata
|
||||
|
||||
@@ -655,8 +658,8 @@ class MediaDataManager(
|
||||
val extras = sbn.notification.extras
|
||||
val deviceName = extras.getCharSequence(Notification.EXTRA_MEDIA_REMOTE_DEVICE, null)
|
||||
val deviceIcon = extras.getInt(Notification.EXTRA_MEDIA_REMOTE_ICON, -1)
|
||||
val deviceIntent = extras.getParcelable(Notification.EXTRA_MEDIA_REMOTE_INTENT)
|
||||
as PendingIntent?
|
||||
val deviceIntent = extras.getParcelable(
|
||||
Notification.EXTRA_MEDIA_REMOTE_INTENT, PendingIntent::class.java)
|
||||
Log.d(TAG, "$key is RCN for $deviceName")
|
||||
|
||||
if (deviceName != null && deviceIcon > -1) {
|
||||
|
||||
@@ -454,7 +454,7 @@ public class NotificationMediaManager implements Dumpable {
|
||||
* update this manager's internal state.
|
||||
* @return whether the current MediaMetadata changed (and needs to be announced to listeners).
|
||||
*/
|
||||
private boolean findPlayingMediaNotification(
|
||||
boolean findPlayingMediaNotification(
|
||||
@NonNull Collection<NotificationEntry> allNotifications) {
|
||||
boolean metaDataChanged = false;
|
||||
// Promote the media notification with a controller in 'playing' state, if any.
|
||||
@@ -465,7 +465,7 @@ public class NotificationMediaManager implements Dumpable {
|
||||
if (notif.isMediaNotification()) {
|
||||
final MediaSession.Token token =
|
||||
entry.getSbn().getNotification().extras.getParcelable(
|
||||
Notification.EXTRA_MEDIA_SESSION);
|
||||
Notification.EXTRA_MEDIA_SESSION, MediaSession.Token.class);
|
||||
if (token != null) {
|
||||
MediaController aController = new MediaController(mContext, token);
|
||||
if (PlaybackState.STATE_PLAYING
|
||||
|
||||
@@ -573,11 +573,10 @@ public class StatusBarIconView extends AnimatedImageView implements StatusIconDi
|
||||
} catch (RuntimeException e) {
|
||||
Log.e(TAG, "Unable to recover builder", e);
|
||||
// Trying to get the app name from the app info instead.
|
||||
Parcelable appInfo = n.extras.getParcelable(
|
||||
Notification.EXTRA_BUILDER_APPLICATION_INFO);
|
||||
if (appInfo instanceof ApplicationInfo) {
|
||||
appName = String.valueOf(((ApplicationInfo) appInfo).loadLabel(
|
||||
c.getPackageManager()));
|
||||
ApplicationInfo appInfo = n.extras.getParcelable(
|
||||
Notification.EXTRA_BUILDER_APPLICATION_INFO, ApplicationInfo.class);
|
||||
if (appInfo != null) {
|
||||
appName = String.valueOf(appInfo.loadLabel(c.getPackageManager()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -542,7 +542,8 @@ public final class NotificationEntry extends ListEntry {
|
||||
if (senderPerson == null) {
|
||||
return true;
|
||||
}
|
||||
Person user = extras.getParcelable(Notification.EXTRA_MESSAGING_PERSON);
|
||||
Person user = extras.getParcelable(
|
||||
Notification.EXTRA_MESSAGING_PERSON, Person.class);
|
||||
return Objects.equals(user, senderPerson);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,9 +44,8 @@ public class NotificationBigPictureTemplateViewWrapper extends NotificationTempl
|
||||
|
||||
private void updateImageTag(StatusBarNotification sbn) {
|
||||
final Bundle extras = sbn.getNotification().extras;
|
||||
boolean bigLargeIconSet = extras.containsKey(Notification.EXTRA_LARGE_ICON_BIG);
|
||||
if (bigLargeIconSet) {
|
||||
Icon bigLargeIcon = extras.getParcelable(Notification.EXTRA_LARGE_ICON_BIG);
|
||||
Icon bigLargeIcon = extras.getParcelable(Notification.EXTRA_LARGE_ICON_BIG, Icon.class);
|
||||
if (bigLargeIcon != null) {
|
||||
mRightIcon.setTag(ImageTransformState.ICON_TAG, bigLargeIcon);
|
||||
mLeftIcon.setTag(ImageTransformState.ICON_TAG, bigLargeIcon);
|
||||
} else {
|
||||
|
||||
@@ -276,6 +276,49 @@ class MediaDataManagerTest : SysuiTestCase() {
|
||||
eq(mediaDataCaptor.value.instanceId), eq(MediaData.PLAYBACK_CAST_REMOTE))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testLoadMediaDataInBg_invalidTokenNoCrash() {
|
||||
val bundle = Bundle()
|
||||
// wrong data type
|
||||
bundle.putParcelable(Notification.EXTRA_MEDIA_SESSION, Bundle())
|
||||
val rcn = SbnBuilder().run {
|
||||
setPkg(SYSTEM_PACKAGE_NAME)
|
||||
modifyNotification(context).also {
|
||||
it.setSmallIcon(android.R.drawable.ic_media_pause)
|
||||
it.addExtras(bundle)
|
||||
it.setStyle(MediaStyle().apply {
|
||||
setRemotePlaybackInfo("Remote device", 0, null)
|
||||
})
|
||||
}
|
||||
build()
|
||||
}
|
||||
|
||||
mediaDataManager.loadMediaDataInBg(KEY, rcn, null)
|
||||
// no crash even though the data structure is incorrect
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testLoadMediaDataInBg_invalidMediaRemoteIntentNoCrash() {
|
||||
val bundle = Bundle()
|
||||
// wrong data type
|
||||
bundle.putParcelable(Notification.EXTRA_MEDIA_REMOTE_INTENT, Bundle())
|
||||
val rcn = SbnBuilder().run {
|
||||
setPkg(SYSTEM_PACKAGE_NAME)
|
||||
modifyNotification(context).also {
|
||||
it.setSmallIcon(android.R.drawable.ic_media_pause)
|
||||
it.addExtras(bundle)
|
||||
it.setStyle(MediaStyle().apply {
|
||||
setMediaSession(session.sessionToken)
|
||||
setRemotePlaybackInfo("Remote device", 0, null)
|
||||
})
|
||||
}
|
||||
build()
|
||||
}
|
||||
|
||||
mediaDataManager.loadMediaDataInBg(KEY, rcn, null)
|
||||
// no crash even though the data structure is incorrect
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testOnNotificationRemoved_callsListener() {
|
||||
addNotificationAndLoad()
|
||||
|
||||
@@ -32,6 +32,7 @@ import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.app.Notification;
|
||||
import android.content.Context;
|
||||
import android.content.ContextWrapper;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
@@ -41,6 +42,7 @@ import android.graphics.Bitmap;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
import android.graphics.drawable.Icon;
|
||||
import android.os.Bundle;
|
||||
import android.os.UserHandle;
|
||||
import android.service.notification.StatusBarNotification;
|
||||
|
||||
@@ -170,4 +172,16 @@ public class StatusBarIconViewTest extends SysuiTestCase {
|
||||
mIconView.getIcon(largeIcon);
|
||||
// No crash? good
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testContentDescForNotification_invalidAi_noCrash() {
|
||||
Notification n = new Notification.Builder(mContext, "test")
|
||||
.setSmallIcon(0)
|
||||
.build();
|
||||
// should be ApplicationInfo
|
||||
n.extras.putParcelable(Notification.EXTRA_BUILDER_APPLICATION_INFO, new Bundle());
|
||||
StatusBarIconView.contentDescForNotification(mContext, n);
|
||||
|
||||
// no crash, good
|
||||
}
|
||||
}
|
||||
|
||||
@@ -229,6 +229,41 @@ public class NotificationEntryTest extends SysuiTestCase {
|
||||
assertTrue(entry.isLastMessageFromReply());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void notificationDataEntry_testIsLastMessageFromReply_invalidPerson_noCrash() {
|
||||
Person.Builder person = new Person.Builder()
|
||||
.setName("name")
|
||||
.setKey("abc")
|
||||
.setUri("uri")
|
||||
.setBot(true);
|
||||
|
||||
Bundle bundle = new Bundle();
|
||||
// should be Person.class
|
||||
bundle.putParcelable(Notification.EXTRA_MESSAGING_PERSON, new Bundle());
|
||||
Bundle[] messagesBundle = new Bundle[]{new Notification.MessagingStyle.Message(
|
||||
"text", 0, person.build()).toBundle()};
|
||||
bundle.putParcelableArray(Notification.EXTRA_MESSAGES, messagesBundle);
|
||||
|
||||
Notification notification = new Notification.Builder(mContext, "test")
|
||||
.addExtras(bundle)
|
||||
.build();
|
||||
|
||||
NotificationEntry entry = new NotificationEntryBuilder()
|
||||
.setPkg("pkg")
|
||||
.setOpPkg("pkg")
|
||||
.setTag("tag")
|
||||
.setNotification(notification)
|
||||
.setUser(mContext.getUser())
|
||||
.setOverrideGroupKey("")
|
||||
.build();
|
||||
entry.setHasSentReply();
|
||||
|
||||
entry.isLastMessageFromReply();
|
||||
|
||||
// no crash, good
|
||||
}
|
||||
|
||||
|
||||
private Notification.Action createContextualAction(String title) {
|
||||
return new Notification.Action.Builder(
|
||||
Icon.createWithResource(getContext(), android.R.drawable.sym_def_app_icon),
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* 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 com.android.systemui.statusbar.notification.row.wrapper;
|
||||
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.app.Notification;
|
||||
import android.content.Context;
|
||||
import android.graphics.drawable.Icon;
|
||||
import android.os.Bundle;
|
||||
import android.testing.AndroidTestingRunner;
|
||||
import android.testing.TestableLooper;
|
||||
import android.testing.TestableLooper.RunWithLooper;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.test.filters.SmallTest;
|
||||
|
||||
import com.android.systemui.SysuiTestCase;
|
||||
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
|
||||
import com.android.systemui.statusbar.notification.row.NotificationTestHelper;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
@RunWith(AndroidTestingRunner.class)
|
||||
@SmallTest
|
||||
@RunWithLooper
|
||||
public class NotificationBigPictureTemplateViewWrapperTest extends SysuiTestCase {
|
||||
|
||||
private View mView;
|
||||
private ExpandableNotificationRow mRow;
|
||||
|
||||
|
||||
@Before
|
||||
public void setup() throws Exception {
|
||||
allowTestableLooperAsMainThread();
|
||||
NotificationTestHelper helper = new NotificationTestHelper(
|
||||
mContext,
|
||||
mDependency,
|
||||
TestableLooper.get(this));
|
||||
mView = LayoutInflater.from(mContext).inflate(
|
||||
com.android.internal.R.layout.notification_template_material_big_picture, null);
|
||||
mRow = helper.createRow();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void invalidLargeIconBig_noCrash() {
|
||||
NotificationViewWrapper wrapper = new NotificationBigPictureTemplateViewWrapper(
|
||||
mContext, mView, mRow);
|
||||
// should be Icon.class
|
||||
mRow.getEntry().getSbn().getNotification().setSmallIcon(
|
||||
Icon.createWithResource(mContext, 0));
|
||||
mRow.getEntry().getSbn().getNotification().extras.putParcelable(
|
||||
Notification.EXTRA_LARGE_ICON_BIG, new Bundle());
|
||||
wrapper.onContentUpdated(mRow);
|
||||
}
|
||||
}
|
||||
@@ -5827,7 +5827,7 @@ public class NotificationManagerService extends SystemService {
|
||||
// Add summary
|
||||
final ApplicationInfo appInfo =
|
||||
adjustedSbn.getNotification().extras.getParcelable(
|
||||
Notification.EXTRA_BUILDER_APPLICATION_INFO);
|
||||
Notification.EXTRA_BUILDER_APPLICATION_INFO, ApplicationInfo.class);
|
||||
final Bundle extras = new Bundle();
|
||||
extras.putParcelable(Notification.EXTRA_BUILDER_APPLICATION_INFO, appInfo);
|
||||
final String channelId = notificationRecord.getChannel().getId();
|
||||
|
||||
Reference in New Issue
Block a user