Make notification getParcelable usages safer

Test: SystemUITests, CtsAppTestCases
Fixes: 198825327
Change-Id: I7a4868a56bc2c9a69d2fb1eae5d53faa3c9dede0
This commit is contained in:
Julia Reynolds
2022-04-14 13:31:40 -04:00
parent 2f056bb150
commit d6090a038a
12 changed files with 422 additions and 56 deletions

View File

@@ -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);
}
}

View File

@@ -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);

View File

@@ -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) {

View File

@@ -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

View File

@@ -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()));
}
}

View File

@@ -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);
}
}

View File

@@ -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 {

View File

@@ -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()

View File

@@ -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
}
}

View File

@@ -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),

View File

@@ -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);
}
}

View File

@@ -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();