RemoteCallbackList.java revision ef4351cc72abeeba0f659950c199a4f9b7cd1842
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 19390517be2d60dd6e6264150c190c372d89bb331aDianne Hackbornimport android.util.ArrayMap; 20390517be2d60dd6e6264150c190c372d89bb331aDianne Hackborn 21ef4351cc72abeeba0f659950c199a4f9b7cd1842Eugene Suslaimport java.util.function.Consumer; 22ef4351cc72abeeba0f659950c199a4f9b7cd1842Eugene Susla 239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/** 249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Takes care of the grunt work of maintaining a list of remote interfaces, 259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * typically for the use of performing callbacks from a 269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * {@link android.app.Service} to its clients. In particular, this: 277b0b1ed979aa665175bf3952c8902ce13c763ab8The Android Open Source Project * 289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <ul> 299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <li> Keeps track of a set of registered {@link IInterface} callbacks, 309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * taking care to identify them through their underlying unique {@link IBinder} 319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * (by calling {@link IInterface#asBinder IInterface.asBinder()}. 329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <li> Attaches a {@link IBinder.DeathRecipient IBinder.DeathRecipient} to 339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * each registered interface, so that it can be cleaned out of the list if its 349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * process goes away. 359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <li> Performs locking of the underlying list of interfaces to deal with 369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * multithreaded incoming calls, and a thread-safe way to iterate over a 379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * snapshot of the list without holding its lock. 389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * </ul> 397b0b1ed979aa665175bf3952c8902ce13c763ab8The Android Open Source Project * 409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <p>To use this class, simply create a single instance along with your 419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * service, and call its {@link #register} and {@link #unregister} methods 429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * as client register and unregister with your service. To call back on to 439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * the registered clients, use {@link #beginBroadcast}, 449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * {@link #getBroadcastItem}, and {@link #finishBroadcast}. 457b0b1ed979aa665175bf3952c8902ce13c763ab8The Android Open Source Project * 469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <p>If a registered callback's process goes away, this class will take 479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * care of automatically removing it from the list. If you want to do 489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * additional work in this situation, you can create a subclass that 499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * implements the {@link #onCallbackDied} method. 509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpublic class RemoteCallbackList<E extends IInterface> { 52390517be2d60dd6e6264150c190c372d89bb331aDianne Hackborn /*package*/ ArrayMap<IBinder, Callback> mCallbacks 53390517be2d60dd6e6264150c190c372d89bb331aDianne Hackborn = new ArrayMap<IBinder, Callback>(); 54231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn private Object[] mActiveBroadcast; 55b06ea706530e6d19eb2a1a9a7ae6c5dd77d80af0Dianne Hackborn private int mBroadcastCount = -1; 569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private boolean mKilled = false; 577b0b1ed979aa665175bf3952c8902ce13c763ab8The Android Open Source Project 589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private final class Callback implements IBinder.DeathRecipient { 599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final E mCallback; 60231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn final Object mCookie; 619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 62231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn Callback(E callback, Object cookie) { 639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mCallback = callback; 64231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn mCookie = cookie; 659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 667b0b1ed979aa665175bf3952c8902ce13c763ab8The Android Open Source Project 679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void binderDied() { 689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project synchronized (mCallbacks) { 699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mCallbacks.remove(mCallback.asBinder()); 709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 71231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn onCallbackDied(mCallback, mCookie); 729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 747b0b1ed979aa665175bf3952c8902ce13c763ab8The Android Open Source Project 759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 76231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn * Simple version of {@link RemoteCallbackList#register(E, Object)} 77231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn * that does not take a cookie object. 78231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn */ 79231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn public boolean register(E callback) { 80231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn return register(callback, null); 81231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn } 825614bf5a1ae4522dfc1a041f003cebc9b25c8b93Dianne Hackborn 83231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn /** 849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Add a new callback to the list. This callback will remain in the list 859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * until a corresponding call to {@link #unregister} or its hosting process 869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * goes away. If the callback was already registered (determined by 879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * checking to see if the {@link IInterface#asBinder callback.asBinder()} 889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * object is already in the list), then it will be left as-is. 899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Registrations are not counted; a single call to {@link #unregister} 909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * will remove a callback after any number calls to register it. 917b0b1ed979aa665175bf3952c8902ce13c763ab8The Android Open Source Project * 929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param callback The callback interface to be added to the list. Must 939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * not be null -- passing null here will cause a NullPointerException. 949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Most services will want to check for null before calling this with 959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * an object given from a client, so that clients can't crash the 969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * service with bad data. 977b0b1ed979aa665175bf3952c8902ce13c763ab8The Android Open Source Project * 98231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn * @param cookie Optional additional data to be associated with this 99231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn * callback. 1009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 1019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return Returns true if the callback was successfully added to the list. 1029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Returns false if it was not added, either because {@link #kill} had 1039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * previously been called or the callback's process has gone away. 1047b0b1ed979aa665175bf3952c8902ce13c763ab8The Android Open Source Project * 1059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @see #unregister 1069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @see #kill 1079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @see #onCallbackDied 1089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 109231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn public boolean register(E callback, Object cookie) { 1109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project synchronized (mCallbacks) { 1119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mKilled) { 1129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 1139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project IBinder binder = callback.asBinder(); 1159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 116231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn Callback cb = new Callback(callback, cookie); 1179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project binder.linkToDeath(cb, 0); 1189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mCallbacks.put(binder, cb); 1199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return true; 1209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (RemoteException e) { 1219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 1229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1257b0b1ed979aa665175bf3952c8902ce13c763ab8The Android Open Source Project 1269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Remove from the list a callback that was previously added with 1289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * {@link #register}. This uses the 1299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * {@link IInterface#asBinder callback.asBinder()} object to correctly 1309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * find the previous registration. 1319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Registrations are not counted; a single unregister call will remove 1329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * a callback after any number calls to {@link #register} for it. 1337b0b1ed979aa665175bf3952c8902ce13c763ab8The Android Open Source Project * 1349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param callback The callback to be removed from the list. Passing 1359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * null here will cause a NullPointerException, so you will generally want 1369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * to check for null before calling. 1377b0b1ed979aa665175bf3952c8902ce13c763ab8The Android Open Source Project * 1389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return Returns true if the callback was found and unregistered. Returns 1399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * false if the given callback was not found on the list. 1407b0b1ed979aa665175bf3952c8902ce13c763ab8The Android Open Source Project * 1419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @see #register 1429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public boolean unregister(E callback) { 1449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project synchronized (mCallbacks) { 1459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Callback cb = mCallbacks.remove(callback.asBinder()); 1469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (cb != null) { 1479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project cb.mCallback.asBinder().unlinkToDeath(cb, 0); 1489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return true; 1499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 1519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1537b0b1ed979aa665175bf3952c8902ce13c763ab8The Android Open Source Project 1549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Disable this callback list. All registered callbacks are unregistered, 1569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * and the list is disabled so that future calls to {@link #register} will 1579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * fail. This should be used when a Service is stopping, to prevent clients 1589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * from registering callbacks after it is stopped. 1597b0b1ed979aa665175bf3952c8902ce13c763ab8The Android Open Source Project * 1609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @see #register 1619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void kill() { 1639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project synchronized (mCallbacks) { 164390517be2d60dd6e6264150c190c372d89bb331aDianne Hackborn for (int cbi=mCallbacks.size()-1; cbi>=0; cbi--) { 165390517be2d60dd6e6264150c190c372d89bb331aDianne Hackborn Callback cb = mCallbacks.valueAt(cbi); 1669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project cb.mCallback.asBinder().unlinkToDeath(cb, 0); 1679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mCallbacks.clear(); 1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mKilled = true; 1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1727b0b1ed979aa665175bf3952c8902ce13c763ab8The Android Open Source Project 1739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 174231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn * Old version of {@link #onCallbackDied(E, Object)} that 175231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn * does not provide a cookie. 176231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn */ 177231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn public void onCallbackDied(E callback) { 178231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn } 179231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn 180231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn /** 1819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Called when the process hosting a callback in the list has gone away. 182231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn * The default implementation calls {@link #onCallbackDied(E)} 183231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn * for backwards compatibility. 1849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 1859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param callback The callback whose process has died. Note that, since 1869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * its process has died, you can not make any calls on to this interface. 1879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You can, however, retrieve its IBinder and compare it with another 1889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * IBinder to see if it is the same object. 189231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn * @param cookie The cookie object original provided to 190231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn * {@link #register(E, Object)}. 1919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 1929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @see #register 1939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 194231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn public void onCallbackDied(E callback, Object cookie) { 195231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn onCallbackDied(callback); 1969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1977b0b1ed979aa665175bf3952c8902ce13c763ab8The Android Open Source Project 1989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Prepare to start making calls to the currently registered callbacks. 2009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * This creates a copy of the callback list, which you can retrieve items 2019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * from using {@link #getBroadcastItem}. Note that only one broadcast can 2029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * be active at a time, so you must be sure to always call this from the 203b06ea706530e6d19eb2a1a9a7ae6c5dd77d80af0Dianne Hackborn * same thread (usually by scheduling with {@link Handler}) or 2049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * do your own synchronization. You must call {@link #finishBroadcast} 2059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * when done. 2067b0b1ed979aa665175bf3952c8902ce13c763ab8The Android Open Source Project * 2079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <p>A typical loop delivering a broadcast looks like this: 2087b0b1ed979aa665175bf3952c8902ce13c763ab8The Android Open Source Project * 2099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <pre> 210b06ea706530e6d19eb2a1a9a7ae6c5dd77d80af0Dianne Hackborn * int i = callbacks.beginBroadcast(); 211dace230043314d6fab1c5ced4b031eaccd814c25Dianne Hackborn * while (i > 0) { 212b06ea706530e6d19eb2a1a9a7ae6c5dd77d80af0Dianne Hackborn * i--; 2139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * try { 2149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * callbacks.getBroadcastItem(i).somethingHappened(); 2159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * } catch (RemoteException e) { 2169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * // The RemoteCallbackList will take care of removing 2179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * // the dead object for us. 2189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * } 2199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * } 2209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * callbacks.finishBroadcast();</pre> 2217b0b1ed979aa665175bf3952c8902ce13c763ab8The Android Open Source Project * 2229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return Returns the number of callbacks in the broadcast, to be used 2239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * with {@link #getBroadcastItem} to determine the range of indices you 2249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * can supply. 2257b0b1ed979aa665175bf3952c8902ce13c763ab8The Android Open Source Project * 2269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @see #getBroadcastItem 2279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @see #finishBroadcast 2289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 2299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int beginBroadcast() { 2309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project synchronized (mCallbacks) { 231b06ea706530e6d19eb2a1a9a7ae6c5dd77d80af0Dianne Hackborn if (mBroadcastCount > 0) { 232b06ea706530e6d19eb2a1a9a7ae6c5dd77d80af0Dianne Hackborn throw new IllegalStateException( 233b06ea706530e6d19eb2a1a9a7ae6c5dd77d80af0Dianne Hackborn "beginBroadcast() called while already in a broadcast"); 234b06ea706530e6d19eb2a1a9a7ae6c5dd77d80af0Dianne Hackborn } 235b06ea706530e6d19eb2a1a9a7ae6c5dd77d80af0Dianne Hackborn 236b06ea706530e6d19eb2a1a9a7ae6c5dd77d80af0Dianne Hackborn final int N = mBroadcastCount = mCallbacks.size(); 2379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (N <= 0) { 2389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return 0; 2399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 240231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn Object[] active = mActiveBroadcast; 2419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (active == null || active.length < N) { 242231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn mActiveBroadcast = active = new Object[N]; 2439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 244390517be2d60dd6e6264150c190c372d89bb331aDianne Hackborn for (int i=0; i<N; i++) { 245390517be2d60dd6e6264150c190c372d89bb331aDianne Hackborn active[i] = mCallbacks.valueAt(i); 2469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 247390517be2d60dd6e6264150c190c372d89bb331aDianne Hackborn return N; 2489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2507b0b1ed979aa665175bf3952c8902ce13c763ab8The Android Open Source Project 2519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 2529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Retrieve an item in the active broadcast that was previously started 2539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * with {@link #beginBroadcast}. This can <em>only</em> be called after 2549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * the broadcast is started, and its data is no longer valid after 2559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * calling {@link #finishBroadcast}. 2567b0b1ed979aa665175bf3952c8902ce13c763ab8The Android Open Source Project * 2579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <p>Note that it is possible for the process of one of the returned 2589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * callbacks to go away before you call it, so you will need to catch 2599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * {@link RemoteException} when calling on to the returned object. 2609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * The callback list itself, however, will take care of unregistering 2619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * these objects once it detects that it is no longer valid, so you can 2629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * handle such an exception by simply ignoring it. 2637b0b1ed979aa665175bf3952c8902ce13c763ab8The Android Open Source Project * 2649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param index Which of the registered callbacks you would like to 2659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * retrieve. Ranges from 0 to 1-{@link #beginBroadcast}. 2667b0b1ed979aa665175bf3952c8902ce13c763ab8The Android Open Source Project * 2679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return Returns the callback interface that you can call. This will 2689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * always be non-null. 2697b0b1ed979aa665175bf3952c8902ce13c763ab8The Android Open Source Project * 2709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @see #beginBroadcast 2719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 2729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public E getBroadcastItem(int index) { 273231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn return ((Callback)mActiveBroadcast[index]).mCallback; 274231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn } 275231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn 276231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn /** 277231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn * Retrieve the cookie associated with the item 278231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn * returned by {@link #getBroadcastItem(int)}. 279231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn * 280231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn * @see #getBroadcastItem 281231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn */ 282231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn public Object getBroadcastCookie(int index) { 283231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn return ((Callback)mActiveBroadcast[index]).mCookie; 2849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2857b0b1ed979aa665175bf3952c8902ce13c763ab8The Android Open Source Project 2869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 2879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Clean up the state of a broadcast previously initiated by calling 2889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * {@link #beginBroadcast}. This must always be called when you are done 2899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * with a broadcast. 2907b0b1ed979aa665175bf3952c8902ce13c763ab8The Android Open Source Project * 2919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @see #beginBroadcast 2929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 2939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void finishBroadcast() { 2947bdb9ce97811782864d3b54616f233c041590c7eMakoto Onuki synchronized (mCallbacks) { 2957bdb9ce97811782864d3b54616f233c041590c7eMakoto Onuki if (mBroadcastCount < 0) { 2967bdb9ce97811782864d3b54616f233c041590c7eMakoto Onuki throw new IllegalStateException( 2977bdb9ce97811782864d3b54616f233c041590c7eMakoto Onuki "finishBroadcast() called outside of a broadcast"); 2989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2997bdb9ce97811782864d3b54616f233c041590c7eMakoto Onuki 3007bdb9ce97811782864d3b54616f233c041590c7eMakoto Onuki Object[] active = mActiveBroadcast; 3017bdb9ce97811782864d3b54616f233c041590c7eMakoto Onuki if (active != null) { 3027bdb9ce97811782864d3b54616f233c041590c7eMakoto Onuki final int N = mBroadcastCount; 3037bdb9ce97811782864d3b54616f233c041590c7eMakoto Onuki for (int i=0; i<N; i++) { 3047bdb9ce97811782864d3b54616f233c041590c7eMakoto Onuki active[i] = null; 3057bdb9ce97811782864d3b54616f233c041590c7eMakoto Onuki } 3067bdb9ce97811782864d3b54616f233c041590c7eMakoto Onuki } 3077bdb9ce97811782864d3b54616f233c041590c7eMakoto Onuki 3087bdb9ce97811782864d3b54616f233c041590c7eMakoto Onuki mBroadcastCount = -1; 3099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3111cf70bbf96930662cab0e699d70b62865766ff52Svetoslav Ganov 3121cf70bbf96930662cab0e699d70b62865766ff52Svetoslav Ganov /** 313ef4351cc72abeeba0f659950c199a4f9b7cd1842Eugene Susla * Performs {@code action} on each callback, calling 314ef4351cc72abeeba0f659950c199a4f9b7cd1842Eugene Susla * {@link #beginBroadcast()}/{@link #finishBroadcast()} before/after looping 315ef4351cc72abeeba0f659950c199a4f9b7cd1842Eugene Susla * 316ef4351cc72abeeba0f659950c199a4f9b7cd1842Eugene Susla * @hide 317ef4351cc72abeeba0f659950c199a4f9b7cd1842Eugene Susla */ 318ef4351cc72abeeba0f659950c199a4f9b7cd1842Eugene Susla public void broadcast(Consumer<E> action) { 319ef4351cc72abeeba0f659950c199a4f9b7cd1842Eugene Susla int itemCount = beginBroadcast(); 320ef4351cc72abeeba0f659950c199a4f9b7cd1842Eugene Susla try { 321ef4351cc72abeeba0f659950c199a4f9b7cd1842Eugene Susla for (int i = 0; i < itemCount; i++) { 322ef4351cc72abeeba0f659950c199a4f9b7cd1842Eugene Susla action.accept(getBroadcastItem(i)); 323ef4351cc72abeeba0f659950c199a4f9b7cd1842Eugene Susla } 324ef4351cc72abeeba0f659950c199a4f9b7cd1842Eugene Susla } finally { 325ef4351cc72abeeba0f659950c199a4f9b7cd1842Eugene Susla finishBroadcast(); 326ef4351cc72abeeba0f659950c199a4f9b7cd1842Eugene Susla } 327ef4351cc72abeeba0f659950c199a4f9b7cd1842Eugene Susla } 328ef4351cc72abeeba0f659950c199a4f9b7cd1842Eugene Susla 329ef4351cc72abeeba0f659950c199a4f9b7cd1842Eugene Susla /** 3301cf70bbf96930662cab0e699d70b62865766ff52Svetoslav Ganov * Returns the number of registered callbacks. Note that the number of registered 3311cf70bbf96930662cab0e699d70b62865766ff52Svetoslav Ganov * callbacks may differ from the value returned by {@link #beginBroadcast()} since 3321cf70bbf96930662cab0e699d70b62865766ff52Svetoslav Ganov * the former returns the number of callbacks registered at the time of the call 3331cf70bbf96930662cab0e699d70b62865766ff52Svetoslav Ganov * and the second the number of callback to which the broadcast will be delivered. 3341cf70bbf96930662cab0e699d70b62865766ff52Svetoslav Ganov * <p> 3351cf70bbf96930662cab0e699d70b62865766ff52Svetoslav Ganov * This function is useful to decide whether to schedule a broadcast if this 3361cf70bbf96930662cab0e699d70b62865766ff52Svetoslav Ganov * requires doing some work which otherwise would not be performed. 3371cf70bbf96930662cab0e699d70b62865766ff52Svetoslav Ganov * </p> 3381cf70bbf96930662cab0e699d70b62865766ff52Svetoslav Ganov * 3391cf70bbf96930662cab0e699d70b62865766ff52Svetoslav Ganov * @return The size. 3401cf70bbf96930662cab0e699d70b62865766ff52Svetoslav Ganov */ 3411cf70bbf96930662cab0e699d70b62865766ff52Svetoslav Ganov public int getRegisteredCallbackCount() { 3421cf70bbf96930662cab0e699d70b62865766ff52Svetoslav Ganov synchronized (mCallbacks) { 3431cf70bbf96930662cab0e699d70b62865766ff52Svetoslav Ganov if (mKilled) { 3441cf70bbf96930662cab0e699d70b62865766ff52Svetoslav Ganov return 0; 3451cf70bbf96930662cab0e699d70b62865766ff52Svetoslav Ganov } 3461cf70bbf96930662cab0e699d70b62865766ff52Svetoslav Ganov return mCallbacks.size(); 3471cf70bbf96930662cab0e699d70b62865766ff52Svetoslav Ganov } 3481cf70bbf96930662cab0e699d70b62865766ff52Svetoslav Ganov } 3495614bf5a1ae4522dfc1a041f003cebc9b25c8b93Dianne Hackborn 3505614bf5a1ae4522dfc1a041f003cebc9b25c8b93Dianne Hackborn /** 35159359d06c4b504579db1bc72ded5ef29c4334c79Dianne Hackborn * Return a currently registered callback. Note that this is 35259359d06c4b504579db1bc72ded5ef29c4334c79Dianne Hackborn * <em>not</em> the same as {@link #getBroadcastItem} and should not be used 35359359d06c4b504579db1bc72ded5ef29c4334c79Dianne Hackborn * interchangeably with it. This method returns the registered callback at the given 35459359d06c4b504579db1bc72ded5ef29c4334c79Dianne Hackborn * index, not the current broadcast state. This means that it is not itself thread-safe: 35559359d06c4b504579db1bc72ded5ef29c4334c79Dianne Hackborn * any call to {@link #register} or {@link #unregister} will change these indices, so you 35659359d06c4b504579db1bc72ded5ef29c4334c79Dianne Hackborn * must do your own thread safety between these to protect from such changes. 35759359d06c4b504579db1bc72ded5ef29c4334c79Dianne Hackborn * 35859359d06c4b504579db1bc72ded5ef29c4334c79Dianne Hackborn * @param index Index of which callback registration to return, from 0 to 35959359d06c4b504579db1bc72ded5ef29c4334c79Dianne Hackborn * {@link #getRegisteredCallbackCount()} - 1. 36059359d06c4b504579db1bc72ded5ef29c4334c79Dianne Hackborn * 36159359d06c4b504579db1bc72ded5ef29c4334c79Dianne Hackborn * @return Returns whatever callback is associated with this index, or null if 36259359d06c4b504579db1bc72ded5ef29c4334c79Dianne Hackborn * {@link #kill()} has been called. 36359359d06c4b504579db1bc72ded5ef29c4334c79Dianne Hackborn */ 36459359d06c4b504579db1bc72ded5ef29c4334c79Dianne Hackborn public E getRegisteredCallbackItem(int index) { 36559359d06c4b504579db1bc72ded5ef29c4334c79Dianne Hackborn synchronized (mCallbacks) { 36659359d06c4b504579db1bc72ded5ef29c4334c79Dianne Hackborn if (mKilled) { 36759359d06c4b504579db1bc72ded5ef29c4334c79Dianne Hackborn return null; 36859359d06c4b504579db1bc72ded5ef29c4334c79Dianne Hackborn } 36959359d06c4b504579db1bc72ded5ef29c4334c79Dianne Hackborn return mCallbacks.valueAt(index).mCallback; 37059359d06c4b504579db1bc72ded5ef29c4334c79Dianne Hackborn } 37159359d06c4b504579db1bc72ded5ef29c4334c79Dianne Hackborn } 37259359d06c4b504579db1bc72ded5ef29c4334c79Dianne Hackborn 37359359d06c4b504579db1bc72ded5ef29c4334c79Dianne Hackborn /** 37459359d06c4b504579db1bc72ded5ef29c4334c79Dianne Hackborn * Return any cookie associated with a currently registered callback. Note that this is 3755614bf5a1ae4522dfc1a041f003cebc9b25c8b93Dianne Hackborn * <em>not</em> the same as {@link #getBroadcastCookie} and should not be used 37659359d06c4b504579db1bc72ded5ef29c4334c79Dianne Hackborn * interchangeably with it. This method returns the current cookie registered at the given 3775614bf5a1ae4522dfc1a041f003cebc9b25c8b93Dianne Hackborn * index, not the current broadcast state. This means that it is not itself thread-safe: 3785614bf5a1ae4522dfc1a041f003cebc9b25c8b93Dianne Hackborn * any call to {@link #register} or {@link #unregister} will change these indices, so you 3795614bf5a1ae4522dfc1a041f003cebc9b25c8b93Dianne Hackborn * must do your own thread safety between these to protect from such changes. 3805614bf5a1ae4522dfc1a041f003cebc9b25c8b93Dianne Hackborn * 38159359d06c4b504579db1bc72ded5ef29c4334c79Dianne Hackborn * @param index Index of which registration cookie to return, from 0 to 38259359d06c4b504579db1bc72ded5ef29c4334c79Dianne Hackborn * {@link #getRegisteredCallbackCount()} - 1. 3835614bf5a1ae4522dfc1a041f003cebc9b25c8b93Dianne Hackborn * 3845614bf5a1ae4522dfc1a041f003cebc9b25c8b93Dianne Hackborn * @return Returns whatever cookie object is associated with this index, or null if 3855614bf5a1ae4522dfc1a041f003cebc9b25c8b93Dianne Hackborn * {@link #kill()} has been called. 3865614bf5a1ae4522dfc1a041f003cebc9b25c8b93Dianne Hackborn */ 3875614bf5a1ae4522dfc1a041f003cebc9b25c8b93Dianne Hackborn public Object getRegisteredCallbackCookie(int index) { 3885614bf5a1ae4522dfc1a041f003cebc9b25c8b93Dianne Hackborn synchronized (mCallbacks) { 3895614bf5a1ae4522dfc1a041f003cebc9b25c8b93Dianne Hackborn if (mKilled) { 3905614bf5a1ae4522dfc1a041f003cebc9b25c8b93Dianne Hackborn return null; 3915614bf5a1ae4522dfc1a041f003cebc9b25c8b93Dianne Hackborn } 3925614bf5a1ae4522dfc1a041f003cebc9b25c8b93Dianne Hackborn return mCallbacks.valueAt(index).mCookie; 3935614bf5a1ae4522dfc1a041f003cebc9b25c8b93Dianne Hackborn } 3945614bf5a1ae4522dfc1a041f003cebc9b25c8b93Dianne Hackborn } 3959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 396