mobile/android/base/NotificationClient.java

Wed, 31 Dec 2014 07:22:50 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 07:22:50 +0100
branch
TOR_BUG_3246
changeset 4
fc2d59ddac77
permissions
-rw-r--r--

Correct previous dual key logic pending first delivery installment.

michael@0 1 /* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*-
michael@0 2 * This Source Code Form is subject to the terms of the Mozilla Public
michael@0 3 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 5
michael@0 6 package org.mozilla.gecko;
michael@0 7
michael@0 8 import android.app.Notification;
michael@0 9 import android.app.PendingIntent;
michael@0 10 import android.text.TextUtils;
michael@0 11 import android.util.Log;
michael@0 12
michael@0 13 import java.util.LinkedList;
michael@0 14 import java.util.concurrent.ConcurrentHashMap;
michael@0 15
michael@0 16 /**
michael@0 17 * Client for posting notifications through a NotificationHandler.
michael@0 18 */
michael@0 19 public abstract class NotificationClient {
michael@0 20 private static final String LOGTAG = "GeckoNotificationClient";
michael@0 21
michael@0 22 private volatile NotificationHandler mHandler;
michael@0 23 private boolean mReady;
michael@0 24 private final LinkedList<Runnable> mTaskQueue = new LinkedList<Runnable>();
michael@0 25 private final ConcurrentHashMap<Integer, UpdateRunnable> mUpdatesMap =
michael@0 26 new ConcurrentHashMap<Integer, UpdateRunnable>();
michael@0 27
michael@0 28 /**
michael@0 29 * Runnable that is reused between update notifications.
michael@0 30 *
michael@0 31 * Updates happen frequently, so reusing Runnables prevents frequent dynamic allocation.
michael@0 32 */
michael@0 33 private class UpdateRunnable implements Runnable {
michael@0 34 private long mProgress;
michael@0 35 private long mProgressMax;
michael@0 36 private String mAlertText;
michael@0 37 final private int mNotificationID;
michael@0 38
michael@0 39 public UpdateRunnable(int notificationID) {
michael@0 40 mNotificationID = notificationID;
michael@0 41 }
michael@0 42
michael@0 43 public synchronized boolean updateProgress(long progress, long progressMax, String alertText) {
michael@0 44 if (progress == mProgress
michael@0 45 && mProgressMax == progressMax
michael@0 46 && TextUtils.equals(mAlertText, alertText)) {
michael@0 47 return false;
michael@0 48 }
michael@0 49
michael@0 50 mProgress = progress;
michael@0 51 mProgressMax = progressMax;
michael@0 52 mAlertText = alertText;
michael@0 53 return true;
michael@0 54 }
michael@0 55
michael@0 56 @Override
michael@0 57 public void run() {
michael@0 58 long progress;
michael@0 59 long progressMax;
michael@0 60 String alertText;
michael@0 61
michael@0 62 synchronized (this) {
michael@0 63 progress = mProgress;
michael@0 64 progressMax = mProgressMax;
michael@0 65 alertText = mAlertText;
michael@0 66 }
michael@0 67
michael@0 68 mHandler.update(mNotificationID, progress, progressMax, alertText);
michael@0 69 }
michael@0 70 };
michael@0 71
michael@0 72 /**
michael@0 73 * Adds a notification.
michael@0 74 *
michael@0 75 * @see NotificationHandler#add(int, String, String, String, PendingIntent, PendingIntent)
michael@0 76 */
michael@0 77 public synchronized void add(final int notificationID, final String aImageUrl,
michael@0 78 final String aAlertTitle, final String aAlertText, final PendingIntent contentIntent) {
michael@0 79 mTaskQueue.add(new Runnable() {
michael@0 80 @Override
michael@0 81 public void run() {
michael@0 82 mHandler.add(notificationID, aImageUrl, aAlertTitle, aAlertText, contentIntent);
michael@0 83 }
michael@0 84 });
michael@0 85 notify();
michael@0 86
michael@0 87 if (!mReady) {
michael@0 88 bind();
michael@0 89 }
michael@0 90 }
michael@0 91
michael@0 92 /**
michael@0 93 * Adds a notification.
michael@0 94 *
michael@0 95 * @see NotificationHandler#add(int, Notification)
michael@0 96 */
michael@0 97 public synchronized void add(final int notificationID, final Notification notification) {
michael@0 98 mTaskQueue.add(new Runnable() {
michael@0 99 @Override
michael@0 100 public void run() {
michael@0 101 mHandler.add(notificationID, notification);
michael@0 102 }
michael@0 103 });
michael@0 104 notify();
michael@0 105
michael@0 106 if (!mReady) {
michael@0 107 bind();
michael@0 108 }
michael@0 109 }
michael@0 110
michael@0 111 /**
michael@0 112 * Updates a notification.
michael@0 113 *
michael@0 114 * @see NotificationHandler#update(int, long, long, String)
michael@0 115 */
michael@0 116 public void update(final int notificationID, final long aProgress, final long aProgressMax,
michael@0 117 final String aAlertText) {
michael@0 118 UpdateRunnable runnable = mUpdatesMap.get(notificationID);
michael@0 119
michael@0 120 if (runnable == null) {
michael@0 121 runnable = new UpdateRunnable(notificationID);
michael@0 122 mUpdatesMap.put(notificationID, runnable);
michael@0 123 }
michael@0 124
michael@0 125 // If we've already posted an update with these values, there's no
michael@0 126 // need to do it again.
michael@0 127 if (!runnable.updateProgress(aProgress, aProgressMax, aAlertText)) {
michael@0 128 return;
michael@0 129 }
michael@0 130
michael@0 131 synchronized (this) {
michael@0 132 if (mReady) {
michael@0 133 mTaskQueue.add(runnable);
michael@0 134 notify();
michael@0 135 }
michael@0 136 }
michael@0 137 }
michael@0 138
michael@0 139 /**
michael@0 140 * Removes a notification.
michael@0 141 *
michael@0 142 * @see NotificationHandler#remove(int)
michael@0 143 */
michael@0 144 public synchronized void remove(final int notificationID) {
michael@0 145 if (!mReady) {
michael@0 146 return;
michael@0 147 }
michael@0 148
michael@0 149 mTaskQueue.add(new Runnable() {
michael@0 150 @Override
michael@0 151 public void run() {
michael@0 152 mHandler.remove(notificationID);
michael@0 153 mUpdatesMap.remove(notificationID);
michael@0 154 }
michael@0 155 });
michael@0 156 notify();
michael@0 157 }
michael@0 158
michael@0 159 /**
michael@0 160 * Determines whether a notification is showing progress.
michael@0 161 *
michael@0 162 * @see NotificationHandler#isProgressStyle(int)
michael@0 163 */
michael@0 164 public boolean isOngoing(int notificationID) {
michael@0 165 final NotificationHandler handler = mHandler;
michael@0 166 return handler != null && handler.isOngoing(notificationID);
michael@0 167 }
michael@0 168
michael@0 169 protected void bind() {
michael@0 170 mReady = true;
michael@0 171 }
michael@0 172
michael@0 173 protected void unbind() {
michael@0 174 mReady = false;
michael@0 175 mUpdatesMap.clear();
michael@0 176 }
michael@0 177
michael@0 178 protected void connectHandler(NotificationHandler handler) {
michael@0 179 mHandler = handler;
michael@0 180 new Thread(new NotificationRunnable()).start();
michael@0 181 }
michael@0 182
michael@0 183 private class NotificationRunnable implements Runnable {
michael@0 184 @Override
michael@0 185 public void run() {
michael@0 186 Runnable r;
michael@0 187 try {
michael@0 188 while (true) {
michael@0 189 // Synchronize polls to prevent tasks from being added to the queue
michael@0 190 // during the isDone check.
michael@0 191 synchronized (NotificationClient.this) {
michael@0 192 r = mTaskQueue.poll();
michael@0 193 while (r == null) {
michael@0 194 if (mHandler.isDone()) {
michael@0 195 unbind();
michael@0 196 return;
michael@0 197 }
michael@0 198 NotificationClient.this.wait();
michael@0 199 r = mTaskQueue.poll();
michael@0 200 }
michael@0 201 }
michael@0 202 r.run();
michael@0 203 }
michael@0 204 } catch (InterruptedException e) {
michael@0 205 Log.e(LOGTAG, "Notification task queue processing interrupted", e);
michael@0 206 }
michael@0 207 }
michael@0 208 }
michael@0 209 }

mercurial