xref: /aosp_15_r20/external/robolectric/shadows/framework/src/main/java/org/robolectric/shadows/ShadowMessage.java (revision e6ba16074e6af37d123cb567d575f496bf0a58ee)
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.Message;
7 import org.robolectric.annotation.Implements;
8 import org.robolectric.annotation.LooperMode;
9 import org.robolectric.annotation.Resetter;
10 import org.robolectric.util.reflector.Accessor;
11 import org.robolectric.util.reflector.Direct;
12 import org.robolectric.util.reflector.ForType;
13 import org.robolectric.util.reflector.Static;
14 
15 /**
16  * The shadow API for {@link android.os.Message}.
17  *
18  * <p>Different shadow implementations will be used depending on the current {@link LooperMode}. See
19  * {@link ShadowLegacyMessage} and {@link ShadowPausedMessage} for details.
20  */
21 @Implements(value = Message.class, shadowPicker = ShadowMessage.Picker.class)
22 public abstract class ShadowMessage {
23 
24   /** The shadow Picker for this class */
25   public static class Picker extends LooperShadowPicker<ShadowMessage> {
26 
Picker()27     public Picker() {
28       super(ShadowLegacyMessage.class, ShadowPausedMessage.class);
29     }
30   }
31 
32   /** Exposes the package-private {@link Message#recycleUnchecked()} */
recycleUnchecked()33   public abstract void recycleUnchecked();
34 
35   /**
36    * Stores the {@link Runnable} instance that has been scheduled to invoke this message. This is
37    * called when the message is enqueued by {@link ShadowLegacyMessageQueue#enqueueMessage} and is
38    * used when the message is recycled to ensure that the correct {@link Runnable} instance is
39    * removed from the associated scheduler.
40    *
41    * @param r the {@link Runnable} instance that is scheduled to trigger this message.
42    *     <p>#if ($api >= 21) * @see #recycleUnchecked() #else * @see #recycle() #end
43    *     <p>Only supported in {@link LooperMode.Mode.LEGACY}.
44    */
setScheduledRunnable(Runnable r)45   public abstract void setScheduledRunnable(Runnable r);
46 
47   /**
48    * Convenience method to provide getter access to the private field {@code Message.next}.
49    *
50    * <p>Only supported in {@link LooperMode.Mode.LEGACY}
51    *
52    * @return The next message in the current message chain.
53    * @see #setNext(Message)
54    */
getNext()55   public abstract Message getNext();
56 
57   /**
58    * Convenience method to provide setter access to the private field {@code Message.next}.
59    *
60    * <p>Only supported in {@link LooperMode.Mode.LEGACY}
61    *
62    * @param next the new next message for the current message.
63    * @see #getNext()
64    */
setNext(Message next)65   public abstract void setNext(Message next);
66 
67   /** Resets the static state of the {@link Message} class by emptying the message pool. */
68   @Resetter
reset()69   public static void reset() {
70     Object lock = reflector(MessageReflector.class).getPoolSync();
71     synchronized (lock) {
72       reflector(MessageReflector.class).setPoolSize(0);
73       reflector(MessageReflector.class).setPool(null);
74     }
75   }
76 
77   /** Accessor interface for {@link Message}'s internals. */
78   @ForType(Message.class)
79   interface MessageReflector {
80 
81     @Direct
recycle()82     void recycle();
83 
84     @Direct
recycleUnchecked()85     void recycleUnchecked();
86 
87     @Static
88     @Accessor("sPool")
setPool(Message o)89     void setPool(Message o);
90 
91     @Static
92     @Accessor("sPoolSize")
setPoolSize(int size)93     void setPoolSize(int size);
94 
95     @Static
96     @Accessor("sPoolSync")
getPoolSync()97     Object getPoolSync();
98 
99     @Accessor("when")
getWhen()100     long getWhen();
101 
102     @Accessor("next")
getNext()103     Message getNext();
104 
105     @Accessor("next")
setNext(Message next)106     void setNext(Message next);
107 
108     @Accessor("target")
getTarget()109     Handler getTarget();
110   }
111 }
112