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 /** 68 * Resets the static state of the {@link Message} class by 69 * emptying the message pool. 70 */ 71 @Resetter reset()72 public static void reset() { 73 Object lock = reflector(MessageReflector.class).getPoolSync(); 74 synchronized (lock) { 75 reflector(MessageReflector.class).setPoolSize(0); 76 reflector(MessageReflector.class).setPool(null); 77 } 78 } 79 80 /** Accessor interface for {@link Message}'s internals. */ 81 @ForType(Message.class) 82 interface MessageReflector { 83 84 @Direct recycle()85 void recycle(); 86 87 @Direct recycleUnchecked()88 void recycleUnchecked(); 89 90 @Static 91 @Accessor("sPool") setPool(Message o)92 void setPool(Message o); 93 94 @Static 95 @Accessor("sPoolSize") setPoolSize(int size)96 void setPoolSize(int size); 97 98 @Static 99 @Accessor("sPoolSync") getPoolSync()100 Object getPoolSync(); 101 102 @Accessor("when") getWhen()103 long getWhen(); 104 105 @Accessor("next") getNext()106 Message getNext(); 107 108 @Accessor("next") setNext(Message next)109 void setNext(Message next); 110 111 @Accessor("target") getTarget()112 Handler getTarget(); 113 } 114 } 115