
org.robolectric.shadows.ShadowMessageQueue Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of framework Show documentation
Show all versions of framework Show documentation
An alternative Android testing framework.
The newest version!
package org.robolectric.shadows;
import android.os.Handler;
import android.os.Message;
import android.os.MessageQueue;
import org.robolectric.annotation.HiddenApi;
import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements;
import org.robolectric.annotation.RealObject;
import org.robolectric.util.Scheduler;
import static android.os.Build.VERSION_CODES.KITKAT_WATCH;
import static android.os.Build.VERSION_CODES.LOLLIPOP;
import static org.robolectric.RuntimeEnvironment.getApiLevel;
import static org.robolectric.Shadows.shadowOf;
import static org.robolectric.shadow.api.Shadow.directlyOn;
import static org.robolectric.util.ReflectionHelpers.ClassParameter.from;
import static org.robolectric.util.ReflectionHelpers.callInstanceMethod;
import static org.robolectric.util.ReflectionHelpers.getField;
import static org.robolectric.util.ReflectionHelpers.setField;
/**
* Robolectric puts {@link android.os.Message}s into the scheduler queue instead of sending
* them to be handled on a separate thread. {@link android.os.Message}s that are scheduled to
* be dispatched can be triggered by calling {@link ShadowLooper#idleMainLooper}.
*
* @see ShadowLooper
*/
@Implements(MessageQueue.class)
public class ShadowMessageQueue {
@RealObject
private MessageQueue realQueue;
private Scheduler scheduler;
// Stub out the native peer - scheduling
// is handled by the Scheduler class which is user-driven
// rather than automatic.
@HiddenApi
@Implementation
public static Number nativeInit() {
return 1;
}
@HiddenApi
@Implementation(maxSdk = KITKAT_WATCH)
public static void nativeDestroy(int ptr) {
nativeDestroy((long) ptr);
}
@Implementation(minSdk = LOLLIPOP)
public static void nativeDestroy(long ptr) {
}
@HiddenApi
@Implementation(maxSdk = KITKAT_WATCH)
public static void nativePollOnce(int ptr, int timeoutMillis) {
nativePollOnce((long) ptr, timeoutMillis);
}
@Implementation(minSdk = LOLLIPOP)
public static void nativePollOnce(long ptr, int timeoutMillis) {
throw new AssertionError("Should not be called");
}
@HiddenApi
@Implementation(maxSdk = KITKAT_WATCH)
public static void nativeWake(int ptr) {
nativeWake((long) ptr);
}
@Implementation(minSdk = LOLLIPOP)
public static void nativeWake(long ptr) {
throw new AssertionError("Should not be called");
}
@HiddenApi
@Implementation(maxSdk = KITKAT_WATCH)
public static boolean nativeIsIdling(int ptr) {
return nativeIsIdling((long) ptr);
}
@Implementation(minSdk = LOLLIPOP)
public static boolean nativeIsIdling(long ptr) {
return false;
}
public Scheduler getScheduler() {
return scheduler;
}
public void setScheduler(Scheduler scheduler) {
this.scheduler = scheduler;
}
public Message getHead() {
return getField(realQueue, "mMessages");
}
public void setHead(Message msg) {
setField(realQueue, "mMessages", msg);
}
public void reset() {
setHead(null);
}
@Implementation
public boolean enqueueMessage(final Message msg, long when) {
final boolean retval = directlyOn(realQueue, MessageQueue.class, "enqueueMessage", from(Message.class, msg), from(long.class, when));
if (retval) {
final Runnable callback = new Runnable() {
@Override
public void run() {
synchronized (realQueue) {
Message m = getHead();
if (m == null) {
return;
}
Message n = shadowOf(m).getNext();
if (m == msg) {
setHead(n);
} else {
while (n != null) {
if (n == msg) {
n = shadowOf(n).getNext();
shadowOf(m).setNext(n);
break;
}
m = n;
n = shadowOf(m).getNext();
}
}
}
dispatchMessage(msg);
}
};
shadowOf(msg).setScheduledRunnable(callback);
if (when == 0) {
scheduler.postAtFrontOfQueue(callback);
} else {
scheduler.postDelayed(callback, when - scheduler.getCurrentTime());
}
}
return retval;
}
@HiddenApi
@Implementation
public void removeSyncBarrier(int token) {
}
private static void dispatchMessage(Message msg) {
final Handler target = msg.getTarget();
shadowOf(msg).setNext(null);
// If target is null it means the message has been removed
// from the queue prior to being dispatched by the scheduler.
if (target != null) {
callInstanceMethod(msg, "markInUse");
target.dispatchMessage(msg);
if (getApiLevel() >= LOLLIPOP) {
callInstanceMethod(msg, "recycleUnchecked");
} else {
callInstanceMethod(msg, "recycle");
}
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy