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