summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDanny Baumann <dannybaumann@web.de>2016-01-15 12:21:47 +0100
committerDanny Baumann <dannybaumann@web.de>2016-01-20 23:32:40 -0800
commita29e6b2215fcab6024345e156d30ea1a931120d3 (patch)
tree3d197087f0fd4d853fb53f2e8f8121f9356cb0a7
parent34fb128e4325f764267c54629c4ee563e08aa6c7 (diff)
downloadandroid_packages_apps_Email-a29e6b2215fcab6024345e156d30ea1a931120d3.tar.gz
android_packages_apps_Email-a29e6b2215fcab6024345e156d30ea1a931120d3.tar.bz2
android_packages_apps_Email-a29e6b2215fcab6024345e156d30ea1a931120d3.zip
Improve notification coalescence algorithm.
Instead of coalescing for 15 seconds after the first change notification, coalesce until change notifications have been idle for at least 2 seconds. This avoids long update delays, which is especially jarring when using notifications on a wearable and the initial notification didn't yet include the message body. Also skip coalescence entirely for deletions; update immediately in that case. Change-Id: I67bed9a1af7b023020b0fd5429495eb45000e858
-rw-r--r--src/com/android/email/EmailNotificationController.java101
1 files changed, 55 insertions, 46 deletions
diff --git a/src/com/android/email/EmailNotificationController.java b/src/com/android/email/EmailNotificationController.java
index e57b41833..2d22776d8 100644
--- a/src/com/android/email/EmailNotificationController.java
+++ b/src/com/android/email/EmailNotificationController.java
@@ -56,6 +56,7 @@ import com.android.mail.utils.NotificationUtils;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -213,9 +214,7 @@ public class EmailNotificationController implements NotificationController {
*/
private static final int NOTIFICATION_DELAYED_MESSAGE = 0;
- private static final long NOTIFICATION_DELAY = 15 * DateUtils.SECOND_IN_MILLIS;
- // True if we're coalescing notification updates
- private static boolean sNotificationDelayedMessagePending;
+ private static final long NOTIFICATION_DELAY = 2 * DateUtils.SECOND_IN_MILLIS;
// True if accounts have changed and we need to refresh everything
private static boolean sRefreshAllNeeded;
// Set of accounts we need to regenerate notifications for
@@ -228,28 +227,30 @@ public class EmailNotificationController implements NotificationController {
sNotificationThread = new NotificationThread();
sNotificationHandler = new Handler(sNotificationThread.getLooper(),
new Handler.Callback() {
- @Override
- public boolean handleMessage(final android.os.Message message) {
- /**
- * To reduce spamming the notifications, we quiesce updates for a few
- * seconds to batch them up, then handle them here.
- */
- LogUtils.d(LOG_TAG, "Delayed notification processing");
- synchronized (sNotificationDelayedMessageLock) {
- sNotificationDelayedMessagePending = false;
- final Context context = (Context)message.obj;
- if (sRefreshAllNeeded) {
- sRefreshAllNeeded = false;
- refreshAllNotificationsInternal(context);
- }
+ @Override
+ public boolean handleMessage(final android.os.Message message) {
+ /**
+ * To reduce spamming the notifications, we quiesce updates for a few
+ * seconds to batch them up, then handle them here.
+ */
+ if (message.arg1 != 0) {
+ LogUtils.d(LOG_TAG, "Delayed notification processing");
+ synchronized (sNotificationDelayedMessageLock) {
+ final Context context = (Context)message.obj;
+ if (sRefreshAllNeeded) {
+ sRefreshAllNeeded = false;
+ refreshAllNotificationsInternal(context);
+ } else {
for (final Long accountId : sRefreshAccountSet) {
refreshNotificationsForAccountInternal(context, accountId);
}
- sRefreshAccountSet.clear();
}
- return true;
+ sRefreshAccountSet.clear();
}
- });
+ }
+ return true;
+ }
+ });
}
}
@@ -590,19 +591,32 @@ public class EmailNotificationController implements NotificationController {
notificationManager.cancel((int) (NOTIFICATION_ID_BASE_SECURITY_CHANGED + account.mId));
}
+ private static void scheduleNotificationUpdateLocked(final Context context,
+ boolean immediate) {
+ ensureHandlerExists();
+ android.os.Message msg = android.os.Message.obtain(sNotificationHandler,
+ NOTIFICATION_DELAYED_MESSAGE, 1, 0, context);
+ boolean isInDelayWindow = sNotificationHandler.hasMessages(NOTIFICATION_DELAYED_MESSAGE);
+
+ sNotificationHandler.removeMessages(NOTIFICATION_DELAYED_MESSAGE);
+ if (!immediate && isInDelayWindow) {
+ // we're in the delay window, restart timer
+ sNotificationHandler.sendMessageDelayed(msg, NOTIFICATION_DELAY);
+ } else {
+ // no refreshes happened in the last delay window; refresh immediately
+ // and send a dummy message to ensure the delay window is respected
+ // when the next update comes in
+ sNotificationHandler.sendMessage(msg);
+ sNotificationHandler.sendEmptyMessageDelayed(NOTIFICATION_DELAYED_MESSAGE,
+ NOTIFICATION_DELAY);
+ }
+ }
+
private static void refreshNotificationsForAccount(final Context context,
- final long accountId) {
+ final long accountId, boolean immediate) {
synchronized (sNotificationDelayedMessageLock) {
- if (sNotificationDelayedMessagePending) {
- sRefreshAccountSet.add(accountId);
- } else {
- ensureHandlerExists();
- sNotificationHandler.sendMessageDelayed(
- android.os.Message.obtain(sNotificationHandler,
- NOTIFICATION_DELAYED_MESSAGE, context), NOTIFICATION_DELAY);
- sNotificationDelayedMessagePending = true;
- refreshNotificationsForAccountInternal(context, accountId);
- }
+ sRefreshAccountSet.add(accountId);
+ scheduleNotificationUpdateLocked(context, immediate);
}
}
@@ -722,18 +736,10 @@ public class EmailNotificationController implements NotificationController {
account, folder, true /* getAttention */);
}
- private static void refreshAllNotifications(final Context context) {
+ private static void refreshAllNotifications(final Context context, boolean immediate) {
synchronized (sNotificationDelayedMessageLock) {
- if (sNotificationDelayedMessagePending) {
- sRefreshAllNeeded = true;
- } else {
- ensureHandlerExists();
- sNotificationHandler.sendMessageDelayed(
- android.os.Message.obtain(sNotificationHandler,
- NOTIFICATION_DELAYED_MESSAGE, context), NOTIFICATION_DELAY);
- sNotificationDelayedMessagePending = true;
- refreshAllNotificationsInternal(context);
- }
+ sRefreshAllNeeded = true;
+ scheduleNotificationUpdateLocked(context, immediate);
}
}
@@ -757,8 +763,11 @@ public class EmailNotificationController implements NotificationController {
}
@Override
- public void onChange(final boolean selfChange) {
- refreshNotificationsForAccount(mContext, mAccountId);
+ public void onChange(final boolean selfChange, Uri uri) {
+ List<String> segments = uri != null ? uri.getPathSegments() : null;
+ boolean isDelete = segments != null && segments.size() >= 2
+ ? EmailProvider.NOTIFICATION_OP_DELETE.equals(segments.get(1)) : false;
+ refreshNotificationsForAccount(mContext, mAccountId, isDelete);
}
}
@@ -774,7 +783,7 @@ public class EmailNotificationController implements NotificationController {
}
@Override
- public void onChange(final boolean selfChange) {
+ public void onChange(final boolean selfChange, Uri uri) {
final ContentResolver resolver = mContext.getContentResolver();
final Cursor c = resolver.query(Account.CONTENT_URI, EmailContent.ID_PROJECTION,
null, null, null);
@@ -811,7 +820,7 @@ public class EmailNotificationController implements NotificationController {
sInstance.unregisterMessageNotification(accountId);
}
- refreshAllNotifications(mContext);
+ refreshAllNotifications(mContext, !removedAccountList.isEmpty());
}
}