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