3737 * @hide
3838*/
3939public abstract class UEventObserver {
40- private static final String TAG = UEventObserver .class .getSimpleName ();
40+ private static UEventThread sThread ;
41+
42+ private static native void native_setup ();
43+ private static native int next_event (byte [] buffer );
44+
45+ public UEventObserver () {
46+ }
47+
48+ protected void finalize () throws Throwable {
49+ try {
50+ stopObserving ();
51+ } finally {
52+ super .finalize ();
53+ }
54+ }
55+
56+ private static UEventThread getThread () {
57+ synchronized (UEventObserver .class ) {
58+ if (sThread == null ) {
59+ sThread = new UEventThread ();
60+ sThread .start ();
61+ }
62+ return sThread ;
63+ }
64+ }
65+
66+ private static UEventThread peekThread () {
67+ synchronized (UEventObserver .class ) {
68+ return sThread ;
69+ }
70+ }
71+
72+ /**
73+ * Begin observation of UEvent's.<p>
74+ * This method will cause the UEvent thread to start if this is the first
75+ * invocation of startObserving in this process.<p>
76+ * Once called, the UEvent thread will call onUEvent() when an incoming
77+ * UEvent matches the specified string.<p>
78+ * This method can be called multiple times to register multiple matches.
79+ * Only one call to stopObserving is required even with multiple registered
80+ * matches.
81+ * @param match A substring of the UEvent to match. Use "" to match all
82+ * UEvent's
83+ */
84+ public final void startObserving (String match ) {
85+ final UEventThread t = getThread ();
86+ t .addObserver (match , this );
87+ }
88+
89+ /**
90+ * End observation of UEvent's.<p>
91+ * This process's UEvent thread will never call onUEvent() on this
92+ * UEventObserver after this call. Repeated calls have no effect.
93+ */
94+ public final void stopObserving () {
95+ final UEventThread t = getThread ();
96+ if (t != null ) {
97+ t .removeObserver (this );
98+ }
99+ }
100+
101+ /**
102+ * Subclasses of UEventObserver should override this method to handle
103+ * UEvents.
104+ */
105+ public abstract void onUEvent (UEvent event );
41106
42107 /**
43108 * Representation of a UEvent.
44109 */
45- static public class UEvent {
110+ public static final class UEvent {
46111 // collection of key=value pairs parsed from the uevent message
47- public HashMap <String ,String > mMap = new HashMap <String ,String >();
112+ private final HashMap <String ,String > mMap = new HashMap <String ,String >();
48113
49114 public UEvent (String message ) {
50115 int offset = 0 ;
@@ -79,20 +144,20 @@ public String toString() {
79144 }
80145 }
81146
82- private static UEventThread sThread ;
83- private static boolean sThreadStarted = false ;
84-
85- private static class UEventThread extends Thread {
147+ private static final class UEventThread extends Thread {
86148 /** Many to many mapping of string match to observer.
87149 * Multimap would be better, but not available in android, so use
88150 * an ArrayList where even elements are the String match and odd
89151 * elements the corresponding UEventObserver observer */
90- private ArrayList <Object > mObservers = new ArrayList <Object >();
91-
92- UEventThread () {
152+ private final ArrayList <Object > mKeysAndObservers = new ArrayList <Object >();
153+
154+ private final ArrayList <UEventObserver > mTempObserversToSignal =
155+ new ArrayList <UEventObserver >();
156+
157+ public UEventThread () {
93158 super ("UEventObserver" );
94159 }
95-
160+
96161 public void run () {
97162 native_setup ();
98163
@@ -101,91 +166,54 @@ public void run() {
101166 while (true ) {
102167 len = next_event (buffer );
103168 if (len > 0 ) {
104- String bufferStr = new String (buffer , 0 , len ); // easier to search a String
105- synchronized (mObservers ) {
106- for (int i = 0 ; i < mObservers .size (); i += 2 ) {
107- if (bufferStr .indexOf ((String )mObservers .get (i )) != -1 ) {
108- ((UEventObserver )mObservers .get (i +1 ))
109- .onUEvent (new UEvent (bufferStr ));
110- }
111- }
169+ sendEvent (new String (buffer , 0 , len ));
170+ }
171+ }
172+ }
173+
174+ private void sendEvent (String message ) {
175+ synchronized (mKeysAndObservers ) {
176+ final int N = mKeysAndObservers .size ();
177+ for (int i = 0 ; i < N ; i += 2 ) {
178+ final String key = (String )mKeysAndObservers .get (i );
179+ if (message .indexOf (key ) != -1 ) {
180+ final UEventObserver observer =
181+ (UEventObserver )mKeysAndObservers .get (i + 1 );
182+ mTempObserversToSignal .add (observer );
112183 }
113184 }
114185 }
186+
187+ if (!mTempObserversToSignal .isEmpty ()) {
188+ final UEvent event = new UEvent (message );
189+ final int N = mTempObserversToSignal .size ();
190+ for (int i = 0 ; i < N ; i ++) {
191+ final UEventObserver observer = mTempObserversToSignal .get (i );
192+ observer .onUEvent (event );
193+ }
194+ mTempObserversToSignal .clear ();
195+ }
115196 }
197+
116198 public void addObserver (String match , UEventObserver observer ) {
117- synchronized ( mObservers ) {
118- mObservers .add (match );
119- mObservers .add (observer );
199+ synchronized ( mKeysAndObservers ) {
200+ mKeysAndObservers .add (match );
201+ mKeysAndObservers .add (observer );
120202 }
121203 }
204+
122205 /** Removes every key/value pair where value=observer from mObservers */
123206 public void removeObserver (UEventObserver observer ) {
124- synchronized (mObservers ) {
125- boolean found = true ;
126- while (found ) {
127- found = false ;
128- for (int i = 0 ; i < mObservers .size (); i += 2 ) {
129- if (mObservers .get (i +1 ) == observer ) {
130- mObservers .remove (i +1 );
131- mObservers .remove (i );
132- found = true ;
133- break ;
134- }
207+ synchronized (mKeysAndObservers ) {
208+ for (int i = 0 ; i < mKeysAndObservers .size (); ) {
209+ if (mKeysAndObservers .get (i + 1 ) == observer ) {
210+ mKeysAndObservers .remove (i + 1 );
211+ mKeysAndObservers .remove (i );
212+ } else {
213+ i += 2 ;
135214 }
136215 }
137216 }
138217 }
139218 }
140-
141- private static native void native_setup ();
142- private static native int next_event (byte [] buffer );
143-
144- private static final synchronized void ensureThreadStarted () {
145- if (sThreadStarted == false ) {
146- sThread = new UEventThread ();
147- sThread .start ();
148- sThreadStarted = true ;
149- }
150- }
151-
152- /**
153- * Begin observation of UEvent's.<p>
154- * This method will cause the UEvent thread to start if this is the first
155- * invocation of startObserving in this process.<p>
156- * Once called, the UEvent thread will call onUEvent() when an incoming
157- * UEvent matches the specified string.<p>
158- * This method can be called multiple times to register multiple matches.
159- * Only one call to stopObserving is required even with multiple registered
160- * matches.
161- * @param match A substring of the UEvent to match. Use "" to match all
162- * UEvent's
163- */
164- public final synchronized void startObserving (String match ) {
165- ensureThreadStarted ();
166- sThread .addObserver (match , this );
167- }
168-
169- /**
170- * End observation of UEvent's.<p>
171- * This process's UEvent thread will never call onUEvent() on this
172- * UEventObserver after this call. Repeated calls have no effect.
173- */
174- public final synchronized void stopObserving () {
175- sThread .removeObserver (this );
176- }
177-
178- /**
179- * Subclasses of UEventObserver should override this method to handle
180- * UEvents.
181- */
182- public abstract void onUEvent (UEvent event );
183-
184- protected void finalize () throws Throwable {
185- try {
186- stopObserving ();
187- } finally {
188- super .finalize ();
189- }
190- }
191219}
0 commit comments