package com.xtremelabs.robolectric.shadows; import java.util.HashMap; import android.os.IBinder; import android.os.IInterface; import android.os.RemoteCallbackList; import android.os.RemoteException; import com.xtremelabs.robolectric.internal.Implementation; import com.xtremelabs.robolectric.internal.Implements; @Implements(RemoteCallbackList.class) public class ShadowRemoteCallbackList { private HashMap callbacks = new HashMap(); private Object[] activeBroadcast; private int broadcastCount = -1; private boolean killed = false; private final class Callback implements IBinder.DeathRecipient { final E callback; final Object cookie; Callback(E callback, Object cookie) { this.callback = callback; this.cookie = cookie; } public void binderDied() { synchronized (callbacks) { callbacks.remove(callback.asBinder()); } onCallbackDied(callback, cookie); } } @Implementation public boolean register(E callback) { return register(callback, null); } @Implementation public boolean register(E callback, Object cookie) { synchronized (callbacks) { if (killed) { return false; } IBinder binder = callback.asBinder(); try { Callback cb = new Callback(callback, cookie); binder.linkToDeath(cb, 0); callbacks.put(binder, cb); return true; } catch (RemoteException e) { return false; } } } @Implementation public boolean unregister(E callback) { synchronized (callbacks) { Callback cb = callbacks.remove(callback.asBinder()); if (cb != null) { cb.callback.asBinder().unlinkToDeath(cb, 0); return true; } return false; } } @Implementation public void kill() { synchronized (callbacks) { for (Callback cb : callbacks.values()) { cb.callback.asBinder().unlinkToDeath(cb, 0); } callbacks.clear(); killed = true; } } @Implementation public void onCallbackDied(E callback) {} @Implementation public void onCallbackDied(E callback, Object cookie) { onCallbackDied(callback); } @Implementation public int beginBroadcast() { synchronized (callbacks) { if (broadcastCount > 0) { throw new IllegalStateException("beginBroadcast() called while already in a broadcast"); } final int N = broadcastCount = callbacks.size(); if (N <= 0) { return 0; } Object[] active = activeBroadcast; if (active == null || active.length < N) { activeBroadcast = active = new Object[N]; } int i = 0; for (Callback cb : callbacks.values()) { active[i++] = cb; } return i; } } @Implementation public E getBroadcastItem(int index) { return ((Callback) activeBroadcast[index]).callback; } @Implementation public Object getBroadcastCookie(int index) { return ((Callback) activeBroadcast[index]).cookie; } @Implementation public void finishBroadcast() { if (broadcastCount < 0) { throw new IllegalStateException("finishBroadcast() called outside of a broadcast"); } Object[] active = activeBroadcast; if (active != null) { final int N = broadcastCount; for (int i = 0; i < N; i++) { active[i] = null; } } broadcastCount = -1; } }