ShadowHandler.java revision 99fafb79bf98b7aa1946bbda1f0a225cefa2d35d
1ecb9a302b52b034610efb85bd73cb473e7c4ddb2Yabin Cuipackage com.xtremelabs.robolectric.shadows; 2ecb9a302b52b034610efb85bd73cb473e7c4ddb2Yabin Cui 3ecb9a302b52b034610efb85bd73cb473e7c4ddb2Yabin Cuiimport android.os.Handler; 4ecb9a302b52b034610efb85bd73cb473e7c4ddb2Yabin Cuiimport android.os.Looper; 5ecb9a302b52b034610efb85bd73cb473e7c4ddb2Yabin Cuiimport android.os.Message; 6ecb9a302b52b034610efb85bd73cb473e7c4ddb2Yabin Cui 7ecb9a302b52b034610efb85bd73cb473e7c4ddb2Yabin Cuiimport com.xtremelabs.robolectric.Robolectric; 8ecb9a302b52b034610efb85bd73cb473e7c4ddb2Yabin Cuiimport com.xtremelabs.robolectric.internal.Implementation; 9ecb9a302b52b034610efb85bd73cb473e7c4ddb2Yabin Cuiimport com.xtremelabs.robolectric.internal.Implements; 10ecb9a302b52b034610efb85bd73cb473e7c4ddb2Yabin Cuiimport com.xtremelabs.robolectric.internal.RealObject; 11ecb9a302b52b034610efb85bd73cb473e7c4ddb2Yabin Cui 12ecb9a302b52b034610efb85bd73cb473e7c4ddb2Yabin Cuiimport java.util.ArrayList; 13ecb9a302b52b034610efb85bd73cb473e7c4ddb2Yabin Cuiimport java.util.Iterator; 14ecb9a302b52b034610efb85bd73cb473e7c4ddb2Yabin Cuiimport java.util.List; 15ecb9a302b52b034610efb85bd73cb473e7c4ddb2Yabin Cui 16ecb9a302b52b034610efb85bd73cb473e7c4ddb2Yabin Cuiimport static com.xtremelabs.robolectric.Robolectric.shadowOf; 17ecb9a302b52b034610efb85bd73cb473e7c4ddb2Yabin Cui 18ecb9a302b52b034610efb85bd73cb473e7c4ddb2Yabin Cui/** 19ecb9a302b52b034610efb85bd73cb473e7c4ddb2Yabin Cui * Shadow for Handler that puts posted {@link Runnable}s into a queue instead of sending them to be handled on a 20ecb9a302b52b034610efb85bd73cb473e7c4ddb2Yabin Cui * separate thread.{@link Runnable}s that are scheduled to be executed immediately can be triggered by calling 21ecb9a302b52b034610efb85bd73cb473e7c4ddb2Yabin Cui * {@link #idleMainLooper()}. 22ecb9a302b52b034610efb85bd73cb473e7c4ddb2Yabin Cui * todo: add utility method to advance time and trigger execution of Runnables scheduled for a time in the future 23ecb9a302b52b034610efb85bd73cb473e7c4ddb2Yabin Cui */ 24ecb9a302b52b034610efb85bd73cb473e7c4ddb2Yabin Cui@SuppressWarnings({"UnusedDeclaration"}) 25ecb9a302b52b034610efb85bd73cb473e7c4ddb2Yabin Cui@Implements(Handler.class) 26ecb9a302b52b034610efb85bd73cb473e7c4ddb2Yabin Cuipublic class ShadowHandler { 27ecb9a302b52b034610efb85bd73cb473e7c4ddb2Yabin Cui @RealObject 28ecb9a302b52b034610efb85bd73cb473e7c4ddb2Yabin Cui private Handler realHandler; 29ecb9a302b52b034610efb85bd73cb473e7c4ddb2Yabin Cui private Looper looper = Looper.myLooper(); 30ecb9a302b52b034610efb85bd73cb473e7c4ddb2Yabin Cui private List<Message> messages = new ArrayList<Message>(); 31ecb9a302b52b034610efb85bd73cb473e7c4ddb2Yabin Cui private Handler.Callback callback; 32ecb9a302b52b034610efb85bd73cb473e7c4ddb2Yabin Cui 33ecb9a302b52b034610efb85bd73cb473e7c4ddb2Yabin Cui public void __constructor__() { 34ecb9a302b52b034610efb85bd73cb473e7c4ddb2Yabin Cui this.looper = Looper.myLooper(); 35ecb9a302b52b034610efb85bd73cb473e7c4ddb2Yabin Cui } 36ecb9a302b52b034610efb85bd73cb473e7c4ddb2Yabin Cui 37ecb9a302b52b034610efb85bd73cb473e7c4ddb2Yabin Cui public void __constructor__(Looper looper) { 38ecb9a302b52b034610efb85bd73cb473e7c4ddb2Yabin Cui this.looper = looper; 39ecb9a302b52b034610efb85bd73cb473e7c4ddb2Yabin Cui } 40ecb9a302b52b034610efb85bd73cb473e7c4ddb2Yabin Cui 41ecb9a302b52b034610efb85bd73cb473e7c4ddb2Yabin Cui public void __constructor__(Handler.Callback callback) { 42ecb9a302b52b034610efb85bd73cb473e7c4ddb2Yabin Cui this.callback = callback; 43ecb9a302b52b034610efb85bd73cb473e7c4ddb2Yabin Cui } 44 45 @Implementation 46 public boolean post(Runnable r) { 47 return postDelayed(r, 0); 48 } 49 50 @Implementation 51 public boolean postDelayed(Runnable r, long delayMillis) { 52 return shadowOf(looper).post(r, delayMillis); 53 } 54 55 @Implementation 56 public final boolean postAtFrontOfQueue(Runnable runnable) { 57 return shadowOf(looper).postAtFrontOfQueue(runnable); 58 } 59 60 @Implementation 61 public Message obtainMessage() { 62 return obtainMessage(0); 63 } 64 65 @Implementation 66 public Message obtainMessage(int what) { 67 return obtainMessage(what, null); 68 } 69 70 @Implementation 71 public Message obtainMessage(int what, Object obj) { 72 return obtainMessage(what, 0, 0, obj); 73 } 74 75 @Implementation 76 public Message obtainMessage(int what, int arg1, int arg2) { 77 return obtainMessage(what, arg1, arg2, null); 78 } 79 80 @Implementation 81 public Message obtainMessage(int what, int arg1, int arg2, Object obj) { 82 Message message = new Message(); 83 message.what = what; 84 message.arg1 = arg1; 85 message.arg2 = arg2; 86 message.obj = obj; 87 message.setTarget(realHandler); 88 return message; 89 } 90 91 @Implementation 92 public final boolean sendMessage(final Message msg) { 93 return sendMessageDelayed(msg, 0L); 94 } 95 96 @Implementation 97 public final boolean sendMessageDelayed(final Message msg, long delayMillis) { 98 Robolectric.shadowOf(msg).setWhen(Robolectric.shadowOf(looper).getScheduler().getCurrentTime()+delayMillis); 99 messages.add(msg); 100 postDelayed(new Runnable() { 101 @Override 102 public void run() { 103 if (messages.contains(msg)) { 104 messages.remove(msg); 105 routeMessage(msg); 106 } 107 } 108 }, delayMillis); 109 return true; 110 } 111 112 private void routeMessage(Message msg) { 113 if(callback != null) { 114 callback.handleMessage(msg); 115 } else { 116 realHandler.handleMessage(msg); 117 } 118 } 119 120 @Implementation 121 public final boolean sendEmptyMessage(int what) { 122 return sendEmptyMessageDelayed(what, 0L); 123 } 124 125 @Implementation 126 public final boolean sendEmptyMessageDelayed(int what, long delayMillis) { 127 final Message msg = new Message(); 128 msg.what = what; 129 return sendMessageDelayed(msg, delayMillis); 130 } 131 132 @Implementation 133 public final boolean sendMessageAtFrontOfQueue(final Message msg) { 134 Robolectric.shadowOf(msg).setWhen(Robolectric.shadowOf(looper).getScheduler().getCurrentTime()); 135 messages.add(0, msg); 136 postAtFrontOfQueue(new Runnable() { 137 @Override 138 public void run() { 139 if (messages.contains(msg)) { 140 messages.remove(msg); 141 routeMessage(msg); 142 } 143 } 144 }); 145 return true; 146 } 147 148 @Implementation 149 public final Looper getLooper() { 150 return looper; 151 } 152 153 @Implementation 154 public final void removeCallbacks(java.lang.Runnable r) { 155 shadowOf(looper).getScheduler().remove(r); 156 } 157 158 @Implementation 159 public final boolean hasMessages(int what) { 160 for (Message message : messages) { 161 if (message.what == what) { 162 return true; 163 } 164 } 165 return false; 166 } 167 168 @Implementation 169 public final boolean hasMessages(int what, Object object) { 170 for (Message message : messages) { 171 if(message.what == what && message.obj == object) { 172 return true; 173 } 174 } 175 return false; 176 } 177 178 179 @Implementation 180 public final void removeMessages(int what) { 181 removeMessages(what, null); 182 } 183 184 @Implementation 185 public final void removeMessages(int what, Object object) { 186 for (Iterator<Message> iterator = messages.iterator(); iterator.hasNext(); ) { 187 Message message = iterator.next(); 188 if (message.what == what && (object == null || object.equals(message.obj))) { 189 iterator.remove(); 190 } 191 } 192 } 193 194 195 196 /** 197 * @deprecated use {@link #idleMainLooper()} instead 198 */ 199 public static void flush() { 200 idleMainLooper(); 201 } 202 203 /** 204 * @see com.xtremelabs.robolectric.shadows.ShadowLooper#idle() 205 */ 206 public static void idleMainLooper() { 207 shadowOf(Looper.myLooper()).idle(); 208 } 209 210 /** 211 * @see ShadowLooper#runToEndOfTasks() () 212 */ 213 public static void runMainLooperToEndOfTasks() { 214 shadowOf(Looper.myLooper()).runToEndOfTasks(); 215 } 216 217 218 /** 219 * @see ShadowLooper#runOneTask() () 220 */ 221 public static void runMainLooperOneTask() { 222 shadowOf(Looper.myLooper()).runOneTask(); 223 } 224 225 /** 226 * @see ShadowLooper#runToNextTask() () 227 */ 228 public static void runMainLooperToNextTask() { 229 shadowOf(Looper.myLooper()).runToNextTask(); 230 } 231} 232