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.

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

mercurial