summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/app/Notification.java6
-rwxr-xr-xservices/core/java/com/android/server/notification/NotificationManagerService.java13
-rw-r--r--services/tests/uiservicestests/Android.bp1
-rwxr-xr-xservices/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java139
4 files changed, 108 insertions, 51 deletions
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 93c2b5ad4d86..dd7db23d668b 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -9195,6 +9195,12 @@ public class Notification implements Parcelable
* You can opt-out of this behavior by using {@link Notification.Builder#setColorized(boolean)}.
* <p>
*
+ * <p>
+ * Starting at {@link android.os.Build.VERSION_CODES#VANILLA_ICE_CREAM Android V} the
+ * {@link Notification#FLAG_NO_CLEAR NO_CLEAR flag} will be set for valid MediaStyle
+ * notifications.
+ * <p>
+ *
* To use this style with your Notification, feed it to
* {@link Notification.Builder#setStyle(android.app.Notification.Style)} like so:
* <pre class="prettyprint">
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index a3c71c2e0218..db69d93583d4 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -541,6 +541,13 @@ public class NotificationManagerService extends SystemService {
@EnabledAfter(targetSdkVersion = Build.VERSION_CODES.S_V2)
private static final long NOTIFICATION_LOG_ASSISTANT_CANCEL = 195579280L;
+ /**
+ * NO_CLEAR flag will be set for any media notification.
+ */
+ @ChangeId
+ @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+ static final long ENFORCE_NO_CLEAR_FLAG_ON_MEDIA_NOTIFICATION = 264179692L;
+
private static final Duration POST_WAKE_LOCK_TIMEOUT = Duration.ofSeconds(30);
private IActivityManager mAm;
@@ -7189,6 +7196,12 @@ public class NotificationManagerService extends SystemService {
+ "MEDIA_CONTENT_CONTROL permission");
}
}
+
+ // Enforce NO_CLEAR flag on MediaStyle notification for apps with targetSdk >= V.
+ if (CompatChanges.isChangeEnabled(ENFORCE_NO_CLEAR_FLAG_ON_MEDIA_NOTIFICATION,
+ notificationUid)) {
+ notification.flags |= Notification.FLAG_NO_CLEAR;
+ }
}
// Ensure only allowed packages have a substitute app name
diff --git a/services/tests/uiservicestests/Android.bp b/services/tests/uiservicestests/Android.bp
index 2dacda0af7f4..1d37f9da8d7a 100644
--- a/services/tests/uiservicestests/Android.bp
+++ b/services/tests/uiservicestests/Android.bp
@@ -31,6 +31,7 @@ android_test {
"androidx.test.rules",
"hamcrest-library",
"mockito-target-inline-minus-junit4",
+ "platform-compat-test-rules",
"platform-test-annotations",
"platformprotosnano",
"statsdprotolite",
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 9543a2de1e13..c98d2359b2f9 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -164,6 +164,7 @@ import android.app.admin.DevicePolicyManagerInternal;
import android.app.usage.UsageStatsManagerInternal;
import android.companion.AssociationInfo;
import android.companion.ICompanionDeviceManager;
+import android.compat.testing.PlatformCompatChangeRule;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.ContentUris;
@@ -270,11 +271,15 @@ import com.android.server.wm.WindowManagerInternal;
import com.google.android.collect.Lists;
import com.google.common.collect.ImmutableList;
+import libcore.junit.util.compat.CoreCompatChangeRule.DisableCompatChanges;
+import libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges;
+
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
+import org.junit.rules.TestRule;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.ArgumentMatcher;
@@ -317,6 +322,9 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
private final int mUid = Binder.getCallingUid();
private final @UserIdInt int mUserId = UserHandle.getUserId(mUid);
+ @Rule
+ public TestRule compatChangeRule = new PlatformCompatChangeRule();
+
private TestableNotificationManagerService mService;
private INotificationManager mBinderService;
private NotificationManagerInternal mInternalService;
@@ -4828,6 +4836,62 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
}
@Test
+ @EnableCompatChanges({NotificationManagerService.ENFORCE_NO_CLEAR_FLAG_ON_MEDIA_NOTIFICATION})
+ public void testMediaStyle_enforceNoClearFlagEnabled() throws RemoteException {
+ Notification.MediaStyle style = new Notification.MediaStyle();
+ Notification.Builder nb = new Notification.Builder(mContext,
+ mTestNotificationChannel.getId())
+ .setStyle(style);
+
+ NotificationRecord posted = createAndPostNotification(nb, "testMediaStyleSetNoClearFlag");
+
+ assertThat(posted.getFlags() & FLAG_NO_CLEAR).isEqualTo(FLAG_NO_CLEAR);
+ }
+
+ @Test
+ @EnableCompatChanges({NotificationManagerService.ENFORCE_NO_CLEAR_FLAG_ON_MEDIA_NOTIFICATION})
+ public void testCustomMediaStyle_enforceNoClearFlagEnabled() throws RemoteException {
+ Notification.DecoratedMediaCustomViewStyle style =
+ new Notification.DecoratedMediaCustomViewStyle();
+ Notification.Builder nb = new Notification.Builder(mContext,
+ mTestNotificationChannel.getId())
+ .setStyle(style);
+
+ NotificationRecord posted = createAndPostNotification(nb,
+ "testCustomMediaStyleSetNoClearFlag");
+
+ assertThat(posted.getFlags() & FLAG_NO_CLEAR).isEqualTo(FLAG_NO_CLEAR);
+ }
+
+ @Test
+ @DisableCompatChanges(NotificationManagerService.ENFORCE_NO_CLEAR_FLAG_ON_MEDIA_NOTIFICATION)
+ public void testMediaStyle_enforceNoClearFlagDisabled() throws RemoteException {
+ Notification.MediaStyle style = new Notification.MediaStyle();
+ Notification.Builder nb = new Notification.Builder(mContext,
+ mTestNotificationChannel.getId())
+ .setStyle(style);
+
+ NotificationRecord posted = createAndPostNotification(nb, "testMediaStyleSetNoClearFlag");
+
+ assertThat(posted.getFlags() & FLAG_NO_CLEAR).isNotEqualTo(FLAG_NO_CLEAR);
+ }
+
+ @Test
+ @DisableCompatChanges(NotificationManagerService.ENFORCE_NO_CLEAR_FLAG_ON_MEDIA_NOTIFICATION)
+ public void testCustomMediaStyle_enforceNoClearFlagDisabled() throws RemoteException {
+ Notification.DecoratedMediaCustomViewStyle style =
+ new Notification.DecoratedMediaCustomViewStyle();
+ Notification.Builder nb = new Notification.Builder(mContext,
+ mTestNotificationChannel.getId())
+ .setStyle(style);
+
+ NotificationRecord posted = createAndPostNotification(nb,
+ "testCustomMediaStyleSetNoClearFlag");
+
+ assertThat(posted.getFlags() & FLAG_NO_CLEAR).isNotEqualTo(FLAG_NO_CLEAR);
+ }
+
+ @Test
public void testMediaStyleRemote_hasPermission() throws RemoteException {
String deviceName = "device";
mContext.getTestablePermissions().setPermission(
@@ -4838,17 +4902,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
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());
+ NotificationRecord posted = createAndPostNotification(nb,
+ "testMediaStyleRemoteHasPermission");
Bundle extras = posted.getNotification().extras;
assertTrue(extras.containsKey(Notification.EXTRA_MEDIA_REMOTE_DEVICE));
@@ -4866,17 +4921,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
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());
+ NotificationRecord posted = createAndPostNotification(nb,
+ "testMediaStyleRemoteNoPermission");
assertFalse(posted.getNotification().extras
.containsKey(Notification.EXTRA_MEDIA_REMOTE_DEVICE));
@@ -4899,17 +4945,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
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());
+ NotificationRecord posted = createAndPostNotification(nb,
+ "testCustomMediaStyleRemoteNoPermission");
assertFalse(posted.getNotification().extras
.containsKey(Notification.EXTRA_MEDIA_REMOTE_DEVICE));
@@ -4929,16 +4966,9 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
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());
+ NotificationRecord posted = createAndPostNotification(nb,
+ "testSubstituteAppNameHasPermission");
assertTrue(posted.getNotification().extras
.containsKey(Notification.EXTRA_SUBSTITUTE_APP_NAME));
@@ -4955,16 +4985,9 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
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());
+ NotificationRecord posted = createAndPostNotification(nb,
+ "testSubstituteAppNameNoPermission");
assertFalse(posted.getNotification().extras
.containsKey(Notification.EXTRA_SUBSTITUTE_APP_NAME));
@@ -12656,6 +12679,20 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
verify(service, times(1)).setDNDMigrationDone(user.id);
}
+ private NotificationRecord createAndPostNotification(Notification.Builder nb, String testName)
+ throws RemoteException {
+ StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 1, testName, 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();
+
+ return mService.findNotificationLocked(
+ PKG, nr.getSbn().getTag(), nr.getSbn().getId(), nr.getSbn().getUserId());
+ }
+
private static <T extends Parcelable> T parcelAndUnparcel(T source,
Parcelable.Creator<T> creator) {
Parcel parcel = Parcel.obtain();