diff options
author | 2022-02-11 00:22:07 +0000 | |
---|---|---|
committer | 2022-02-11 00:22:07 +0000 | |
commit | 4f2645ae1b04aea60aea65256b5b6f8585c8dbd4 (patch) | |
tree | 8e8a7a3ec70582bce11c0426d198fce3001598aa | |
parent | 34bf5558910eb629ce8085b9f5a4e4ea3c87de85 (diff) | |
parent | ded4a734d163ed022e84940c3786cf99a80b0f06 (diff) |
Merge "Add SystemAPI to override default media output switcher"
12 files changed, 244 insertions, 41 deletions
diff --git a/core/api/system-current.txt b/core/api/system-current.txt index 321ebcf42ea5..58ddaa6d2aec 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -851,6 +851,10 @@ package android.app { field public static final int SEMANTIC_ACTION_MARK_CONVERSATION_AS_PRIORITY = 11; // 0xb } + public static class Notification.MediaStyle extends android.app.Notification.Style { + method @NonNull @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public android.app.Notification.MediaStyle setRemotePlaybackInfo(@NonNull CharSequence, @DrawableRes int, @Nullable android.app.PendingIntent); + } + public static final class Notification.TvExtender implements android.app.Notification.Extender { ctor public Notification.TvExtender(); ctor public Notification.TvExtender(android.app.Notification); diff --git a/core/api/test-current.txt b/core/api/test-current.txt index ff4ec311349c..dad7b48d15dd 100644 --- a/core/api/test-current.txt +++ b/core/api/test-current.txt @@ -300,6 +300,9 @@ package android.app { public class Notification implements android.os.Parcelable { method public boolean shouldShowForegroundImmediately(); + field public static final String EXTRA_MEDIA_REMOTE_DEVICE = "android.mediaRemoteDevice"; + field public static final String EXTRA_MEDIA_REMOTE_ICON = "android.mediaRemoteIcon"; + field public static final String EXTRA_MEDIA_REMOTE_INTENT = "android.mediaRemoteIntent"; } public final class NotificationChannel implements android.os.Parcelable { diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java index b8380160ed88..9dd206e21c44 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -1330,6 +1330,32 @@ public class Notification implements Parcelable public static final String EXTRA_MEDIA_SESSION = "android.mediaSession"; /** + * {@link #extras} key: A {@code CharSequence} name of a remote device used for a media session + * associated with a {@link Notification.MediaStyle} notification. This will show in the media + * controls output switcher instead of the local device name. + * @hide + */ + @TestApi + public static final String EXTRA_MEDIA_REMOTE_DEVICE = "android.mediaRemoteDevice"; + + /** + * {@link #extras} key: A {@code int} resource ID for an icon that should show in the output + * switcher of the media controls for a {@link Notification.MediaStyle} notification. + * @hide + */ + @TestApi + public static final String EXTRA_MEDIA_REMOTE_ICON = "android.mediaRemoteIcon"; + + /** + * {@link #extras} key: A {@code PendingIntent} that will replace the default action for the + * media controls output switcher chip, associated with a {@link Notification.MediaStyle} + * notification. This should launch an activity. + * @hide + */ + @TestApi + public static final String EXTRA_MEDIA_REMOTE_INTENT = "android.mediaRemoteIntent"; + + /** * {@link #extras} key: the indices of actions to be shown in the compact view, * as supplied to (e.g.) {@link MediaStyle#setShowActionsInCompactView(int...)}. */ @@ -8943,6 +8969,9 @@ public class Notification implements Parcelable private int[] mActionsToShowInCompact = null; private MediaSession.Token mToken; + private CharSequence mDeviceName; + private int mDeviceIcon; + private PendingIntent mDeviceIntent; public MediaStyle() { } @@ -8976,6 +9005,32 @@ public class Notification implements Parcelable } /** + * For media notifications associated with playback on a remote device, provide device + * information that will replace the default values for the output switcher chip on the + * media control, as well as an intent to use when the output switcher chip is tapped, + * on devices where this is supported. + * + * @param deviceName The name of the remote device to display + * @param iconResource Icon resource representing the device + * @param chipIntent PendingIntent to send when the output switcher is tapped. May be + * {@code null}, in which case the output switcher will be disabled. + * This intent should open an Activity or it will be ignored. + * @return MediaStyle + * + * @hide + */ + @SystemApi + @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) + @NonNull + public MediaStyle setRemotePlaybackInfo(@NonNull CharSequence deviceName, + @DrawableRes int iconResource, @Nullable PendingIntent chipIntent) { + mDeviceName = deviceName; + mDeviceIcon = iconResource; + mDeviceIntent = chipIntent; + return this; + } + + /** * @hide */ @Override @@ -9023,6 +9078,15 @@ public class Notification implements Parcelable if (mActionsToShowInCompact != null) { extras.putIntArray(EXTRA_COMPACT_ACTIONS, mActionsToShowInCompact); } + if (mDeviceName != null) { + extras.putCharSequence(EXTRA_MEDIA_REMOTE_DEVICE, mDeviceName); + } + if (mDeviceIcon > 0) { + extras.putInt(EXTRA_MEDIA_REMOTE_ICON, mDeviceIcon); + } + if (mDeviceIntent != null) { + extras.putParcelable(EXTRA_MEDIA_REMOTE_INTENT, mDeviceIntent); + } } /** @@ -9038,6 +9102,15 @@ public class Notification implements Parcelable if (extras.containsKey(EXTRA_COMPACT_ACTIONS)) { mActionsToShowInCompact = extras.getIntArray(EXTRA_COMPACT_ACTIONS); } + if (extras.containsKey(EXTRA_MEDIA_REMOTE_DEVICE)) { + mDeviceName = extras.getCharSequence(EXTRA_MEDIA_REMOTE_DEVICE); + } + if (extras.containsKey(EXTRA_MEDIA_REMOTE_ICON)) { + mDeviceIcon = extras.getInt(EXTRA_MEDIA_REMOTE_ICON); + } + if (extras.containsKey(EXTRA_MEDIA_REMOTE_INTENT)) { + mDeviceIntent = extras.getParcelable(EXTRA_MEDIA_REMOTE_INTENT); + } } /** diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java index b3e66829a72b..ce7a6977df92 100644 --- a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java +++ b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java @@ -371,13 +371,6 @@ public class MediaControlPanel { // Output switcher chip ViewGroup seamlessView = mMediaViewHolder.getSeamless(); seamlessView.setVisibility(View.VISIBLE); - seamlessView.setOnClickListener( - v -> { - if (!mFalsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) { - mMediaOutputDialogFactory.create(data.getPackageName(), true, - mMediaViewHolder.getSeamlessButton()); - } - }); ImageView iconView = mMediaViewHolder.getSeamlessIcon(); TextView deviceName = mMediaViewHolder.getSeamlessText(); final MediaDeviceData device = data.getDevice(); @@ -387,8 +380,8 @@ public class MediaControlPanel { final float seamlessAlpha = seamlessDisabled ? DISABLED_ALPHA : 1.0f; mMediaViewHolder.getSeamlessButton().setAlpha(seamlessAlpha); seamlessView.setEnabled(!seamlessDisabled); - String deviceString = null; - if (device != null && device.getEnabled()) { + CharSequence deviceString = mContext.getString(R.string.media_seamless_other_device); + if (device != null) { Drawable icon = device.getIcon(); if (icon instanceof AdaptiveIcon) { AdaptiveIcon aIcon = (AdaptiveIcon) icon; @@ -399,13 +392,32 @@ public class MediaControlPanel { } deviceString = device.getName(); } else { - // Reset to default - Log.w(TAG, "Device is null or not enabled: " + device + ", not binding output chip."); + // Set to default icon iconView.setImageResource(R.drawable.ic_media_home_devices); - deviceString = mContext.getString(R.string.media_seamless_other_device); } deviceName.setText(deviceString); seamlessView.setContentDescription(deviceString); + seamlessView.setOnClickListener( + v -> { + if (mFalsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) { + return; + } + if (device.getIntent() != null) { + if (device.getIntent().isActivity()) { + mActivityStarter.startActivity( + device.getIntent().getIntent(), true); + } else { + try { + device.getIntent().send(); + } catch (PendingIntent.CanceledException e) { + Log.e(TAG, "Device pending intent was canceled"); + } + } + } else { + mMediaOutputDialogFactory.create(data.getPackageName(), true, + mMediaViewHolder.getSeamlessButton()); + } + }); // Dismiss mMediaViewHolder.getDismissText().setAlpha(isDismissible ? 1 : DISABLED_ALPHA); diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaData.kt b/packages/SystemUI/src/com/android/systemui/media/MediaData.kt index 4b8dfdee040e..500e82efdb0a 100644 --- a/packages/SystemUI/src/com/android/systemui/media/MediaData.kt +++ b/packages/SystemUI/src/com/android/systemui/media/MediaData.kt @@ -164,8 +164,17 @@ data class MediaAction( ) /** State of the media device. */ -data class MediaDeviceData( +data class MediaDeviceData +@JvmOverloads constructor( + /** Whether or not to enable the chip */ val enabled: Boolean, + + /** Device icon to show in the chip */ val icon: Drawable?, - val name: String? + + /** Device display name */ + val name: CharSequence?, + + /** Optional intent to override the default output switcher for this control */ + val intent: PendingIntent? = null ) diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt index 240ca3678765..e1ff110f8d73 100644 --- a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt +++ b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt @@ -27,8 +27,6 @@ import android.content.ContentResolver import android.content.Context import android.content.Intent import android.content.IntentFilter -import android.content.pm.ApplicationInfo -import android.content.pm.PackageManager import android.graphics.Bitmap import android.graphics.ImageDecoder import android.graphics.drawable.Icon @@ -129,7 +127,7 @@ class MediaDataManager( private val useQsMediaPlayer: Boolean, private val systemClock: SystemClock, private val tunerService: TunerService, - private val mediaFlags: MediaFlags, + private val mediaFlags: MediaFlags ) : Dumpable, BcSmartspaceDataPlugin.SmartspaceTargetListener { companion object { @@ -170,20 +168,9 @@ class MediaDataManager( /** * Check whether this notification is an RCN - * TODO(b/204910409) implement new API for explicitly declaring this */ private fun isRemoteCastNotification(sbn: StatusBarNotification): Boolean { - val pm = context.packageManager - try { - val info = pm.getApplicationInfo(sbn.packageName, PackageManager.MATCH_SYSTEM_ONLY) - if (info.privateFlags and ApplicationInfo.PRIVATE_FLAG_PRIVILEGED != 0) { - val extras = sbn.notification.extras - if (extras.containsKey(Notification.EXTRA_SUBSTITUTE_APP_NAME)) { - return true - } - } - } catch (e: PackageManager.NameNotFoundException) { } - return false + return sbn.notification.extras.containsKey(Notification.EXTRA_MEDIA_REMOTE_DEVICE) } @Inject @@ -597,6 +584,25 @@ class MediaDataManager( artist = HybridGroupManager.resolveText(notif) } + // Device name (used for remote cast notifications) + var device: MediaDeviceData? = null + if (isRemoteCastNotification(sbn)) { + 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? + Log.d(TAG, "$key is RCN for $deviceName") + + if (deviceName != null && deviceIcon > -1) { + // Name and icon must be present, but intent may be null + val enabled = deviceIntent != null && deviceIntent.isActivity + val deviceDrawable = Icon.createWithResource(sbn.packageName, deviceIcon) + .loadDrawable(sbn.getPackageContext(context)) + device = MediaDeviceData(enabled, deviceDrawable, deviceName, deviceIntent) + } + } + // Control buttons // If flag is enabled and controller has a PlaybackState, create actions from session info // Otherwise, use the notification actions @@ -624,7 +630,7 @@ class MediaDataManager( val active = mediaEntries[key]?.active ?: true onMediaDataLoaded(key, oldKey, MediaData(sbn.normalizedUserId, true, bgColor, app, smallIcon, artist, song, artWorkIcon, actionIcons, actionsToShowCollapsed, - semanticActions, sbn.packageName, token, notif.contentIntent, null, + semanticActions, sbn.packageName, token, notif.contentIntent, device, active, resumeAction = resumeAction, playbackLocation = playbackLocation, notificationKey = key, hasCheckedForResume = hasCheckedForResume, isPlaying = isPlaying, isClearable = sbn.isClearable(), diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaDeviceManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaDeviceManager.kt index f972da560ed8..ffae898d07fa 100644 --- a/packages/SystemUI/src/com/android/systemui/media/MediaDeviceManager.kt +++ b/packages/SystemUI/src/com/android/systemui/media/MediaDeviceManager.kt @@ -81,6 +81,12 @@ class MediaDeviceManager @Inject constructor( var entry = entries[key] if (entry == null || entry?.token != data.token) { entry?.stop() + if (data.device != null) { + // If we were already provided device info (e.g. from RCN), keep that and don't + // listen for updates, but process once to push updates to listeners + processDevice(key, oldKey, data.device) + return + } val controller = data.token?.let { controllerFactory.create(it) } diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt index 609291a983ce..708fc915410c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt @@ -74,6 +74,7 @@ private const val SESSION_KEY = "SESSION_KEY" private const val SESSION_ARTIST = "SESSION_ARTIST" private const val SESSION_TITLE = "SESSION_TITLE" private const val USER_ID = 0 +private const val DISABLED_DEVICE_NAME = "DISABLED_DEVICE_NAME" @SmallTest @RunWith(AndroidTestingRunner::class) @@ -131,7 +132,7 @@ public class MediaControlPanelTest : SysuiTestCase() { private lateinit var session: MediaSession private val device = MediaDeviceData(true, null, DEVICE_NAME) - private val disabledDevice = MediaDeviceData(false, null, "Disabled Device") + private val disabledDevice = MediaDeviceData(false, null, DISABLED_DEVICE_NAME) private lateinit var mediaData: MediaData private val clock = FakeSystemClock() @@ -396,13 +397,12 @@ public class MediaControlPanelTest : SysuiTestCase() { @Test fun bindDisabledDevice() { seamless.id = 1 - val fallbackString = context.getString(R.string.media_seamless_other_device) player.attachPlayer(holder, MediaViewController.TYPE.PLAYER) val state = mediaData.copy(device = disabledDevice) player.bindPlayer(state, PACKAGE) assertThat(seamless.isEnabled()).isFalse() - assertThat(seamlessText.getText()).isEqualTo(fallbackString) - assertThat(seamless.contentDescription).isEqualTo(fallbackString) + assertThat(seamlessText.getText()).isEqualTo(DISABLED_DEVICE_NAME) + assertThat(seamless.contentDescription).isEqualTo(DISABLED_DEVICE_NAME) } @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt index 649ee872c99e..f4fa921703aa 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt @@ -1,6 +1,5 @@ package com.android.systemui.media -import android.app.Notification import android.app.Notification.MediaStyle import android.app.PendingIntent import android.app.smartspace.SmartspaceAction @@ -240,15 +239,14 @@ class MediaDataManagerTest : SysuiTestCase() { @Test fun testOnNotificationAdded_isRcn_markedRemote() { - val bundle = Bundle().apply { - putString(Notification.EXTRA_SUBSTITUTE_APP_NAME, "Remote Cast Notification") - } val rcn = SbnBuilder().run { setPkg("com.android.systemui") // System package modifyNotification(context).also { it.setSmallIcon(android.R.drawable.ic_media_pause) - it.setStyle(MediaStyle().apply { setMediaSession(session.sessionToken) }) - it.addExtras(bundle) + it.setStyle(MediaStyle().apply { + setMediaSession(session.sessionToken) + setRemotePlaybackInfo("Remote device", 0, null) + }) } build() } diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDeviceManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDeviceManagerTest.kt index 64b5b86f47f6..d912a8906ab3 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDeviceManagerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDeviceManagerTest.kt @@ -437,6 +437,24 @@ public class MediaDeviceManagerTest : SysuiTestCase() { verify(mr2, never()).getRoutingSessionForMediaController(eq(controller)) } + @Test + fun testRemotePlaybackDeviceOverride() { + whenever(route.name).thenReturn(DEVICE_NAME) + val deviceData = MediaDeviceData(false, null, REMOTE_DEVICE_NAME, null) + val mediaDataWithDevice = mediaData.copy(device = deviceData) + + // GIVEN media data that already has a device set + manager.onMediaDataLoaded(KEY, null, mediaDataWithDevice) + fakeBgExecutor.runAllReady() + fakeFgExecutor.runAllReady() + + // THEN we keep the device info, and don't register a listener + val data = captureDeviceData(KEY) + assertThat(data.enabled).isFalse() + assertThat(data.name).isEqualTo(REMOTE_DEVICE_NAME) + verify(lmm, never()).registerCallback(any()) + } + fun captureCallback(): LocalMediaManager.DeviceCallback { val captor = ArgumentCaptor.forClass(LocalMediaManager.DeviceCallback::class.java) verify(lmm).registerCallback(captor.capture()) diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 2717f0c4c8a4..2dc5fab47f3c 100755 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -6527,7 +6527,7 @@ public class NotificationManagerService extends SystemService { @VisibleForTesting protected void fixNotification(Notification notification, String pkg, String tag, int id, - int userId) throws NameNotFoundException { + int userId) throws NameNotFoundException, RemoteException { final ApplicationInfo ai = mPackageManagerClient.getApplicationInfoAsUser( pkg, PackageManager.MATCH_DEBUG_TRIAGED_MISSING, (userId == UserHandle.USER_ALL) ? USER_SYSTEM : userId); @@ -6561,6 +6561,21 @@ public class NotificationManagerService extends SystemService { actions.toArray(notification.actions); } + // Ensure MediaStyle has correct permissions for remote device extras + if (notification.isStyle(Notification.MediaStyle.class)) { + int hasMediaContentControlPermission = mPackageManager.checkPermission( + android.Manifest.permission.MEDIA_CONTENT_CONTROL, pkg, userId); + if (hasMediaContentControlPermission != PERMISSION_GRANTED) { + notification.extras.remove(Notification.EXTRA_MEDIA_REMOTE_DEVICE); + notification.extras.remove(Notification.EXTRA_MEDIA_REMOTE_ICON); + notification.extras.remove(Notification.EXTRA_MEDIA_REMOTE_INTENT); + if (DBG) { + Slog.w(TAG, "Package " + pkg + ": Use of setRemotePlayback requires the " + + "MEDIA_CONTENT_CONTROL permission"); + } + } + } + // Remote views? Are they too big? checkRemoteViews(pkg, tag, id, notification); } diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java index ef9494aca4a5..2bed57ab50b1 100755 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java @@ -102,6 +102,7 @@ import static org.mockito.Mockito.when; import static java.util.Collections.emptyList; import static java.util.Collections.singletonList; +import android.annotation.SuppressLint; import android.app.ActivityManager; import android.app.ActivityManagerInternal; import android.app.AlarmManager; @@ -241,6 +242,7 @@ import java.util.function.Consumer; @SmallTest @RunWith(AndroidTestingRunner.class) +@SuppressLint("GuardedBy") // It's ok for this test to access guarded methods from the service. @RunWithLooper public class NotificationManagerServiceTest extends UiServiceTestCase { private static final String TEST_CHANNEL_ID = "NotificationManagerServiceTestChannelId"; @@ -4006,6 +4008,63 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { } @Test + public void testMediaStyleRemote_hasPermission() throws RemoteException { + String deviceName = "device"; + when(mPackageManager.checkPermission( + eq(android.Manifest.permission.MEDIA_CONTENT_CONTROL), any(), anyInt())) + .thenReturn(PERMISSION_GRANTED); + Notification.MediaStyle style = new Notification.MediaStyle(); + style.setRemotePlaybackInfo(deviceName, 0, null); + Notification.Builder nb = new Notification.Builder(mContext, + mTestNotificationChannel.getId()) + .setStyle(style); + + StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 1, + "testMediaStyleRemoteHasPermission", mUid, 0, + nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0); + NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel); + + mBinderService.enqueueNotificationWithTag(PKG, PKG, sbn.getTag(), + nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); + waitForIdle(); + + NotificationRecord posted = mService.findNotificationLocked( + PKG, nr.getSbn().getTag(), nr.getSbn().getId(), nr.getSbn().getUserId()); + Bundle extras = posted.getNotification().extras; + + assertTrue(extras.containsKey(Notification.EXTRA_MEDIA_REMOTE_DEVICE)); + assertEquals(deviceName, extras.getString(Notification.EXTRA_MEDIA_REMOTE_DEVICE)); + } + + @Test + public void testMediaStyleRemote_noPermission() throws RemoteException { + String deviceName = "device"; + when(mPackageManager.checkPermission( + eq(android.Manifest.permission.MEDIA_CONTENT_CONTROL), any(), anyInt())) + .thenReturn(PERMISSION_DENIED); + Notification.MediaStyle style = new Notification.MediaStyle(); + style.setRemotePlaybackInfo(deviceName, 0, null); + Notification.Builder nb = new Notification.Builder(mContext, + mTestNotificationChannel.getId()) + .setStyle(style); + + StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 1, + "testMediaStyleRemoteNoPermission", mUid, 0, + nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0); + NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel); + + mBinderService.enqueueNotificationWithTag(PKG, PKG, sbn.getTag(), + nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); + waitForIdle(); + + NotificationRecord posted = mService.findNotificationLocked( + PKG, nr.getSbn().getTag(), nr.getSbn().getId(), nr.getSbn().getUserId()); + + assertFalse(posted.getNotification().extras + .containsKey(Notification.EXTRA_MEDIA_REMOTE_DEVICE)); + } + + @Test public void testGetNotificationCountLocked() { String sampleTagToExclude = null; int sampleIdToExclude = 0; |