Fix issues with setRemotePlaybackInfo

- Check permissions when building DecoratedMediaCustomViewStyle if it includes
the extras from this API

- Send device intent as a regular PendingIntent if it can open over lockscreen

Bug: 271846393
Test: atest NotificationManagerServiceTest MediaControlPanelTest
Test: manual using test app
Change-Id: Ida43bb4acc34d666e354c16c4344d5c5eb6b333b
Merged-In: Ida43bb4acc34d666e354c16c4344d5c5eb6b333b
(cherry picked from commit 335a3cb7b4)
This commit is contained in:
Beth Thibodeau
2023-03-14 22:43:54 -05:00
parent 8ea4e1557c
commit c90fb3f90a
4 changed files with 88 additions and 5 deletions

View File

@@ -646,12 +646,15 @@ public class MediaControlPanel {
} else {
mLogger.logOpenOutputSwitcher(mUid, mPackageName, mInstanceId);
if (device.getIntent() != null) {
if (device.getIntent().isActivity()) {
mActivityStarter.startActivity(
device.getIntent().getIntent(), true);
PendingIntent deviceIntent = device.getIntent();
boolean showOverLockscreen = mKeyguardStateController.isShowing()
&& mActivityIntentHelper.wouldPendingShowOverLockscreen(
deviceIntent, mLockscreenUserManager.getCurrentUserId());
if (deviceIntent.isActivity() && !showOverLockscreen) {
mActivityStarter.postStartActivityDismissingKeyguard(deviceIntent);
} else {
try {
device.getIntent().send();
deviceIntent.send();
} catch (PendingIntent.CanceledException e) {
Log.e(TAG, "Device pending intent was canceled");
}

View File

@@ -2350,6 +2350,48 @@ public class MediaControlPanelTest : SysuiTestCase() {
}
}
@Test
fun outputSwitcher_hasCustomIntent_openOverLockscreen() {
// When the device for a media player has an intent that opens over lockscreen
val pendingIntent = mock(PendingIntent::class.java)
whenever(pendingIntent.isActivity).thenReturn(true)
whenever(keyguardStateController.isShowing).thenReturn(true)
whenever(activityIntentHelper.wouldPendingShowOverLockscreen(any(), any())).thenReturn(true)
val customDevice = device.copy(intent = pendingIntent)
val dataWithDevice = mediaData.copy(device = customDevice)
player.attachPlayer(viewHolder)
player.bindPlayer(dataWithDevice, KEY)
// When the user taps on the output switcher,
seamless.callOnClick()
// Then we send the pending intent as is, without modifying the original intent
verify(pendingIntent).send()
verify(pendingIntent, never()).getIntent()
}
@Test
fun outputSwitcher_hasCustomIntent_requiresUnlock() {
// When the device for a media player has an intent that cannot open over lockscreen
val pendingIntent = mock(PendingIntent::class.java)
whenever(pendingIntent.isActivity).thenReturn(true)
whenever(keyguardStateController.isShowing).thenReturn(true)
whenever(activityIntentHelper.wouldPendingShowOverLockscreen(any(), any()))
.thenReturn(false)
val customDevice = device.copy(intent = pendingIntent)
val dataWithDevice = mediaData.copy(device = customDevice)
player.attachPlayer(viewHolder)
player.bindPlayer(dataWithDevice, KEY)
// When the user taps on the output switcher,
seamless.callOnClick()
// Then we request keyguard dismissal
verify(activityStarter).postStartActivityDismissingKeyguard(eq(pendingIntent))
}
private fun getScrubbingChangeListener(): SeekBarViewModel.ScrubbingChangeListener =
withArgCaptor {
verify(seekBarViewModel).setScrubbingChangeListener(capture())

View File

@@ -6751,7 +6751,8 @@ public class NotificationManagerService extends SystemService {
}
// Ensure MediaStyle has correct permissions for remote device extras
if (notification.isStyle(Notification.MediaStyle.class)) {
if (notification.isStyle(Notification.MediaStyle.class)
|| notification.isStyle(Notification.DecoratedMediaCustomViewStyle.class)) {
int hasMediaContentControlPermission = mPackageManager.checkPermission(
android.Manifest.permission.MEDIA_CONTENT_CONTROL, pkg, userId);
if (hasMediaContentControlPermission != PERMISSION_GRANTED) {

View File

@@ -4359,6 +4359,43 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
assertFalse(posted.getNotification().extras
.containsKey(Notification.EXTRA_MEDIA_REMOTE_DEVICE));
assertFalse(posted.getNotification().extras
.containsKey(Notification.EXTRA_MEDIA_REMOTE_ICON));
assertFalse(posted.getNotification().extras
.containsKey(Notification.EXTRA_MEDIA_REMOTE_INTENT));
}
@Test
public void testCustomMediaStyleRemote_noPermission() throws RemoteException {
String deviceName = "device";
when(mPackageManager.checkPermission(
eq(android.Manifest.permission.MEDIA_CONTENT_CONTROL), any(), anyInt()))
.thenReturn(PERMISSION_DENIED);
Notification.DecoratedMediaCustomViewStyle style =
new Notification.DecoratedMediaCustomViewStyle();
style.setRemotePlaybackInfo(deviceName, 0, null);
Notification.Builder nb = new Notification.Builder(mContext,
mTestNotificationChannel.getId())
.setStyle(style);
StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 1,
"testCustomMediaStyleRemoteNoPermission", 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));
assertFalse(posted.getNotification().extras
.containsKey(Notification.EXTRA_MEDIA_REMOTE_ICON));
assertFalse(posted.getNotification().extras
.containsKey(Notification.EXTRA_MEDIA_REMOTE_INTENT));
}
@Test