1package com.xtremelabs.robolectric.shadows; 2 3import android.os.Handler; 4import android.os.Looper; 5import android.os.Message; 6import com.xtremelabs.robolectric.Robolectric; 7import com.xtremelabs.robolectric.WithTestDefaultsRunner; 8import com.xtremelabs.robolectric.util.TestRunnable; 9import com.xtremelabs.robolectric.util.Transcript; 10import org.junit.Before; 11import org.junit.Test; 12import org.junit.runner.RunWith; 13 14import static com.xtremelabs.robolectric.Robolectric.newInstanceOf; 15import static com.xtremelabs.robolectric.Robolectric.shadowOf; 16import static org.hamcrest.CoreMatchers.equalTo; 17import static org.hamcrest.CoreMatchers.nullValue; 18import static org.junit.Assert.assertThat; 19import static org.junit.Assert.assertTrue; 20import static org.junit.Assert.assertFalse; 21 22import java.util.ArrayList; 23import java.util.List; 24 25@RunWith(WithTestDefaultsRunner.class) 26public class HandlerTest { 27 private Transcript transcript; 28 TestRunnable scratchRunnable = new TestRunnable(); 29 30 private Handler.Callback callback = new Handler.Callback() { 31 @Override 32 public boolean handleMessage(Message msg) { 33 hasHandlerCallbackHandledMessage = true; 34 return false; 35 } 36 }; 37 38 private Boolean hasHandlerCallbackHandledMessage = false; 39 40 @Before 41 public void setUp() throws Exception { 42 transcript = new Transcript(); 43 } 44 45 @Test 46 public void testInsertsRunnablesBasedOnLooper() throws Exception { 47 Looper looper = newInstanceOf(Looper.class); 48 49 Handler handler1 = new Handler(looper); 50 handler1.post(new Say("first thing")); 51 52 Handler handler2 = new Handler(looper); 53 handler2.post(new Say("second thing")); 54 55 shadowOf(looper).idle(); 56 57 transcript.assertEventsSoFar("first thing", "second thing"); 58 } 59 60 @Test 61 public void testDefaultConstructorUsesDefaultLooper() throws Exception { 62 Handler handler1 = new Handler(); 63 handler1.post(new Say("first thing")); 64 65 Handler handler2 = new Handler(Looper.myLooper()); 66 handler2.post(new Say("second thing")); 67 68 shadowOf(Looper.myLooper()).idle(); 69 70 transcript.assertEventsSoFar("first thing", "second thing"); 71 } 72 73 @Test 74 public void testDifferentLoopersGetDifferentQueues() throws Exception { 75 Looper looper1 = Robolectric.newInstanceOf(Looper.class); 76 Robolectric.pauseLooper(looper1); 77 78 Looper looper2 = Robolectric.newInstanceOf(Looper.class); 79 Robolectric.pauseLooper(looper2); 80 81 Handler handler1 = new Handler(looper1); 82 handler1.post(new Say("first thing")); 83 84 Handler handler2 = new Handler(looper2); 85 handler2.post(new Say("second thing")); 86 87 shadowOf(looper2).idle(); 88 89 transcript.assertEventsSoFar("second thing"); 90 } 91 92 @Test 93 public void shouldCallProvidedHandlerCallback() { 94 Handler handler = new Handler(callback); 95 handler.sendMessage(new Message()); 96 assertTrue(hasHandlerCallbackHandledMessage); 97 } 98 99 @Test 100 public void testPostAndIdleMainLooper() throws Exception { 101 new Handler().post(scratchRunnable); 102 ShadowHandler.idleMainLooper(); 103 assertThat(scratchRunnable.wasRun, equalTo(true)); 104 } 105 106 @Test 107 public void postDelayedThenIdleMainLooper_shouldNotRunRunnable() throws Exception { 108 new Handler().postDelayed(scratchRunnable, 1); 109 ShadowHandler.idleMainLooper(); 110 assertThat(scratchRunnable.wasRun, equalTo(false)); 111 } 112 113 @Test 114 public void testPostDelayedThenRunMainLooperOneTask() throws Exception { 115 new Handler().postDelayed(scratchRunnable, 1); 116 ShadowHandler.runMainLooperOneTask(); 117 assertThat(scratchRunnable.wasRun, equalTo(true)); 118 } 119 120 @Test 121 public void testRemoveCallbacks() throws Exception { 122 Handler handler = new Handler(); 123 ShadowLooper shadowLooper = shadowOf(handler.getLooper()); 124 shadowLooper.pause(); 125 handler.post(scratchRunnable); 126 handler.removeCallbacks(scratchRunnable); 127 128 shadowLooper.unPause(); 129 130 assertThat(scratchRunnable.wasRun, equalTo(false)); 131 } 132 133 @Test 134 public void testPostDelayedThenRunMainLooperToNextTask_shouldRunOneTask() throws Exception { 135 new Handler().postDelayed(scratchRunnable, 1); 136 ShadowHandler.runMainLooperToNextTask(); 137 assertThat(scratchRunnable.wasRun, equalTo(true)); 138 } 139 140 @Test 141 public void testPostDelayedTwiceThenRunMainLooperToNextTask_shouldRunMultipleTasks() throws Exception { 142 TestRunnable task1 = new TestRunnable(); 143 TestRunnable task2 = new TestRunnable(); 144 145 new Handler().postDelayed(task1, 1); 146 new Handler().postDelayed(task2, 1); 147 148 ShadowHandler.runMainLooperToNextTask(); 149 assertThat(task1.wasRun, equalTo(true)); 150 assertThat(task2.wasRun, equalTo(true)); 151 } 152 153 @Test 154 public void testPostDelayedTwiceThenRunMainLooperOneTask_shouldRunOnlyOneTask() throws Exception { 155 TestRunnable task1 = new TestRunnable(); 156 TestRunnable task2 = new TestRunnable(); 157 158 new Handler().postDelayed(task1, 1); 159 new Handler().postDelayed(task2, 1); 160 161 ShadowHandler.runMainLooperOneTask(); 162 assertThat(task1.wasRun, equalTo(true)); 163 assertThat(task2.wasRun, equalTo(false)); 164 } 165 166 @Test 167 public void testPostDelayedMultipleThenRunMainLooperOneTask_shouldRunMultipleTask() throws Exception { 168 TestRunnable task1 = new TestRunnable(); 169 TestRunnable task2 = new TestRunnable(); 170 TestRunnable task3 = new TestRunnable(); 171 172 new Handler().postDelayed(task1, 1); 173 new Handler().postDelayed(task2, 10); 174 new Handler().postDelayed(task3, 100); 175 176 ShadowHandler.runMainLooperToEndOfTasks(); 177 assertThat(task1.wasRun, equalTo(true)); 178 assertThat(task2.wasRun, equalTo(true)); 179 assertThat(task3.wasRun, equalTo(true)); 180 } 181 182 @Test 183 public void testPostAtFrontOfQueueThenRunMainLooperOneTaskAtATime_shouldRunFrontOfQueueTaskFirst() throws Exception { 184 TestRunnable task1 = new TestRunnable(); 185 TestRunnable task2 = new TestRunnable(); 186 187 ShadowLooper.pauseMainLooper(); 188 new Handler().post(task1); 189 boolean result = new Handler().postAtFrontOfQueue(task2); 190 191 assertTrue(result); 192 193 ShadowHandler.runMainLooperOneTask(); 194 assertThat(task2.wasRun, equalTo(true)); 195 assertThat(task1.wasRun, equalTo(false)); 196 ShadowHandler.runMainLooperOneTask(); 197 assertThat(task1.wasRun, equalTo(true)); 198 } 199 200 @Test 201 public void testSendMessageAtFrontOfQueueThenRunMainLooperOneMsgAtATime_shouldRunFrontOfQueueMsgFirst() throws Exception { 202 Handler handler = new Handler(); 203 204 ShadowLooper.pauseMainLooper(); 205 // Post two messages to handler. Handle first message and confirm that msg posted 206 // to front is removed. 207 handler.obtainMessage(123).sendToTarget(); 208 Message frontMsg = handler.obtainMessage(345); 209 boolean result = handler.sendMessageAtFrontOfQueue(frontMsg); 210 211 assertTrue(result); 212 213 assertTrue(handler.hasMessages(123)); 214 assertTrue(handler.hasMessages(345)); 215 ShadowHandler.runMainLooperOneTask(); 216 assertTrue(handler.hasMessages(123)); 217 assertFalse(handler.hasMessages(345)); 218 ShadowHandler.runMainLooperOneTask(); 219 assertFalse(handler.hasMessages(123)); 220 assertFalse(handler.hasMessages(345)); 221 } 222 223 @Test 224 public void sendEmptyMessage_addMessageToQueue() { 225 Robolectric.pauseMainLooper(); 226 Handler handler = new Handler(); 227 assertThat(handler.hasMessages(123), equalTo(false)); 228 handler.sendEmptyMessage(123); 229 assertThat(handler.hasMessages(456), equalTo(false)); 230 assertThat(handler.hasMessages(123), equalTo(true)); 231 Robolectric.idleMainLooper(0); 232 assertThat(handler.hasMessages(123), equalTo(false)); 233 } 234 235 @Test 236 public void sendEmptyMessageDelayed_sendsMessageAtCorrectTime() { 237 Robolectric.pauseMainLooper(); 238 Handler handler = new Handler(); 239 handler.sendEmptyMessageDelayed(123, 500); 240 assertThat(handler.hasMessages(123), equalTo(true)); 241 Robolectric.idleMainLooper(100); 242 assertThat(handler.hasMessages(123), equalTo(true)); 243 Robolectric.idleMainLooper(400); 244 assertThat(handler.hasMessages(123), equalTo(false)); 245 } 246 247 @Test 248 public void removeMessages_takesMessageOutOfQueue() { 249 Robolectric.pauseMainLooper(); 250 Handler handler = new Handler(); 251 handler.sendEmptyMessageDelayed(123, 500); 252 handler.removeMessages(123); 253 assertThat(handler.hasMessages(123), equalTo(false)); 254 } 255 256 @Test 257 public void removeMessage_withSpecifiedObject() throws Exception { 258 Robolectric.pauseMainLooper(); 259 Handler handler = new Handler(); 260 Message.obtain(handler, 123, "foo").sendToTarget(); 261 Message.obtain(handler, 123, "bar").sendToTarget(); 262 263 assertThat(handler.hasMessages(123), equalTo(true)); 264 assertThat(handler.hasMessages(123, "foo"), equalTo(true)); 265 assertThat(handler.hasMessages(123, "bar"), equalTo(true)); 266 assertThat(handler.hasMessages(123, "baz"), equalTo(false)); 267 268 handler.removeMessages(123, "foo"); 269 assertThat(handler.hasMessages(123), equalTo(true)); 270 271 handler.removeMessages(123, "bar"); 272 assertThat(handler.hasMessages(123), equalTo(false)); 273 } 274 275 @Test 276 public void testHasMessagesWithWhatAndObject() { 277 Robolectric.pauseMainLooper(); 278 Object testObject = new Object(); 279 Handler handler = new Handler(); 280 Message message = handler.obtainMessage(123, testObject); 281 282 assertFalse(handler.hasMessages(123, testObject)); 283 284 handler.sendMessage(message); 285 286 assertTrue(handler.hasMessages(123, testObject)); 287 } 288 289 @Test 290 public void testSendToTarget() { 291 Robolectric.pauseMainLooper(); 292 Object testObject = new Object(); 293 Handler handler = new Handler(); 294 Message message = handler.obtainMessage(123, testObject); 295 296 assertThat(handler, equalTo(message.getTarget())); 297 298 message.sendToTarget(); 299 300 assertTrue(handler.hasMessages(123, testObject)); 301 } 302 303 @Test 304 public void removeMessages_removesFromLooperQueueAsWell() { 305 final boolean[] wasRun = new boolean[1]; 306 Robolectric.pauseMainLooper(); 307 Handler handler = new Handler() { 308 @Override 309 public void handleMessage(Message msg) { 310 wasRun[0] = true; 311 } 312 }; 313 handler.sendEmptyMessageDelayed(123, 500); 314 handler.removeMessages(123); 315 Robolectric.unPauseMainLooper(); 316 assertThat(wasRun[0], equalTo(false)); 317 } 318 319 @Test 320 public void shouldObtainMessage() throws Exception { 321 Message m0 = new Handler().obtainMessage(); 322 assertThat(m0.what, equalTo(0)); 323 assertThat(m0.obj, nullValue()); 324 325 Message m1 = new Handler().obtainMessage(1); 326 assertThat(m1.what, equalTo(1)); 327 assertThat(m1.obj, nullValue()); 328 329 Message m2 = new Handler().obtainMessage(1, "foo"); 330 assertThat(m2.what, equalTo(1)); 331 assertThat(m2.obj, equalTo((Object)"foo")); 332 333 Message m3 = new Handler().obtainMessage(1, 2, 3); 334 assertThat(m3.what, equalTo(1)); 335 assertThat(m3.arg1, equalTo(2)); 336 assertThat(m3.arg2, equalTo(3)); 337 assertThat(m3.obj, nullValue()); 338 339 Message m4 = new Handler().obtainMessage(1, 2, 3, "foo"); 340 assertThat(m4.what, equalTo(1)); 341 assertThat(m4.arg1, equalTo(2)); 342 assertThat(m4.arg2, equalTo(3)); 343 assertThat(m4.obj, equalTo((Object)"foo")); 344 } 345 346 @Test 347 public void shouldSetWhenOnMessage() throws Exception { 348 final List<Message> msgs = new ArrayList<Message>(); 349 Handler h = new Handler(new Handler.Callback() { 350 @Override 351 public boolean handleMessage(Message msg) { 352 msgs.add(msg); 353 return false; 354 } 355 }); 356 357 h.sendEmptyMessage(0); 358 h.sendEmptyMessageDelayed(0, 4000l); 359 Robolectric.getUiThreadScheduler().advanceToLastPostedRunnable(); 360 h.sendEmptyMessageDelayed(0, 12000l); 361 Robolectric.getUiThreadScheduler().advanceToLastPostedRunnable(); 362 assertThat(msgs.size(), equalTo(3)); 363 364 Message m0 = msgs.get(0); 365 Message m1 = msgs.get(1); 366 Message m2 = msgs.get(2); 367 368 assertThat(m0.getWhen(), equalTo(0l)); 369 assertThat(m1.getWhen(), equalTo(4000l)); 370 assertThat(m2.getWhen(), equalTo(16000l)); 371 } 372 373 @Test 374 public void shouldRemoveMessageFromQueueBeforeDispatching() throws Exception { 375 Handler h = new Handler(Looper.myLooper()) { 376 @Override 377 public void handleMessage(Message msg) { 378 assertFalse(hasMessages(0)); 379 } 380 }; 381 h.sendEmptyMessage(0); 382 h.sendMessageAtFrontOfQueue(h.obtainMessage()); 383 } 384 385 386 private class Say implements Runnable { 387 private String event; 388 389 public Say(String event) { 390 this.event = event; 391 } 392 393 @Override 394 public void run() { 395 transcript.add(event); 396 } 397 } 398} 399