Home | History | Annotate | Download | only in impl
      1 /* GENERATED SOURCE. DO NOT MODIFY. */
      2 //  2016 and later: Unicode, Inc. and others.
      3 // License & terms of use: http://www.unicode.org/copyright.html#License
      4 /**
      5  *******************************************************************************
      6  * Copyright (C) 2001-2009, International Business Machines Corporation and    *
      7  * others. All Rights Reserved.                                                *
      8  *******************************************************************************
      9  */
     10 package android.icu.impl;
     11 
     12 import java.util.ArrayList;
     13 import java.util.EventListener;
     14 import java.util.Iterator;
     15 import java.util.List;
     16 
     17 /**
     18  * <p>Abstract implementation of a notification facility.  Clients add
     19  * EventListeners with addListener and remove them with removeListener.
     20  * Notifiers call notifyChanged when they wish to notify listeners.
     21  * This queues the listener list on the notification thread, which
     22  * eventually dequeues the list and calls notifyListener on each
     23  * listener in the list.</p>
     24  *
     25  * <p>Subclasses override acceptsListener and notifyListener
     26  * to add type-safe notification.  AcceptsListener should return
     27  * true if the listener is of the appropriate type; ICUNotifier
     28  * itself will ensure the listener is non-null and that the
     29  * identical listener is not already registered with the Notifier.
     30  * NotifyListener should cast the listener to the appropriate
     31  * type and call the appropriate method on the listener.
     32  * @hide Only a subset of ICU is exposed in Android
     33  */
     34 public abstract class ICUNotifier {
     35     private final Object notifyLock = new Object();
     36     private NotifyThread notifyThread;
     37     private List<EventListener> listeners;
     38 
     39     /**
     40      * Add a listener to be notified when notifyChanged is called.
     41      * The listener must not be null. AcceptsListener must return
     42      * true for the listener.  Attempts to concurrently
     43      * register the identical listener more than once will be
     44      * silently ignored.
     45      */
     46     public void addListener(EventListener l) {
     47         if (l == null) {
     48             throw new NullPointerException();
     49         }
     50 
     51         if (acceptsListener(l)) {
     52             synchronized (notifyLock) {
     53                 if (listeners == null) {
     54                     listeners = new ArrayList<EventListener>();
     55                 } else {
     56                     // identity equality check
     57                     for (EventListener ll : listeners) {
     58                         if (ll == l) {
     59                             return;
     60                         }
     61                     }
     62                 }
     63 
     64                 listeners.add(l);
     65             }
     66         } else {
     67             throw new IllegalStateException("Listener invalid for this notifier.");
     68         }
     69     }
     70 
     71     /**
     72      * Stop notifying this listener.  The listener must
     73      * not be null.  Attempts to remove a listener that is
     74      * not registered will be silently ignored.
     75      */
     76     public void removeListener(EventListener l) {
     77         if (l == null) {
     78             throw new NullPointerException();
     79         }
     80         synchronized (notifyLock) {
     81             if (listeners != null) {
     82                 // identity equality check
     83                 Iterator<EventListener> iter = listeners.iterator();
     84                 while (iter.hasNext()) {
     85                     if (iter.next() == l) {
     86                         iter.remove();
     87                         if (listeners.size() == 0) {
     88                             listeners = null;
     89                         }
     90                         return;
     91                     }
     92                 }
     93             }
     94         }
     95     }
     96 
     97     /**
     98      * Queue a notification on the notification thread for the current
     99      * listeners.  When the thread unqueues the notification, notifyListener
    100      * is called on each listener from the notification thread.
    101      */
    102     public void notifyChanged() {
    103         synchronized (notifyLock) {
    104             if (listeners != null) {
    105                 if (notifyThread == null) {
    106                     notifyThread = new NotifyThread(this);
    107                     notifyThread.setDaemon(true);
    108                     notifyThread.start();
    109                 }
    110                 notifyThread.queue(listeners.toArray(new EventListener[listeners.size()]));
    111             }
    112         }
    113     }
    114 
    115     /**
    116      * The notification thread.
    117      */
    118     private static class NotifyThread extends Thread {
    119         private final ICUNotifier notifier;
    120         private final List<EventListener[]> queue = new ArrayList<EventListener[]>();
    121 
    122         NotifyThread(ICUNotifier notifier) {
    123             this.notifier = notifier;
    124         }
    125 
    126         /**
    127          * Queue the notification on the thread.
    128          */
    129         public void queue(EventListener[] list) {
    130             synchronized (this) {
    131                 queue.add(list);
    132                 notify();
    133             }
    134         }
    135 
    136         /**
    137          * Wait for a notification to be queued, then notify all
    138          * listeners listed in the notification.
    139          */
    140         @Override
    141         public void run() {
    142             EventListener[] list;
    143             while (true) {
    144                 try {
    145                     synchronized (this) {
    146                         while (queue.isEmpty()) {
    147                             wait();
    148                         }
    149                         list = queue.remove(0);
    150                     }
    151 
    152                     for (int i = 0; i < list.length; ++i) {
    153                         notifier.notifyListener(list[i]);
    154                     }
    155                 }
    156                 catch (InterruptedException e) {
    157                 }
    158             }
    159         }
    160     }
    161 
    162     /**
    163      * Subclasses implement this to return true if the listener is
    164      * of the appropriate type.
    165      */
    166     protected abstract boolean acceptsListener(EventListener l);
    167 
    168     /**
    169      * Subclasses implement this to notify the listener.
    170      */
    171     protected abstract void notifyListener(EventListener l);
    172 }
    173