UEventObserver.java revision 9cf36b7a77bb8e821f9e593fdbb200f8a1742ff0
19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/* 29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2008 The Android Open Source Project 39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License"); 59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License. 69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at 79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0 99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software 119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, 129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and 149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License. 159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpackage android.os; 189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 199cf36b7a77bb8e821f9e593fdbb200f8a1742ff0Jeff Brownimport android.util.Log; 209cf36b7a77bb8e821f9e593fdbb200f8a1742ff0Jeff Brown 219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.ArrayList; 229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.HashMap; 239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/** 259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * UEventObserver is an abstract class that receives UEvent's from the kernel.<p> 269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Subclass UEventObserver, implementing onUEvent(UEvent event), then call 289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * startObserving() with a match string. The UEvent thread will then call your 299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * onUEvent() method when a UEvent occurs that contains your match string.<p> 309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Call stopObserving() to stop receiving UEvent's.<p> 329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * There is only one UEvent thread per process, even if that process has 349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * multiple UEventObserver subclass instances. The UEvent thread starts when 359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * the startObserving() is called for the first time in that process. Once 369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * started the UEvent thread will not stop (although it can stop notifying 379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * UEventObserver's via stopObserving()).<p> 389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @hide 409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project*/ 419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpublic abstract class UEventObserver { 429cf36b7a77bb8e821f9e593fdbb200f8a1742ff0Jeff Brown private static final String TAG = "UEventObserver"; 439cf36b7a77bb8e821f9e593fdbb200f8a1742ff0Jeff Brown private static final boolean DEBUG = false; 449cf36b7a77bb8e821f9e593fdbb200f8a1742ff0Jeff Brown 45008b1762a8d5c908281a832ff90817ade6c7f9f6Jeff Brown private static UEventThread sThread; 46008b1762a8d5c908281a832ff90817ade6c7f9f6Jeff Brown 479cf36b7a77bb8e821f9e593fdbb200f8a1742ff0Jeff Brown private static native void nativeSetup(); 489cf36b7a77bb8e821f9e593fdbb200f8a1742ff0Jeff Brown private static native String nativeWaitForNextEvent(); 499cf36b7a77bb8e821f9e593fdbb200f8a1742ff0Jeff Brown private static native void nativeAddMatch(String match); 509cf36b7a77bb8e821f9e593fdbb200f8a1742ff0Jeff Brown private static native void nativeRemoveMatch(String match); 51008b1762a8d5c908281a832ff90817ade6c7f9f6Jeff Brown 52008b1762a8d5c908281a832ff90817ade6c7f9f6Jeff Brown public UEventObserver() { 53008b1762a8d5c908281a832ff90817ade6c7f9f6Jeff Brown } 54008b1762a8d5c908281a832ff90817ade6c7f9f6Jeff Brown 559cf36b7a77bb8e821f9e593fdbb200f8a1742ff0Jeff Brown @Override 56008b1762a8d5c908281a832ff90817ade6c7f9f6Jeff Brown protected void finalize() throws Throwable { 57008b1762a8d5c908281a832ff90817ade6c7f9f6Jeff Brown try { 58008b1762a8d5c908281a832ff90817ade6c7f9f6Jeff Brown stopObserving(); 59008b1762a8d5c908281a832ff90817ade6c7f9f6Jeff Brown } finally { 60008b1762a8d5c908281a832ff90817ade6c7f9f6Jeff Brown super.finalize(); 61008b1762a8d5c908281a832ff90817ade6c7f9f6Jeff Brown } 62008b1762a8d5c908281a832ff90817ade6c7f9f6Jeff Brown } 63008b1762a8d5c908281a832ff90817ade6c7f9f6Jeff Brown 64008b1762a8d5c908281a832ff90817ade6c7f9f6Jeff Brown private static UEventThread getThread() { 65008b1762a8d5c908281a832ff90817ade6c7f9f6Jeff Brown synchronized (UEventObserver.class) { 66008b1762a8d5c908281a832ff90817ade6c7f9f6Jeff Brown if (sThread == null) { 67008b1762a8d5c908281a832ff90817ade6c7f9f6Jeff Brown sThread = new UEventThread(); 68008b1762a8d5c908281a832ff90817ade6c7f9f6Jeff Brown sThread.start(); 69008b1762a8d5c908281a832ff90817ade6c7f9f6Jeff Brown } 70008b1762a8d5c908281a832ff90817ade6c7f9f6Jeff Brown return sThread; 71008b1762a8d5c908281a832ff90817ade6c7f9f6Jeff Brown } 72008b1762a8d5c908281a832ff90817ade6c7f9f6Jeff Brown } 73008b1762a8d5c908281a832ff90817ade6c7f9f6Jeff Brown 74008b1762a8d5c908281a832ff90817ade6c7f9f6Jeff Brown private static UEventThread peekThread() { 75008b1762a8d5c908281a832ff90817ade6c7f9f6Jeff Brown synchronized (UEventObserver.class) { 76008b1762a8d5c908281a832ff90817ade6c7f9f6Jeff Brown return sThread; 77008b1762a8d5c908281a832ff90817ade6c7f9f6Jeff Brown } 78008b1762a8d5c908281a832ff90817ade6c7f9f6Jeff Brown } 79008b1762a8d5c908281a832ff90817ade6c7f9f6Jeff Brown 80008b1762a8d5c908281a832ff90817ade6c7f9f6Jeff Brown /** 81008b1762a8d5c908281a832ff90817ade6c7f9f6Jeff Brown * Begin observation of UEvent's.<p> 82008b1762a8d5c908281a832ff90817ade6c7f9f6Jeff Brown * This method will cause the UEvent thread to start if this is the first 83008b1762a8d5c908281a832ff90817ade6c7f9f6Jeff Brown * invocation of startObserving in this process.<p> 84008b1762a8d5c908281a832ff90817ade6c7f9f6Jeff Brown * Once called, the UEvent thread will call onUEvent() when an incoming 85008b1762a8d5c908281a832ff90817ade6c7f9f6Jeff Brown * UEvent matches the specified string.<p> 86008b1762a8d5c908281a832ff90817ade6c7f9f6Jeff Brown * This method can be called multiple times to register multiple matches. 87008b1762a8d5c908281a832ff90817ade6c7f9f6Jeff Brown * Only one call to stopObserving is required even with multiple registered 88008b1762a8d5c908281a832ff90817ade6c7f9f6Jeff Brown * matches. 899cf36b7a77bb8e821f9e593fdbb200f8a1742ff0Jeff Brown * 909cf36b7a77bb8e821f9e593fdbb200f8a1742ff0Jeff Brown * @param match A substring of the UEvent to match. Try to be as specific 919cf36b7a77bb8e821f9e593fdbb200f8a1742ff0Jeff Brown * as possible to avoid incurring unintended additional cost from processing 929cf36b7a77bb8e821f9e593fdbb200f8a1742ff0Jeff Brown * irrelevant messages. Netlink messages can be moderately high bandwidth and 939cf36b7a77bb8e821f9e593fdbb200f8a1742ff0Jeff Brown * are expensive to parse. For example, some devices may send one netlink message 949cf36b7a77bb8e821f9e593fdbb200f8a1742ff0Jeff Brown * for each vsync period. 95008b1762a8d5c908281a832ff90817ade6c7f9f6Jeff Brown */ 96008b1762a8d5c908281a832ff90817ade6c7f9f6Jeff Brown public final void startObserving(String match) { 979cf36b7a77bb8e821f9e593fdbb200f8a1742ff0Jeff Brown if (match == null || match.isEmpty()) { 989cf36b7a77bb8e821f9e593fdbb200f8a1742ff0Jeff Brown throw new IllegalArgumentException("match substring must be non-empty"); 999cf36b7a77bb8e821f9e593fdbb200f8a1742ff0Jeff Brown } 1009cf36b7a77bb8e821f9e593fdbb200f8a1742ff0Jeff Brown 101008b1762a8d5c908281a832ff90817ade6c7f9f6Jeff Brown final UEventThread t = getThread(); 102008b1762a8d5c908281a832ff90817ade6c7f9f6Jeff Brown t.addObserver(match, this); 103008b1762a8d5c908281a832ff90817ade6c7f9f6Jeff Brown } 104008b1762a8d5c908281a832ff90817ade6c7f9f6Jeff Brown 105008b1762a8d5c908281a832ff90817ade6c7f9f6Jeff Brown /** 106008b1762a8d5c908281a832ff90817ade6c7f9f6Jeff Brown * End observation of UEvent's.<p> 107008b1762a8d5c908281a832ff90817ade6c7f9f6Jeff Brown * This process's UEvent thread will never call onUEvent() on this 108008b1762a8d5c908281a832ff90817ade6c7f9f6Jeff Brown * UEventObserver after this call. Repeated calls have no effect. 109008b1762a8d5c908281a832ff90817ade6c7f9f6Jeff Brown */ 110008b1762a8d5c908281a832ff90817ade6c7f9f6Jeff Brown public final void stopObserving() { 111008b1762a8d5c908281a832ff90817ade6c7f9f6Jeff Brown final UEventThread t = getThread(); 112008b1762a8d5c908281a832ff90817ade6c7f9f6Jeff Brown if (t != null) { 113008b1762a8d5c908281a832ff90817ade6c7f9f6Jeff Brown t.removeObserver(this); 114008b1762a8d5c908281a832ff90817ade6c7f9f6Jeff Brown } 115008b1762a8d5c908281a832ff90817ade6c7f9f6Jeff Brown } 116008b1762a8d5c908281a832ff90817ade6c7f9f6Jeff Brown 117008b1762a8d5c908281a832ff90817ade6c7f9f6Jeff Brown /** 118008b1762a8d5c908281a832ff90817ade6c7f9f6Jeff Brown * Subclasses of UEventObserver should override this method to handle 119008b1762a8d5c908281a832ff90817ade6c7f9f6Jeff Brown * UEvents. 120008b1762a8d5c908281a832ff90817ade6c7f9f6Jeff Brown */ 121008b1762a8d5c908281a832ff90817ade6c7f9f6Jeff Brown public abstract void onUEvent(UEvent event); 1229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Representation of a UEvent. 1259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 126008b1762a8d5c908281a832ff90817ade6c7f9f6Jeff Brown public static final class UEvent { 1279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // collection of key=value pairs parsed from the uevent message 128008b1762a8d5c908281a832ff90817ade6c7f9f6Jeff Brown private final HashMap<String,String> mMap = new HashMap<String,String>(); 1299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public UEvent(String message) { 1319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int offset = 0; 1329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int length = message.length(); 1339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project while (offset < length) { 1359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int equals = message.indexOf('=', offset); 1369cf36b7a77bb8e821f9e593fdbb200f8a1742ff0Jeff Brown int at = message.indexOf('\0', offset); 1379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (at < 0) break; 1389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (equals > offset && equals < at) { 1409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // key is before the equals sign, and value is after 1419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMap.put(message.substring(offset, equals), 1429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project message.substring(equals + 1, at)); 1439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project offset = at + 1; 1469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public String get(String key) { 1509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mMap.get(key); 1519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public String get(String key, String defaultValue) { 1549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String result = mMap.get(key); 1559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return (result == null ? defaultValue : result); 1569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public String toString() { 1599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mMap.toString(); 1609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 163008b1762a8d5c908281a832ff90817ade6c7f9f6Jeff Brown private static final class UEventThread extends Thread { 1649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** Many to many mapping of string match to observer. 1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Multimap would be better, but not available in android, so use 1669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * an ArrayList where even elements are the String match and odd 1679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * elements the corresponding UEventObserver observer */ 168008b1762a8d5c908281a832ff90817ade6c7f9f6Jeff Brown private final ArrayList<Object> mKeysAndObservers = new ArrayList<Object>(); 169008b1762a8d5c908281a832ff90817ade6c7f9f6Jeff Brown 170008b1762a8d5c908281a832ff90817ade6c7f9f6Jeff Brown private final ArrayList<UEventObserver> mTempObserversToSignal = 171008b1762a8d5c908281a832ff90817ade6c7f9f6Jeff Brown new ArrayList<UEventObserver>(); 172008b1762a8d5c908281a832ff90817ade6c7f9f6Jeff Brown 173008b1762a8d5c908281a832ff90817ade6c7f9f6Jeff Brown public UEventThread() { 1749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project super("UEventObserver"); 1759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 176008b1762a8d5c908281a832ff90817ade6c7f9f6Jeff Brown 1779cf36b7a77bb8e821f9e593fdbb200f8a1742ff0Jeff Brown @Override 1789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void run() { 1799cf36b7a77bb8e821f9e593fdbb200f8a1742ff0Jeff Brown nativeSetup(); 1809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project while (true) { 1829cf36b7a77bb8e821f9e593fdbb200f8a1742ff0Jeff Brown String message = nativeWaitForNextEvent(); 1839cf36b7a77bb8e821f9e593fdbb200f8a1742ff0Jeff Brown if (message != null) { 1849cf36b7a77bb8e821f9e593fdbb200f8a1742ff0Jeff Brown if (DEBUG) { 1859cf36b7a77bb8e821f9e593fdbb200f8a1742ff0Jeff Brown Log.d(TAG, message); 1869cf36b7a77bb8e821f9e593fdbb200f8a1742ff0Jeff Brown } 1879cf36b7a77bb8e821f9e593fdbb200f8a1742ff0Jeff Brown sendEvent(message); 188008b1762a8d5c908281a832ff90817ade6c7f9f6Jeff Brown } 189008b1762a8d5c908281a832ff90817ade6c7f9f6Jeff Brown } 190008b1762a8d5c908281a832ff90817ade6c7f9f6Jeff Brown } 191008b1762a8d5c908281a832ff90817ade6c7f9f6Jeff Brown 192008b1762a8d5c908281a832ff90817ade6c7f9f6Jeff Brown private void sendEvent(String message) { 193008b1762a8d5c908281a832ff90817ade6c7f9f6Jeff Brown synchronized (mKeysAndObservers) { 194008b1762a8d5c908281a832ff90817ade6c7f9f6Jeff Brown final int N = mKeysAndObservers.size(); 195008b1762a8d5c908281a832ff90817ade6c7f9f6Jeff Brown for (int i = 0; i < N; i += 2) { 196008b1762a8d5c908281a832ff90817ade6c7f9f6Jeff Brown final String key = (String)mKeysAndObservers.get(i); 1979cf36b7a77bb8e821f9e593fdbb200f8a1742ff0Jeff Brown if (message.contains(key)) { 198008b1762a8d5c908281a832ff90817ade6c7f9f6Jeff Brown final UEventObserver observer = 199008b1762a8d5c908281a832ff90817ade6c7f9f6Jeff Brown (UEventObserver)mKeysAndObservers.get(i + 1); 200008b1762a8d5c908281a832ff90817ade6c7f9f6Jeff Brown mTempObserversToSignal.add(observer); 2019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 204008b1762a8d5c908281a832ff90817ade6c7f9f6Jeff Brown 205008b1762a8d5c908281a832ff90817ade6c7f9f6Jeff Brown if (!mTempObserversToSignal.isEmpty()) { 206008b1762a8d5c908281a832ff90817ade6c7f9f6Jeff Brown final UEvent event = new UEvent(message); 207008b1762a8d5c908281a832ff90817ade6c7f9f6Jeff Brown final int N = mTempObserversToSignal.size(); 208008b1762a8d5c908281a832ff90817ade6c7f9f6Jeff Brown for (int i = 0; i < N; i++) { 209008b1762a8d5c908281a832ff90817ade6c7f9f6Jeff Brown final UEventObserver observer = mTempObserversToSignal.get(i); 210008b1762a8d5c908281a832ff90817ade6c7f9f6Jeff Brown observer.onUEvent(event); 211008b1762a8d5c908281a832ff90817ade6c7f9f6Jeff Brown } 212008b1762a8d5c908281a832ff90817ade6c7f9f6Jeff Brown mTempObserversToSignal.clear(); 213008b1762a8d5c908281a832ff90817ade6c7f9f6Jeff Brown } 2149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 215008b1762a8d5c908281a832ff90817ade6c7f9f6Jeff Brown 2169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void addObserver(String match, UEventObserver observer) { 217008b1762a8d5c908281a832ff90817ade6c7f9f6Jeff Brown synchronized (mKeysAndObservers) { 218008b1762a8d5c908281a832ff90817ade6c7f9f6Jeff Brown mKeysAndObservers.add(match); 219008b1762a8d5c908281a832ff90817ade6c7f9f6Jeff Brown mKeysAndObservers.add(observer); 2209cf36b7a77bb8e821f9e593fdbb200f8a1742ff0Jeff Brown nativeAddMatch(match); 2219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 223008b1762a8d5c908281a832ff90817ade6c7f9f6Jeff Brown 2249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** Removes every key/value pair where value=observer from mObservers */ 2259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void removeObserver(UEventObserver observer) { 226008b1762a8d5c908281a832ff90817ade6c7f9f6Jeff Brown synchronized (mKeysAndObservers) { 227008b1762a8d5c908281a832ff90817ade6c7f9f6Jeff Brown for (int i = 0; i < mKeysAndObservers.size(); ) { 228008b1762a8d5c908281a832ff90817ade6c7f9f6Jeff Brown if (mKeysAndObservers.get(i + 1) == observer) { 229008b1762a8d5c908281a832ff90817ade6c7f9f6Jeff Brown mKeysAndObservers.remove(i + 1); 2309cf36b7a77bb8e821f9e593fdbb200f8a1742ff0Jeff Brown final String match = (String)mKeysAndObservers.remove(i); 2319cf36b7a77bb8e821f9e593fdbb200f8a1742ff0Jeff Brown nativeRemoveMatch(match); 232008b1762a8d5c908281a832ff90817ade6c7f9f6Jeff Brown } else { 233008b1762a8d5c908281a832ff90817ade6c7f9f6Jeff Brown i += 2; 2349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 240