blob: b2fcee90d1552c034daa7233d9711f661e8b118e [file] [log] [blame]
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<E extends IInterface> {
private HashMap<IBinder, Callback> callbacks = new HashMap<IBinder, Callback>();
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;
}
}