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/**
257014b26c3e1429a6b841696ac7d84589158b0aafValter Strods * UEventObserver is an abstract class that receives UEvents 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 *
317014b26c3e1429a6b841696ac7d84589158b0aafValter Strods * Call stopObserving() to stop receiving UEvents.<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    /**
817014b26c3e1429a6b841696ac7d84589158b0aafValter Strods     * Begin observation of UEvents.<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    /**
1067014b26c3e1429a6b841696ac7d84589158b0aafValter Strods     * End observation of UEvents.<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