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