summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xservices/core/java/com/android/server/notification/NotificationManagerService.java16
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/NotificationListenersTest.java69
-rwxr-xr-xservices/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java53
3 files changed, 133 insertions, 5 deletions
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 76b1201a8784..0c658379fa4d 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -140,6 +140,7 @@ import static android.service.notification.NotificationListenerService.TRIM_FULL
import static android.service.notification.NotificationListenerService.TRIM_LIGHT;
import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
import static android.view.contentprotection.flags.Flags.rapidClearNotificationsByListenerAppOpEnabled;
+
import static com.android.internal.util.FrameworkStatsLog.DND_MODE_RULE;
import static com.android.internal.util.FrameworkStatsLog.PACKAGE_NOTIFICATION_CHANNEL_GROUP_PREFERENCES;
import static com.android.internal.util.FrameworkStatsLog.PACKAGE_NOTIFICATION_CHANNEL_PREFERENCES;
@@ -307,6 +308,7 @@ import android.view.Display;
import android.view.accessibility.AccessibilityManager;
import android.widget.RemoteViews;
import android.widget.Toast;
+
import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
@@ -358,7 +360,9 @@ import com.android.server.utils.quota.MultiRateLimiter;
import com.android.server.wm.ActivityTaskManagerInternal;
import com.android.server.wm.BackgroundActivityStartCallback;
import com.android.server.wm.WindowManagerInternal;
+
import libcore.io.IoUtils;
+
import org.json.JSONException;
import org.json.JSONObject;
import org.xmlpull.v1.XmlPullParserException;
@@ -11776,10 +11780,18 @@ public class NotificationManagerService extends SystemService {
}
if (lifetimeExtensionRefactor()) {
+ if (sendRedacted && redactedSbn == null) {
+ redactedSbn = redactStatusBarNotification(sbn);
+ redactedCache = new TrimCache(redactedSbn);
+ }
+ final StatusBarNotification sbnToPost = sendRedacted
+ ? redactedCache.ForListener(info) : trimCache.ForListener(info);
+
// Checks if this is a request to notify system UI about a notification that
// has been lifetime extended.
// (We only need to check old for the flag, because in both cancellation and
- // update cases, old should have the flag.)
+ // update cases, old should have the flag, whereas in update cases the
+ // new will NOT have the flag.)
// If it is such a request, and this is system UI, we send the post request
// only to System UI, and break as we don't need to continue checking other
// Managed Services.
@@ -11787,7 +11799,7 @@ public class NotificationManagerService extends SystemService {
&& (old.getNotification().flags
& FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY) > 0) {
final NotificationRankingUpdate update = makeRankingUpdateLocked(info);
- listenerCalls.add(() -> notifyPosted(info, oldSbn, update));
+ listenerCalls.add(() -> notifyPosted(info, sbnToPost, update));
break;
}
}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenersTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenersTest.java
index ae3683961d61..983e694a8f1a 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenersTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenersTest.java
@@ -70,6 +70,7 @@ import android.os.RemoteException;
import android.os.UserHandle;
import android.platform.test.flag.junit.SetFlagsRule;
import android.service.notification.INotificationListener;
+import android.service.notification.IStatusBarNotificationHolder;
import android.service.notification.NotificationListenerFilter;
import android.service.notification.NotificationListenerService;
import android.service.notification.NotificationRankingUpdate;
@@ -90,6 +91,7 @@ import com.google.common.collect.ImmutableList;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
+import org.mockito.ArgumentCaptor;
import org.mockito.ArgumentMatcher;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@@ -154,6 +156,11 @@ public class NotificationListenersTest extends UiServiceTestCase {
.thenReturn(new ArrayList<>());
mNm.mHandler = mock(NotificationManagerService.WorkerHandler.class);
mNm.mAssistants = mock(NotificationManagerService.NotificationAssistants.class);
+ FieldSetter.setField(mNm,
+ NotificationManagerService.class.getDeclaredField("mListeners"),
+ mListeners);
+ doReturn(android.service.notification.NotificationListenerService.TRIM_FULL)
+ .when(mListeners).getOnNotificationPostedTrim(any());
}
@Test
@@ -827,6 +834,68 @@ public class NotificationListenersTest extends UiServiceTestCase {
verify(mListeners, never()).redactStatusBarNotification(eq(sbn));
}
+ @Test
+ public void testListenerPost_UpdateLifetimeExtended() throws Exception {
+ mSetFlagsRule.enableFlags(android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR);
+
+ // Create original notification, with FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY.
+ String pkg = "pkg";
+ int uid = 9;
+ UserHandle userHandle = UserHandle.getUserHandleForUid(uid);
+ NotificationChannel channel = new NotificationChannel("id", "name",
+ NotificationManager.IMPORTANCE_HIGH);
+ Notification.Builder nb = new Notification.Builder(mContext, channel.getId())
+ .setContentTitle("foo")
+ .setSmallIcon(android.R.drawable.sym_def_app_icon)
+ .setFlag(Notification.FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY, true);
+ StatusBarNotification sbn = new StatusBarNotification(pkg, pkg, 8, "tag", uid, 0,
+ nb.build(), userHandle, null, 0);
+ NotificationRecord old = new NotificationRecord(mContext, sbn, channel);
+
+ // Creates updated notification (without FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY)
+ Notification.Builder nb2 = new Notification.Builder(mContext, channel.getId())
+ .setContentTitle("new title")
+ .setSmallIcon(android.R.drawable.sym_def_app_icon)
+ .setFlag(Notification.FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY, false);
+ StatusBarNotification sbn2 = new StatusBarNotification(pkg, pkg, 8, "tag", uid, 0,
+ nb2.build(), userHandle, null, 0);
+ NotificationRecord toPost = new NotificationRecord(mContext, sbn2, channel);
+
+ // Create system ui-like service.
+ ManagedServices.ManagedServiceInfo info = mListeners.new ManagedServiceInfo(
+ null, new ComponentName("a", "a"), sbn2.getUserId(), false, null, 33, 33);
+ info.isSystemUi = true;
+ INotificationListener l1 = mock(INotificationListener.class);
+ info.service = l1;
+ List<ManagedServices.ManagedServiceInfo> services = ImmutableList.of(info);
+ when(mListeners.getServices()).thenReturn(services);
+
+ FieldSetter.setField(mNm,
+ NotificationManagerService.class.getDeclaredField("mHandler"),
+ mock(NotificationManagerService.WorkerHandler.class));
+ doReturn(true).when(mNm).isVisibleToListener(any(), anyInt(), any());
+ doReturn(mock(NotificationRankingUpdate.class)).when(mNm).makeRankingUpdateLocked(info);
+ doReturn(false).when(mNm).isInLockDownMode(anyInt());
+ doNothing().when(mNm).updateUriPermissions(any(), any(), any(), anyInt());
+ doReturn(sbn2).when(mListeners).redactStatusBarNotification(sbn2);
+ doReturn(sbn2).when(mListeners).redactStatusBarNotification(any());
+
+ // The notification change is posted to the service listener.
+ mListeners.notifyPostedLocked(toPost, old);
+
+ // Verify that the post occcurs with the updated notification value.
+ ArgumentCaptor<Runnable> runnableCaptor = ArgumentCaptor.forClass(Runnable.class);
+ verify(mNm.mHandler, times(1)).post(runnableCaptor.capture());
+ runnableCaptor.getValue().run();
+ ArgumentCaptor<IStatusBarNotificationHolder> sbnCaptor =
+ ArgumentCaptor.forClass(IStatusBarNotificationHolder.class);
+ verify(l1, times(1)).onNotificationPosted(sbnCaptor.capture(), any());
+ StatusBarNotification sbnResult = sbnCaptor.getValue().get();
+ assertThat(sbnResult.getNotification()
+ .extras.getCharSequence(Notification.EXTRA_TITLE).toString())
+ .isEqualTo("new title");
+ }
+
/**
* Helper method to test the thread safety of some operations.
*
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 011f2e39d6f8..aec47146e833 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -106,6 +106,7 @@ import static android.service.notification.NotificationListenerService.Ranking.U
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Display.INVALID_DISPLAY;
import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
+
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN;
import static com.android.server.am.PendingIntentRecord.FLAG_ACTIVITY_SENDER;
import static com.android.server.am.PendingIntentRecord.FLAG_BROADCAST_SENDER;
@@ -118,11 +119,11 @@ import static com.android.server.notification.NotificationManagerService.TAG;
import static com.android.server.notification.NotificationRecordLogger.NotificationReportedEvent.NOTIFICATION_ADJUSTED;
import static com.android.server.notification.NotificationRecordLogger.NotificationReportedEvent.NOTIFICATION_POSTED;
import static com.android.server.notification.NotificationRecordLogger.NotificationReportedEvent.NOTIFICATION_UPDATED;
+
import static com.google.common.collect.Iterables.getOnlyElement;
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
-import static java.util.Collections.emptyList;
-import static java.util.Collections.singletonList;
+
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertNotNull;
@@ -131,6 +132,7 @@ import static junit.framework.Assert.assertNull;
import static junit.framework.Assert.assertSame;
import static junit.framework.Assert.assertTrue;
import static junit.framework.Assert.fail;
+
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertThrows;
import static org.mockito.ArgumentMatchers.isNull;
@@ -157,6 +159,9 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
+import static java.util.Collections.emptyList;
+import static java.util.Collections.singletonList;
+
import android.Manifest;
import android.annotation.Nullable;
import android.annotation.SuppressLint;
@@ -270,8 +275,10 @@ import android.util.Pair;
import android.util.Xml;
import android.view.accessibility.AccessibilityManager;
import android.widget.RemoteViews;
+
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
+
import com.android.internal.R;
import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
import com.android.internal.config.sysui.TestableFlagResolver;
@@ -303,10 +310,12 @@ import com.android.server.uri.UriGrantsManagerInternal;
import com.android.server.utils.quota.MultiRateLimiter;
import com.android.server.wm.ActivityTaskManagerInternal;
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;
@@ -5934,6 +5943,45 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
}
@Test
+ @EnableFlags(android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR)
+ public void testUpdate_DirectReplyLifetimeExtendedUpdateSucceeds() throws Exception {
+ // Creates a lifetime extended notification.
+ NotificationRecord original = generateNotificationRecord(mTestNotificationChannel);
+ original.getSbn().getNotification().flags |= FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY;
+ mService.addNotification(original);
+
+ // Post an update for that notification.
+ StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, original.getSbn().getId(),
+ original.getSbn().getTag(), mUid, 0,
+ new Notification.Builder(mContext, mTestNotificationChannel.getId())
+ .setSmallIcon(android.R.drawable.sym_def_app_icon)
+ .setContentTitle("new title").build(),
+ UserHandle.getUserHandleForUid(mUid), null, 0);
+ NotificationRecord update = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
+ mService.addEnqueuedNotification(update);
+
+ NotificationManagerService.PostNotificationRunnable runnable =
+ mService.new PostNotificationRunnable(update.getKey(),
+ update.getSbn().getPackageName(),
+ update.getUid(),
+ mPostNotificationTrackerFactory.newTracker(null));
+ runnable.run();
+ waitForIdle();
+
+ // Checks the update was sent, and that update contains the new title, and does not contain
+ // the lifetime extension flag.
+ ArgumentCaptor<NotificationRecord> captor =
+ ArgumentCaptor.forClass(NotificationRecord.class);
+ verify(mListeners, times(1)).prepareNotifyPostedLocked(captor.capture(), any(),
+ anyBoolean());
+ assertThat(captor.getValue().getNotification().flags
+ & FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY).isEqualTo(0);
+ assertThat(captor.getValue()
+ .getNotification().extras.getCharSequence(Notification.EXTRA_TITLE).toString())
+ .isEqualTo("new title");
+ }
+
+ @Test
public void testStats_updatedOnUserExpansion() throws Exception {
NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
mService.addNotification(r);
@@ -12602,7 +12650,6 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
// the notifyPostedLocked function is called twice.
verify(mWorkerHandler, times(2)).postDelayed(any(Runnable.class), anyLong());
- //verify(mListeners, times(2)).notifyPostedLocked(any(), any());
}
@Test