1 package org.robolectric.shadows;
2 
3 import static org.robolectric.util.reflector.Reflector.reflector;
4 
5 import android.os.Handler;
6 import android.os.Looper;
7 import android.os.Message;
8 import org.robolectric.annotation.HiddenApi;
9 import org.robolectric.annotation.Implementation;
10 import org.robolectric.annotation.Implements;
11 import org.robolectric.annotation.LooperMode;
12 import org.robolectric.annotation.RealObject;
13 import org.robolectric.shadow.api.Shadow;
14 import org.robolectric.util.Scheduler;
15 import org.robolectric.util.reflector.ForType;
16 
17 /**
18  * The shadow {@link Message} for {@link LooperMode.Mode.LEGACY}.
19  *
20  * <p>In {@link LooperMode.Mode.LEGACY}, each Message is associated with a Runnable posted to the
21  * {@link Scheduler}.
22  *
23  * @see ShadowLooper
24  * @see ShadowLegacyMessageQueue
25  */
26 @Implements(value = Message.class, isInAndroidSdk = false)
27 public class ShadowLegacyMessage extends ShadowMessage {
28   @RealObject private Message realMessage;
29   private Runnable scheduledRunnable;
30 
unschedule()31   private void unschedule() {
32     Handler target = realMessage.getTarget();
33 
34     if (target != null && scheduledRunnable != null) {
35       shadowOf(target.getLooper()).getScheduler().remove(scheduledRunnable);
36       scheduledRunnable = null;
37     }
38   }
39 
40   /**
41    * Hook to unscheduled the callback when the message is recycled. Invokes {@link #unschedule()}
42    * and then calls through to the package private method {@link Message#recycleUnchecked()} on the
43    * real object.
44    */
45   @HiddenApi
46   @Implementation
recycleUnchecked()47   public void recycleUnchecked() {
48 
49     unschedule();
50     reflector(MessageReflector.class, realMessage).recycleUnchecked();
51   }
52 
53   @Override
setScheduledRunnable(Runnable r)54   public void setScheduledRunnable(Runnable r) {
55     scheduledRunnable = r;
56   }
57 
58   @Override
getNext()59   public Message getNext() {
60     return reflector(MessageReflector.class, realMessage).getNext();
61   }
62 
63   @Override
setNext(Message next)64   public void setNext(Message next) {
65     reflector(MessageReflector.class, realMessage).setNext(next);
66   }
67 
shadowOf(Looper looper)68   private static ShadowLooper shadowOf(Looper looper) {
69     return Shadow.extract(looper);
70   }
71 
72   /** Accessor interface for {@link Message}'s internals. */
73   @ForType(Message.class)
74   interface LegacyMessageReflector {
75 
markInUse()76     void markInUse();
77 
recycle()78     void recycle();
79 
recycleUnchecked()80     void recycleUnchecked();
81   }
82 }
83