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