1f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphreypackage com.xtremelabs.robolectric.shadows; 2f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphrey 3f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphreyimport java.util.HashMap; 4f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphrey 5f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphreyimport android.os.IBinder; 6f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphreyimport android.os.IInterface; 7f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphreyimport android.os.RemoteCallbackList; 8f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphreyimport android.os.RemoteException; 9f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphrey 10f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphreyimport com.xtremelabs.robolectric.internal.Implementation; 11f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphreyimport com.xtremelabs.robolectric.internal.Implements; 12f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphrey 13f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphrey@Implements(RemoteCallbackList.class) 14f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphreypublic class ShadowRemoteCallbackList<E extends IInterface> { 15f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphrey private HashMap<IBinder, Callback> callbacks = new HashMap<IBinder, Callback>(); 16f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphrey private Object[] activeBroadcast; 17f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphrey private int broadcastCount = -1; 18f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphrey private boolean killed = false; 19f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphrey 20f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphrey private final class Callback implements IBinder.DeathRecipient { 21f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphrey final E callback; 22f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphrey final Object cookie; 23f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphrey 24f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphrey Callback(E callback, Object cookie) { 25f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphrey this.callback = callback; 26f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphrey this.cookie = cookie; 27f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphrey } 28f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphrey 29f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphrey public void binderDied() { 30f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphrey synchronized (callbacks) { 31f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphrey callbacks.remove(callback.asBinder()); 32f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphrey } 33f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphrey onCallbackDied(callback, cookie); 34f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphrey } 35f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphrey } 36f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphrey 37f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphrey @Implementation 38f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphrey public boolean register(E callback) { 39f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphrey return register(callback, null); 40f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphrey } 41f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphrey 42f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphrey @Implementation 43f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphrey public boolean register(E callback, Object cookie) { 44f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphrey synchronized (callbacks) { 45f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphrey if (killed) { 46f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphrey return false; 47f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphrey } 48f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphrey IBinder binder = callback.asBinder(); 49f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphrey try { 50f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphrey Callback cb = new Callback(callback, cookie); 51f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphrey binder.linkToDeath(cb, 0); 52f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphrey callbacks.put(binder, cb); 53f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphrey return true; 54f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphrey } catch (RemoteException e) { 55f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphrey return false; 56f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphrey } 57f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphrey } 58f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphrey } 59f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphrey 60f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphrey @Implementation 61f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphrey public boolean unregister(E callback) { 62f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphrey synchronized (callbacks) { 63f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphrey Callback cb = callbacks.remove(callback.asBinder()); 64f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphrey if (cb != null) { 65f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphrey cb.callback.asBinder().unlinkToDeath(cb, 0); 66f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphrey return true; 67f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphrey } 68f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphrey return false; 69f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphrey } 70f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphrey } 71f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphrey 72f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphrey @Implementation 73f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphrey public void kill() { 74f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphrey synchronized (callbacks) { 75f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphrey for (Callback cb : callbacks.values()) { 76f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphrey cb.callback.asBinder().unlinkToDeath(cb, 0); 77f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphrey } 78f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphrey callbacks.clear(); 79f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphrey killed = true; 80f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphrey } 81f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphrey } 82f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphrey 83f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphrey @Implementation 84f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphrey public void onCallbackDied(E callback) {} 85f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphrey 86f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphrey @Implementation 87f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphrey public void onCallbackDied(E callback, Object cookie) { 88f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphrey onCallbackDied(callback); 89f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphrey } 90f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphrey 91f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphrey @Implementation 92f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphrey public int beginBroadcast() { 93f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphrey synchronized (callbacks) { 94f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphrey if (broadcastCount > 0) { 95f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphrey throw new IllegalStateException("beginBroadcast() called while already in a broadcast"); 96f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphrey } 97f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphrey final int N = broadcastCount = callbacks.size(); 98f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphrey if (N <= 0) { 99f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphrey return 0; 100f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphrey } 101f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphrey Object[] active = activeBroadcast; 102f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphrey if (active == null || active.length < N) { 103f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphrey activeBroadcast = active = new Object[N]; 104f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphrey } 105f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphrey int i = 0; 106f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphrey for (Callback cb : callbacks.values()) { 107f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphrey active[i++] = cb; 108f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphrey } 109f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphrey return i; 110f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphrey } 111f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphrey } 112f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphrey 113f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphrey @Implementation 114f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphrey public E getBroadcastItem(int index) { 115f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphrey return ((Callback) activeBroadcast[index]).callback; 116f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphrey } 117f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphrey 118f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphrey @Implementation 119f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphrey public Object getBroadcastCookie(int index) { 120f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphrey return ((Callback) activeBroadcast[index]).cookie; 121f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphrey } 122f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphrey 123f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphrey @Implementation 124f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphrey public void finishBroadcast() { 125f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphrey if (broadcastCount < 0) { 126f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphrey throw new IllegalStateException("finishBroadcast() called outside of a broadcast"); 127f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphrey } 128f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphrey Object[] active = activeBroadcast; 129f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphrey if (active != null) { 130f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphrey final int N = broadcastCount; 131f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphrey for (int i = 0; i < N; i++) { 132f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphrey active[i] = null; 133f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphrey } 134f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphrey } 135f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphrey broadcastCount = -1; 136f459ed3d115ea2fa51606df1cb378c0cb80bd787Rich Humphrey } 137dcd8511f9695994fbfc49b501923ed257d74fea1Christian Rackerseder}