summaryrefslogtreecommitdiff
path: root/java/com/android/dialer/app
diff options
context:
space:
mode:
authorsail <sail@google.com>2017-08-15 03:26:40 -0700
committerEric Erfanian <erfanian@google.com>2017-08-15 08:30:26 -0700
commitf6ece054859eeac5265931a83ba122b85b6c89e3 (patch)
tree25f2660a63f4e7a1c04f0b21c6880e2206f65566 /java/com/android/dialer/app
parent1998bb675eb9e3b3363095b3b6a09d71e947e179 (diff)
Add a rate limiter for Dialer notifications
Android only allows apps to post a maximum of 50 notifications. After this limit is exhausted no more notifications are allowed. This breaks features like incoming phone calls. This CL works around the issue by adding a rate limiter for all cases where a feature posts more than one notification: - call quality feedbakc notifications - missed call notifications - visual vociemail notifications - spam notifications The rate limit is applied on a per group basis. Each group is allowed a maximum of 10 notifications. When the limit is exceeded older notifications are cancelled until we're under the threshold. Some things to note: - the "group summary" for bundles don't count as a notification - because we're not implementing a global rate limiter it could be possible to exceed the maximum system limit. For example, if all features post their maximum number of notifications and all the "one off" notifications are shown then we could potentially be above the limit. - this CL adds groups for spam and feedback notifications. Those notifications don't have a group summary so the UI is unchanged. To enforce all of the above, all notifications must now be posted using the DialerNotificationManager class. This is a thin wrapper around the system NotificationManager API. Using the system API directly is now forbidden. Bug: 62937258 Test: NotificationRateLimiterTest PiperOrigin-RevId: 165289368 Change-Id: I40e688bea3af40d829fd32d985cf04d22f7e384a
Diffstat (limited to 'java/com/android/dialer/app')
-rw-r--r--java/com/android/dialer/app/calllog/LegacyVoicemailNotifier.java9
-rw-r--r--java/com/android/dialer/app/calllog/MissedCallNotifier.java77
-rw-r--r--java/com/android/dialer/app/calllog/VisualVoicemailNotifier.java60
3 files changed, 51 insertions, 95 deletions
diff --git a/java/com/android/dialer/app/calllog/LegacyVoicemailNotifier.java b/java/com/android/dialer/app/calllog/LegacyVoicemailNotifier.java
index c64e03e4e..584f07fe3 100644
--- a/java/com/android/dialer/app/calllog/LegacyVoicemailNotifier.java
+++ b/java/com/android/dialer/app/calllog/LegacyVoicemailNotifier.java
@@ -18,7 +18,6 @@ package com.android.dialer.app.calllog;
import android.annotation.TargetApi;
import android.app.Notification;
-import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.os.Build.VERSION_CODES;
@@ -35,6 +34,7 @@ import com.android.dialer.app.R;
import com.android.dialer.calllogutils.PhoneAccountUtils;
import com.android.dialer.common.Assert;
import com.android.dialer.common.LogUtil;
+import com.android.dialer.notification.DialerNotificationManager;
import com.android.dialer.notification.NotificationChannelManager;
/** Shows a notification in the status bar for legacy vociemail. */
@@ -77,9 +77,7 @@ public final class LegacyVoicemailNotifier {
callVoicemailIntent,
voicemailSettingsIntent,
isRefresh);
- context
- .getSystemService(NotificationManager.class)
- .notify(NOTIFICATION_TAG, NOTIFICATION_ID, notification);
+ DialerNotificationManager.notify(context, NOTIFICATION_TAG, NOTIFICATION_ID, notification);
}
@NonNull
@@ -151,8 +149,7 @@ public final class LegacyVoicemailNotifier {
public static void cancelNotification(@NonNull Context context) {
LogUtil.enterBlock("LegacyVoicemailNotifier.cancelNotification");
Assert.checkArgument(BuildCompat.isAtLeastO());
- NotificationManager notificationManager = context.getSystemService(NotificationManager.class);
- notificationManager.cancel(NOTIFICATION_TAG, NOTIFICATION_ID);
+ DialerNotificationManager.cancel(context, NOTIFICATION_TAG, NOTIFICATION_ID);
}
private LegacyVoicemailNotifier() {}
diff --git a/java/com/android/dialer/app/calllog/MissedCallNotifier.java b/java/com/android/dialer/app/calllog/MissedCallNotifier.java
index e0e3fdf3f..b363b5ab6 100644
--- a/java/com/android/dialer/app/calllog/MissedCallNotifier.java
+++ b/java/com/android/dialer/app/calllog/MissedCallNotifier.java
@@ -17,7 +17,6 @@ package com.android.dialer.app.calllog;
import android.app.Notification;
import android.app.Notification.Builder;
-import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
@@ -48,7 +47,9 @@ import com.android.dialer.callintent.CallInitiationType;
import com.android.dialer.callintent.CallIntentBuilder;
import com.android.dialer.common.LogUtil;
import com.android.dialer.common.concurrent.DialerExecutor.Worker;
+import com.android.dialer.notification.DialerNotificationManager;
import com.android.dialer.notification.NotificationChannelId;
+import com.android.dialer.notification.NotificationManagerUtils;
import com.android.dialer.phonenumbercache.ContactInfo;
import com.android.dialer.phonenumberutil.PhoneNumberHelper;
import com.android.dialer.util.DialerUtils;
@@ -59,9 +60,17 @@ import java.util.Set;
/** Creates a notification for calls that the user missed (neither answered nor rejected). */
public class MissedCallNotifier implements Worker<Pair<Integer, String>, Void> {
- static final String NOTIFICATION_TAG_PREFIX = "MissedCall_";
- static final String NOTIFICATION_GROUP = "MissedCall";
+ /** Prefix used to generate a unique tag for each missed call notification. */
+ private static final String NOTIFICATION_TAG_PREFIX = "MissedCall_";
+ /** Common ID for all missed call notifications. */
private static final int NOTIFICATION_ID = 1;
+ /** Tag for the group summary notification. */
+ private static final String GROUP_SUMMARY_NOTIFICATION_TAG = "GroupSummary_MissedCall";
+ /**
+ * Key used to associate all missed call notifications and the summary as belonging to a single
+ * group.
+ */
+ private static final String GROUP_KEY = "MissedCallGroup";
private final Context context;
private final CallLogNotificationsQueryHelper callLogNotificationsQueryHelper;
@@ -202,33 +211,29 @@ public class MissedCallNotifier implements Worker<Pair<Integer, String>, Void> {
configureLedOnNotification(notification);
LogUtil.i("MissedCallNotifier.updateMissedCallNotification", "adding missed call notification");
- getNotificationMgr().notify(getNotificationTagForGroupSummary(), NOTIFICATION_ID, notification);
+ DialerNotificationManager.notify(
+ context, GROUP_SUMMARY_NOTIFICATION_TAG, NOTIFICATION_ID, notification);
if (useCallList) {
// Do not repost active notifications to prevent erasing post call notes.
- NotificationManager manager = getNotificationMgr();
Set<String> activeTags = new ArraySet<>();
- for (StatusBarNotification activeNotification : manager.getActiveNotifications()) {
+ for (StatusBarNotification activeNotification :
+ DialerNotificationManager.getActiveNotifications(context)) {
activeTags.add(activeNotification.getTag());
}
for (NewCall call : newCalls) {
String callTag = getNotificationTagForCall(call);
if (!activeTags.contains(callTag)) {
- manager.notify(callTag, NOTIFICATION_ID, getNotificationForCall(call, null));
+ DialerNotificationManager.notify(
+ context, callTag, NOTIFICATION_ID, getNotificationForCall(call, null));
}
}
}
}
public static void cancelAllMissedCallNotifications(@NonNull Context context) {
- NotificationManager notificationManager = context.getSystemService(NotificationManager.class);
- for (StatusBarNotification notification : notificationManager.getActiveNotifications()) {
- String tag = notification.getTag();
- if (tag != null && tag.startsWith(NOTIFICATION_TAG_PREFIX)) {
- notificationManager.cancel(tag, notification.getId());
- }
- }
+ NotificationManagerUtils.cancelAllInGroup(context, GROUP_KEY);
}
public static void cancelSingleMissedCallNotification(
@@ -239,31 +244,9 @@ public class MissedCallNotifier implements Worker<Pair<Integer, String>, Void> {
"unable to cancel notification, uri is null");
return;
}
- NotificationManager notificationManager = context.getSystemService(NotificationManager.class);
- String callTag = getNotificationTagForCallUri(callUri);
- String summaryTag = getNotificationTagForGroupSummary();
- int notificationCount = 0;
-
- for (StatusBarNotification notification : notificationManager.getActiveNotifications()) {
- String currentTag = notification.getTag();
- if (currentTag == null) {
- continue;
- }
- if (currentTag.equals(callTag)) {
- notificationManager.cancel(notification.getTag(), notification.getId());
- } else if (currentTag.startsWith(NOTIFICATION_TAG_PREFIX) && !currentTag.equals(summaryTag)) {
- notificationCount++;
- }
- }
-
- if (notificationCount == 0) {
- // There are no more missed call notifications. Remove the summary notification too.
- notificationManager.cancel(summaryTag, NOTIFICATION_ID);
- }
- }
-
- private static String getNotificationTagForGroupSummary() {
- return NOTIFICATION_TAG_PREFIX + "GroupSummary";
+ // This will also dismiss the group summary if there are no more missed call notifications.
+ DialerNotificationManager.cancel(
+ context, getNotificationTagForCallUri(callUri), NOTIFICATION_ID);
}
private static String getNotificationTagForCall(@NonNull NewCall call) {
@@ -280,11 +263,11 @@ public class MissedCallNotifier implements Worker<Pair<Integer, String>, Void> {
for (NewCall call : newCalls) {
if (call.number.equals(number.replace("tel:", ""))) {
// Update the first notification that matches our post call note sender.
- getNotificationMgr()
- .notify(
- getNotificationTagForCall(call),
- NOTIFICATION_ID,
- getNotificationForCall(call, note));
+ DialerNotificationManager.notify(
+ context,
+ getNotificationTagForCall(call),
+ NOTIFICATION_ID,
+ getNotificationForCall(call, note));
break;
}
}
@@ -366,7 +349,7 @@ public class MissedCallNotifier implements Worker<Pair<Integer, String>, Void> {
private Notification.Builder createNotificationBuilder() {
return new Notification.Builder(context)
- .setGroup(NOTIFICATION_GROUP)
+ .setGroup(GROUP_KEY)
.setSmallIcon(android.R.drawable.stat_notify_missed_call)
.setColor(context.getResources().getColor(R.color.dialer_theme_color, null))
.setAutoCancel(true)
@@ -466,8 +449,4 @@ public class MissedCallNotifier implements Worker<Pair<Integer, String>, Void> {
private void closeSystemDialogs(Context context) {
context.sendBroadcast(new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS));
}
-
- private NotificationManager getNotificationMgr() {
- return (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
- }
}
diff --git a/java/com/android/dialer/app/calllog/VisualVoicemailNotifier.java b/java/com/android/dialer/app/calllog/VisualVoicemailNotifier.java
index 99fe466d8..cbadfd317 100644
--- a/java/com/android/dialer/app/calllog/VisualVoicemailNotifier.java
+++ b/java/com/android/dialer/app/calllog/VisualVoicemailNotifier.java
@@ -17,7 +17,6 @@
package com.android.dialer.app.calllog;
import android.app.Notification;
-import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.ComponentName;
import android.content.Context;
@@ -26,7 +25,6 @@ import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Build.VERSION;
import android.os.Build.VERSION_CODES;
-import android.service.notification.StatusBarNotification;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.os.BuildCompat;
@@ -43,7 +41,9 @@ import com.android.dialer.app.list.DialtactsPagerAdapter;
import com.android.dialer.common.LogUtil;
import com.android.dialer.logging.DialerImpression;
import com.android.dialer.logging.Logger;
+import com.android.dialer.notification.DialerNotificationManager;
import com.android.dialer.notification.NotificationChannelManager;
+import com.android.dialer.notification.NotificationManagerUtils;
import com.android.dialer.phonenumbercache.ContactInfo;
import com.android.dialer.telecom.TelecomUtil;
import java.util.List;
@@ -51,9 +51,17 @@ import java.util.Map;
/** Shows a notification in the status bar for visual voicemail. */
final class VisualVoicemailNotifier {
+ /** Prefix used to generate a unique tag for each voicemail notification. */
private static final String NOTIFICATION_TAG_PREFIX = "VisualVoicemail_";
- private static final String NOTIFICATION_GROUP = "VisualVoicemail";
+ /** Common ID for all voicemail notifications. */
private static final int NOTIFICATION_ID = 1;
+ /** Tag for the group summary notification. */
+ private static final String GROUP_SUMMARY_NOTIFICATION_TAG = "GroupSummary_VisualVoicemail";
+ /**
+ * Key used to associate all voicemail notifications and the summary as belonging to a single
+ * group.
+ */
+ private static final String GROUP_KEY = "VisualVoicemailGroup";
public static void showNotifications(
@NonNull Context context,
@@ -82,12 +90,12 @@ final class VisualVoicemailNotifier {
groupSummary.setChannelId(NotificationChannelManager.getVoicemailChannelId(context, handle));
}
- NotificationManager notificationManager = context.getSystemService(NotificationManager.class);
- notificationManager.notify(
- getNotificationTagForGroupSummary(), NOTIFICATION_ID, groupSummary.build());
+ DialerNotificationManager.notify(
+ context, GROUP_SUMMARY_NOTIFICATION_TAG, NOTIFICATION_ID, groupSummary.build());
for (NewCall voicemail : newCalls) {
- notificationManager.notify(
+ DialerNotificationManager.notify(
+ context,
getNotificationTagForVoicemail(voicemail),
NOTIFICATION_ID,
createNotificationForVoicemail(context, voicemail, contactInfos));
@@ -96,13 +104,7 @@ final class VisualVoicemailNotifier {
public static void cancelAllVoicemailNotifications(@NonNull Context context) {
LogUtil.enterBlock("VisualVoicemailNotifier.cancelAllVoicemailNotifications");
- NotificationManager notificationManager = context.getSystemService(NotificationManager.class);
- for (StatusBarNotification notification : notificationManager.getActiveNotifications()) {
- String tag = notification.getTag();
- if (tag != null && tag.startsWith(NOTIFICATION_TAG_PREFIX)) {
- notificationManager.cancel(tag, notification.getId());
- }
- }
+ NotificationManagerUtils.cancelAllInGroup(context, GROUP_KEY);
}
public static void cancelSingleVoicemailNotification(
@@ -112,27 +114,9 @@ final class VisualVoicemailNotifier {
LogUtil.e("VisualVoicemailNotifier.cancelSingleVoicemailNotification", "uri is null");
return;
}
- NotificationManager notificationManager = context.getSystemService(NotificationManager.class);
- String voicemailTag = getNotificationTagForUri(voicemailUri);
- String summaryTag = getNotificationTagForGroupSummary();
- int notificationCount = 0;
-
- for (StatusBarNotification notification : notificationManager.getActiveNotifications()) {
- String currentTag = notification.getTag();
- if (currentTag == null) {
- continue;
- }
- if (currentTag.equals(voicemailTag)) {
- notificationManager.cancel(notification.getTag(), notification.getId());
- } else if (currentTag.startsWith(NOTIFICATION_TAG_PREFIX) && !currentTag.equals(summaryTag)) {
- notificationCount++;
- }
- }
-
- if (notificationCount == 0) {
- // There are no more visual voicemail notifications. Remove the summary notification too.
- notificationManager.cancel(summaryTag, NOTIFICATION_ID);
- }
+ // This will also dismiss the group summary if there are no more voicemail notifications.
+ DialerNotificationManager.cancel(
+ context, getNotificationTagForUri(voicemailUri), NOTIFICATION_ID);
}
private static String getNotificationTagForVoicemail(@NonNull NewCall voicemail) {
@@ -143,15 +127,11 @@ final class VisualVoicemailNotifier {
return NOTIFICATION_TAG_PREFIX + voicemailUri;
}
- private static String getNotificationTagForGroupSummary() {
- return NOTIFICATION_TAG_PREFIX + "GroupSummary";
- }
-
private static Notification.Builder createNotificationBuilder(@NonNull Context context) {
return new Notification.Builder(context)
.setSmallIcon(android.R.drawable.stat_notify_voicemail)
.setColor(context.getColor(R.color.dialer_theme_color))
- .setGroup(NOTIFICATION_GROUP)
+ .setGroup(GROUP_KEY)
.setOnlyAlertOnce(true)
.setAutoCancel(true);
}