Merge "Improve app name handling" into tm-qpr-dev am: e4611ad637

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/19669409

Change-Id: Ia00296624405fe4756256920408c8d308afd5d2a
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
Beth Thibodeau
2022-08-22 20:29:14 +00:00
committed by Automerger Merge Worker
4 changed files with 126 additions and 13 deletions

View File

@@ -17,6 +17,7 @@
package com.android.systemui.media
import android.app.Notification
import android.app.Notification.EXTRA_SUBSTITUTE_APP_NAME
import android.app.PendingIntent
import android.app.smartspace.SmartspaceConfig
import android.app.smartspace.SmartspaceManager
@@ -27,6 +28,7 @@ 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
@@ -57,8 +59,8 @@ import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.dump.DumpManager
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.plugins.BcSmartspaceDataPlugin
import com.android.systemui.statusbar.NotificationMediaManager.isPlayingState
import com.android.systemui.statusbar.NotificationMediaManager.isConnectingState
import com.android.systemui.statusbar.NotificationMediaManager.isPlayingState
import com.android.systemui.statusbar.notification.row.HybridGroupManager
import com.android.systemui.tuner.TunerService
import com.android.systemui.util.Assert
@@ -633,9 +635,14 @@ class MediaDataManager(
}
val mediaController = mediaControllerFactory.create(token)
val metadata = mediaController.metadata
val notif: Notification = sbn.notification
val appInfo = notif.extras.getParcelable(
Notification.EXTRA_BUILDER_APPLICATION_INFO,
ApplicationInfo::class.java
) ?: getAppInfoFromPackage(sbn.packageName)
// Album art
val notif: Notification = sbn.notification
var artworkBitmap = metadata?.let { loadBitmapFromUri(it) }
if (artworkBitmap == null) {
artworkBitmap = metadata?.getBitmap(MediaMetadata.METADATA_KEY_ART)
@@ -650,8 +657,7 @@ class MediaDataManager(
}
// App name
val builder = Notification.Builder.recoverBuilder(context, notif)
val app = builder.loadHeaderAppName()
val appName = getAppName(sbn, appInfo)
// App Icon
val smallIcon = sbn.notification.smallIcon
@@ -712,12 +718,7 @@ class MediaDataManager(
val currentEntry = mediaEntries.get(key)
val instanceId = currentEntry?.instanceId ?: logger.getNewInstanceId()
val appUid = try {
context.packageManager.getApplicationInfo(sbn.packageName, 0)?.uid!!
} catch (e: PackageManager.NameNotFoundException) {
Log.w(TAG, "Could not get app UID for ${sbn.packageName}", e)
Process.INVALID_UID
}
val appUid = appInfo?.uid ?: Process.INVALID_UID
if (logEvent) {
logger.logActiveMediaAdded(appUid, sbn.packageName, instanceId, playbackLocation)
@@ -730,7 +731,7 @@ class MediaDataManager(
val resumeAction: Runnable? = mediaEntries[key]?.resumeAction
val hasCheckedForResume = mediaEntries[key]?.hasCheckedForResume == true
val active = mediaEntries[key]?.active ?: true
onMediaDataLoaded(key, oldKey, MediaData(sbn.normalizedUserId, true, app,
onMediaDataLoaded(key, oldKey, MediaData(sbn.normalizedUserId, true, appName,
smallIcon, artist, song, artWorkIcon, actionIcons, actionsToShowCollapsed,
semanticActions, sbn.packageName, token, notif.contentIntent, device,
active, resumeAction = resumeAction, playbackLocation = playbackLocation,
@@ -740,6 +741,28 @@ class MediaDataManager(
}
}
private fun getAppInfoFromPackage(packageName: String): ApplicationInfo? {
try {
return context.packageManager.getApplicationInfo(packageName, 0)
} catch (e: PackageManager.NameNotFoundException) {
Log.w(TAG, "Could not get app info for $packageName", e)
}
return null
}
private fun getAppName(sbn: StatusBarNotification, appInfo: ApplicationInfo?): String {
val name = sbn.notification.extras.getString(EXTRA_SUBSTITUTE_APP_NAME)
if (name != null) {
return name
}
return if (appInfo != null) {
context.packageManager.getApplicationLabel(appInfo).toString()
} else {
sbn.packageName
}
}
/**
* Generate action buttons based on notification actions
*/

View File

@@ -50,11 +50,10 @@ import org.mockito.Mock
import org.mockito.Mockito
import org.mockito.Mockito.never
import org.mockito.Mockito.reset
import org.mockito.Mockito.times
import org.mockito.Mockito.verify
import org.mockito.Mockito.verifyNoMoreInteractions
import org.mockito.junit.MockitoJUnit
import org.mockito.Mockito.`when` as whenever
import org.mockito.junit.MockitoJUnit
private const val KEY = "KEY"
private const val KEY_2 = "KEY_2"
@@ -286,6 +285,30 @@ class MediaDataManagerTest : SysuiTestCase() {
eq(mediaDataCaptor.value.instanceId), eq(MediaData.PLAYBACK_CAST_REMOTE))
}
@Test
fun testOnNotificationAdded_hasSubstituteName_isUsed() {
val subName = "Substitute Name"
val notif = SbnBuilder().run {
modifyNotification(context).also {
it.extras = Bundle().apply {
putString(Notification.EXTRA_SUBSTITUTE_APP_NAME, subName)
}
it.setStyle(MediaStyle().apply {
setMediaSession(session.sessionToken)
})
}
build()
}
mediaDataManager.onNotificationAdded(KEY, notif)
assertThat(backgroundExecutor.runAllReady()).isEqualTo(1)
assertThat(foregroundExecutor.runAllReady()).isEqualTo(1)
verify(listener).onMediaDataLoaded(eq(KEY), eq(null), capture(mediaDataCaptor), eq(true),
eq(0), eq(false))
assertThat(mediaDataCaptor.value!!.app).isEqualTo(subName)
}
@Test
fun testLoadMediaDataInBg_invalidTokenNoCrash() {
val bundle = Bundle()

View File

@@ -6685,6 +6685,20 @@ public class NotificationManagerService extends SystemService {
}
}
// Ensure only allowed packages have a substitute app name
if (notification.extras.containsKey(Notification.EXTRA_SUBSTITUTE_APP_NAME)) {
int hasSubstituteAppNamePermission = mPackageManager.checkPermission(
permission.SUBSTITUTE_NOTIFICATION_APP_NAME, pkg, userId);
if (hasSubstituteAppNamePermission != PERMISSION_GRANTED) {
notification.extras.remove(Notification.EXTRA_SUBSTITUTE_APP_NAME);
if (DBG) {
Slog.w(TAG, "warning: pkg " + pkg + " attempting to substitute app name"
+ " without holding perm "
+ Manifest.permission.SUBSTITUTE_NOTIFICATION_APP_NAME);
}
}
}
// Remote views? Are they too big?
checkRemoteViews(pkg, tag, id, notification);
}

View File

@@ -4238,6 +4238,59 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
.containsKey(Notification.EXTRA_MEDIA_REMOTE_DEVICE));
}
@Test
public void testSubstituteAppName_hasPermission() throws RemoteException {
String subName = "Substitute Name";
when(mPackageManager.checkPermission(
eq(android.Manifest.permission.SUBSTITUTE_NOTIFICATION_APP_NAME), any(), anyInt()))
.thenReturn(PERMISSION_GRANTED);
Bundle extras = new Bundle();
extras.putString(Notification.EXTRA_SUBSTITUTE_APP_NAME, subName);
Notification.Builder nb = new Notification.Builder(mContext,
mTestNotificationChannel.getId())
.addExtras(extras);
StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 1,
"testSubstituteAppNamePermission", 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());
assertTrue(posted.getNotification().extras
.containsKey(Notification.EXTRA_SUBSTITUTE_APP_NAME));
assertEquals(posted.getNotification().extras
.getString(Notification.EXTRA_SUBSTITUTE_APP_NAME), subName);
}
@Test
public void testSubstituteAppName_noPermission() throws RemoteException {
when(mPackageManager.checkPermission(
eq(android.Manifest.permission.SUBSTITUTE_NOTIFICATION_APP_NAME), any(), anyInt()))
.thenReturn(PERMISSION_DENIED);
Bundle extras = new Bundle();
extras.putString(Notification.EXTRA_SUBSTITUTE_APP_NAME, "Substitute Name");
Notification.Builder nb = new Notification.Builder(mContext,
mTestNotificationChannel.getId())
.addExtras(extras);
StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 1,
"testSubstituteAppNamePermission", 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_SUBSTITUTE_APP_NAME));
}
@Test
public void testGetNotificationCountLocked() {
String sampleTagToExclude = null;