Merge "Suppress HUNs for notifications with old whens" into tm-qpr-dev
This commit is contained in:
@@ -44,4 +44,8 @@ class NotifPipelineFlags @Inject constructor(
|
||||
val shouldFilterUnseenNotifsOnKeyguard: Boolean by lazy {
|
||||
featureFlags.isEnabled(Flags.FILTER_UNSEEN_NOTIFS_ON_KEYGUARD)
|
||||
}
|
||||
|
||||
val isNoHunForOldWhenEnabled: Boolean by lazy {
|
||||
featureFlags.isEnabled(Flags.NO_HUN_FOR_OLD_WHEN)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -106,6 +106,36 @@ class NotificationInterruptLogger @Inject constructor(
|
||||
})
|
||||
}
|
||||
|
||||
fun logNoHeadsUpOldWhen(
|
||||
entry: NotificationEntry,
|
||||
notifWhen: Long,
|
||||
notifAge: Long
|
||||
) {
|
||||
buffer.log(TAG, DEBUG, {
|
||||
str1 = entry.logKey
|
||||
long1 = notifWhen
|
||||
long2 = notifAge
|
||||
}, {
|
||||
"No heads up: old when $long1 (age=$long2 ms): $str1"
|
||||
})
|
||||
}
|
||||
|
||||
fun logMaybeHeadsUpDespiteOldWhen(
|
||||
entry: NotificationEntry,
|
||||
notifWhen: Long,
|
||||
notifAge: Long,
|
||||
reason: String
|
||||
) {
|
||||
buffer.log(TAG, DEBUG, {
|
||||
str1 = entry.logKey
|
||||
str2 = reason
|
||||
long1 = notifWhen
|
||||
long2 = notifAge
|
||||
}, {
|
||||
"Maybe heads up: old when $long1 (age=$long2 ms) but $str2: $str1"
|
||||
})
|
||||
}
|
||||
|
||||
fun logNoHeadsUpSuppressedBy(
|
||||
entry: NotificationEntry,
|
||||
suppressor: NotificationInterruptSuppressor
|
||||
|
||||
@@ -20,6 +20,7 @@ import static com.android.systemui.statusbar.StatusBarState.SHADE;
|
||||
import static com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProviderImpl.NotificationInterruptEvent.FSI_SUPPRESSED_NO_HUN_OR_KEYGUARD;
|
||||
import static com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProviderImpl.NotificationInterruptEvent.FSI_SUPPRESSED_SUPPRESSIVE_GROUP_ALERT_BEHAVIOR;
|
||||
|
||||
import android.app.Notification;
|
||||
import android.app.NotificationManager;
|
||||
import android.content.ContentResolver;
|
||||
import android.database.ContentObserver;
|
||||
@@ -82,7 +83,10 @@ public class NotificationInterruptStateProviderImpl implements NotificationInter
|
||||
FSI_SUPPRESSED_SUPPRESSIVE_GROUP_ALERT_BEHAVIOR(1235),
|
||||
|
||||
@UiEvent(doc = "FSI suppressed for requiring neither HUN nor keyguard")
|
||||
FSI_SUPPRESSED_NO_HUN_OR_KEYGUARD(1236);
|
||||
FSI_SUPPRESSED_NO_HUN_OR_KEYGUARD(1236),
|
||||
|
||||
@UiEvent(doc = "HUN suppressed for old when")
|
||||
HUN_SUPPRESSED_OLD_WHEN(1237);
|
||||
|
||||
private final int mId;
|
||||
|
||||
@@ -346,6 +350,10 @@ public class NotificationInterruptStateProviderImpl implements NotificationInter
|
||||
return false;
|
||||
}
|
||||
|
||||
if (shouldSuppressHeadsUpWhenAwakeForOldWhen(entry, log)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < mSuppressors.size(); i++) {
|
||||
if (mSuppressors.get(i).suppressAwakeHeadsUp(entry)) {
|
||||
if (log) mLogger.logNoHeadsUpSuppressedBy(entry, mSuppressors.get(i));
|
||||
@@ -470,4 +478,51 @@ public class NotificationInterruptStateProviderImpl implements NotificationInter
|
||||
private boolean isSnoozedPackage(StatusBarNotification sbn) {
|
||||
return mHeadsUpManager.isSnoozed(sbn.getPackageName());
|
||||
}
|
||||
|
||||
private boolean shouldSuppressHeadsUpWhenAwakeForOldWhen(NotificationEntry entry, boolean log) {
|
||||
if (!mFlags.isNoHunForOldWhenEnabled()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final Notification notification = entry.getSbn().getNotification();
|
||||
if (notification == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final long when = notification.when;
|
||||
final long now = System.currentTimeMillis();
|
||||
final long age = now - when;
|
||||
|
||||
if (age < MAX_HUN_WHEN_AGE_MS) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (when <= 0) {
|
||||
// Some notifications (including many system notifications) are posted with the "when"
|
||||
// field set to 0. Nothing in the Javadocs for Notification mentions a special meaning
|
||||
// for a "when" of 0, but Android didn't even exist at the dawn of the Unix epoch.
|
||||
// Therefore, assume that these notifications effectively don't have a "when" value,
|
||||
// and don't suppress HUNs.
|
||||
if (log) mLogger.logMaybeHeadsUpDespiteOldWhen(entry, when, age, "when <= 0");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (notification.fullScreenIntent != null) {
|
||||
if (log) mLogger.logMaybeHeadsUpDespiteOldWhen(entry, when, age, "full-screen intent");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (notification.isForegroundService()) {
|
||||
if (log) mLogger.logMaybeHeadsUpDespiteOldWhen(entry, when, age, "foreground service");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (log) mLogger.logNoHeadsUpOldWhen(entry, when, age);
|
||||
final int uid = entry.getSbn().getUid();
|
||||
final String packageName = entry.getSbn().getPackageName();
|
||||
mUiEventLogger.log(NotificationInterruptEvent.HUN_SUPPRESSED_OLD_WHEN, uid, packageName);
|
||||
return true;
|
||||
}
|
||||
|
||||
public static final long MAX_HUN_WHEN_AGE_MS = 24 * 60 * 60 * 1000;
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ package com.android.systemui.statusbar.notification.interruption;
|
||||
|
||||
|
||||
import static android.app.Notification.FLAG_BUBBLE;
|
||||
import static android.app.Notification.FLAG_FOREGROUND_SERVICE;
|
||||
import static android.app.Notification.GROUP_ALERT_SUMMARY;
|
||||
import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
|
||||
import static android.app.NotificationManager.IMPORTANCE_HIGH;
|
||||
@@ -33,6 +34,8 @@ import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.ArgumentMatchers.anyLong;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
@@ -390,6 +393,127 @@ public class NotificationInterruptStateProviderImplTest extends SysuiTestCase {
|
||||
assertThat(mNotifInterruptionStateProvider.shouldHeadsUp(entry)).isFalse();
|
||||
}
|
||||
|
||||
private long makeWhenHoursAgo(long hoursAgo) {
|
||||
return System.currentTimeMillis() - (1000 * 60 * 60 * hoursAgo);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testShouldHeadsUp_oldWhen_flagDisabled() throws Exception {
|
||||
ensureStateForHeadsUpWhenAwake();
|
||||
when(mFlags.isNoHunForOldWhenEnabled()).thenReturn(false);
|
||||
|
||||
NotificationEntry entry = createNotification(IMPORTANCE_HIGH);
|
||||
entry.getSbn().getNotification().when = makeWhenHoursAgo(25);
|
||||
|
||||
assertThat(mNotifInterruptionStateProvider.shouldHeadsUp(entry)).isTrue();
|
||||
|
||||
verify(mLogger, never()).logNoHeadsUpOldWhen(any(), anyLong(), anyLong());
|
||||
verify(mLogger, never()).logMaybeHeadsUpDespiteOldWhen(any(), anyLong(), anyLong(), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testShouldHeadsUp_oldWhen_whenNow() throws Exception {
|
||||
ensureStateForHeadsUpWhenAwake();
|
||||
when(mFlags.isNoHunForOldWhenEnabled()).thenReturn(true);
|
||||
|
||||
NotificationEntry entry = createNotification(IMPORTANCE_HIGH);
|
||||
|
||||
assertThat(mNotifInterruptionStateProvider.shouldHeadsUp(entry)).isTrue();
|
||||
|
||||
verify(mLogger, never()).logNoHeadsUpOldWhen(any(), anyLong(), anyLong());
|
||||
verify(mLogger, never()).logMaybeHeadsUpDespiteOldWhen(any(), anyLong(), anyLong(), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testShouldHeadsUp_oldWhen_whenRecent() throws Exception {
|
||||
ensureStateForHeadsUpWhenAwake();
|
||||
when(mFlags.isNoHunForOldWhenEnabled()).thenReturn(true);
|
||||
|
||||
NotificationEntry entry = createNotification(IMPORTANCE_HIGH);
|
||||
entry.getSbn().getNotification().when = makeWhenHoursAgo(13);
|
||||
|
||||
assertThat(mNotifInterruptionStateProvider.shouldHeadsUp(entry)).isTrue();
|
||||
|
||||
verify(mLogger, never()).logNoHeadsUpOldWhen(any(), anyLong(), anyLong());
|
||||
verify(mLogger, never()).logMaybeHeadsUpDespiteOldWhen(any(), anyLong(), anyLong(), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testShouldHeadsUp_oldWhen_whenZero() throws Exception {
|
||||
ensureStateForHeadsUpWhenAwake();
|
||||
when(mFlags.isNoHunForOldWhenEnabled()).thenReturn(true);
|
||||
|
||||
NotificationEntry entry = createNotification(IMPORTANCE_HIGH);
|
||||
entry.getSbn().getNotification().when = 0L;
|
||||
|
||||
assertThat(mNotifInterruptionStateProvider.shouldHeadsUp(entry)).isTrue();
|
||||
|
||||
verify(mLogger, never()).logNoHeadsUpOldWhen(any(), anyLong(), anyLong());
|
||||
verify(mLogger).logMaybeHeadsUpDespiteOldWhen(eq(entry), eq(0L), anyLong(),
|
||||
eq("when <= 0"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testShouldHeadsUp_oldWhen_whenNegative() throws Exception {
|
||||
ensureStateForHeadsUpWhenAwake();
|
||||
when(mFlags.isNoHunForOldWhenEnabled()).thenReturn(true);
|
||||
|
||||
NotificationEntry entry = createNotification(IMPORTANCE_HIGH);
|
||||
entry.getSbn().getNotification().when = -1L;
|
||||
|
||||
assertThat(mNotifInterruptionStateProvider.shouldHeadsUp(entry)).isTrue();
|
||||
verify(mLogger, never()).logNoHeadsUpOldWhen(any(), anyLong(), anyLong());
|
||||
verify(mLogger).logMaybeHeadsUpDespiteOldWhen(eq(entry), eq(-1L), anyLong(),
|
||||
eq("when <= 0"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testShouldHeadsUp_oldWhen_hasFullScreenIntent() throws Exception {
|
||||
ensureStateForHeadsUpWhenAwake();
|
||||
when(mFlags.isNoHunForOldWhenEnabled()).thenReturn(true);
|
||||
long when = makeWhenHoursAgo(25);
|
||||
|
||||
NotificationEntry entry = createFsiNotification(IMPORTANCE_HIGH, /* silent= */ false);
|
||||
entry.getSbn().getNotification().when = when;
|
||||
|
||||
assertThat(mNotifInterruptionStateProvider.shouldHeadsUp(entry)).isTrue();
|
||||
|
||||
verify(mLogger, never()).logNoHeadsUpOldWhen(any(), anyLong(), anyLong());
|
||||
verify(mLogger).logMaybeHeadsUpDespiteOldWhen(eq(entry), eq(when), anyLong(),
|
||||
eq("full-screen intent"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testShouldHeadsUp_oldWhen_isForegroundService() throws Exception {
|
||||
ensureStateForHeadsUpWhenAwake();
|
||||
when(mFlags.isNoHunForOldWhenEnabled()).thenReturn(true);
|
||||
long when = makeWhenHoursAgo(25);
|
||||
|
||||
NotificationEntry entry = createFgsNotification(IMPORTANCE_HIGH);
|
||||
entry.getSbn().getNotification().when = when;
|
||||
|
||||
assertThat(mNotifInterruptionStateProvider.shouldHeadsUp(entry)).isTrue();
|
||||
|
||||
verify(mLogger, never()).logNoHeadsUpOldWhen(any(), anyLong(), anyLong());
|
||||
verify(mLogger).logMaybeHeadsUpDespiteOldWhen(eq(entry), eq(when), anyLong(),
|
||||
eq("foreground service"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testShouldNotHeadsUp_oldWhen() throws Exception {
|
||||
ensureStateForHeadsUpWhenAwake();
|
||||
when(mFlags.isNoHunForOldWhenEnabled()).thenReturn(true);
|
||||
long when = makeWhenHoursAgo(25);
|
||||
|
||||
NotificationEntry entry = createNotification(IMPORTANCE_HIGH);
|
||||
entry.getSbn().getNotification().when = when;
|
||||
|
||||
assertThat(mNotifInterruptionStateProvider.shouldHeadsUp(entry)).isFalse();
|
||||
|
||||
verify(mLogger).logNoHeadsUpOldWhen(eq(entry), eq(when), anyLong());
|
||||
verify(mLogger, never()).logMaybeHeadsUpDespiteOldWhen(any(), anyLong(), anyLong(), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testShouldNotFullScreen_notPendingIntent_withStrictFlag() throws Exception {
|
||||
when(mFlags.fullScreenIntentRequiresKeyguard()).thenReturn(true);
|
||||
@@ -763,6 +887,16 @@ public class NotificationInterruptStateProviderImplTest extends SysuiTestCase {
|
||||
return createNotification(importance, n);
|
||||
}
|
||||
|
||||
private NotificationEntry createFgsNotification(int importance) {
|
||||
Notification n = new Notification.Builder(getContext(), "a")
|
||||
.setContentTitle("title")
|
||||
.setContentText("content text")
|
||||
.setFlag(FLAG_FOREGROUND_SERVICE, true)
|
||||
.build();
|
||||
|
||||
return createNotification(importance, n);
|
||||
}
|
||||
|
||||
private final NotificationInterruptSuppressor
|
||||
mSuppressAwakeHeadsUp =
|
||||
new NotificationInterruptSuppressor() {
|
||||
|
||||
Reference in New Issue
Block a user