зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1352534 - [1.3] Allow for mupltiple native queues and assign a unique queue per GeckoView. r=jchen
This commit is contained in:
Родитель
75452c87a4
Коммит
2b30df194c
|
@ -9,7 +9,6 @@ import org.mozilla.gecko.annotation.RobocopTarget;
|
||||||
import org.mozilla.gecko.annotation.WrapForJNI;
|
import org.mozilla.gecko.annotation.WrapForJNI;
|
||||||
import org.mozilla.gecko.GeckoAppShell;
|
import org.mozilla.gecko.GeckoAppShell;
|
||||||
import org.mozilla.gecko.mozglue.JNIObject;
|
import org.mozilla.gecko.mozglue.JNIObject;
|
||||||
import org.mozilla.gecko.NativeQueue.StateHolder;
|
|
||||||
import org.mozilla.gecko.util.BundleEventListener;
|
import org.mozilla.gecko.util.BundleEventListener;
|
||||||
import org.mozilla.gecko.util.EventCallback;
|
import org.mozilla.gecko.util.EventCallback;
|
||||||
import org.mozilla.gecko.util.GeckoBundle;
|
import org.mozilla.gecko.util.GeckoBundle;
|
||||||
|
@ -55,7 +54,7 @@ public final class EventDispatcher extends JNIObject {
|
||||||
new HashMap<String, List<BundleEventListener>>(DEFAULT_BACKGROUND_EVENTS_COUNT);
|
new HashMap<String, List<BundleEventListener>>(DEFAULT_BACKGROUND_EVENTS_COUNT);
|
||||||
|
|
||||||
private boolean mAttachedToGecko;
|
private boolean mAttachedToGecko;
|
||||||
private volatile StateHolder mStateHolder;
|
private final NativeQueue mNativeQueue;
|
||||||
|
|
||||||
@ReflectionTarget
|
@ReflectionTarget
|
||||||
@WrapForJNI(calledFrom = "gecko")
|
@WrapForJNI(calledFrom = "gecko")
|
||||||
|
@ -64,22 +63,15 @@ public final class EventDispatcher extends JNIObject {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* package */ EventDispatcher() {
|
/* package */ EventDispatcher() {
|
||||||
mStateHolder = GeckoThread.getStateHolder();
|
mNativeQueue = GeckoThread.getNativeQueue();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* package */ EventDispatcher(final NativeQueue.StateHolder stateHolder) {
|
/* package */ EventDispatcher(final NativeQueue queue) {
|
||||||
mStateHolder = stateHolder;
|
mNativeQueue = queue;
|
||||||
}
|
|
||||||
|
|
||||||
/* package */ void setStateHolder(final NativeQueue.StateHolder stateHolder) {
|
|
||||||
mStateHolder = stateHolder;
|
|
||||||
// Force queue flushing.
|
|
||||||
final NativeQueue.State state = mStateHolder.getState();
|
|
||||||
mStateHolder.checkAndSetState(state, state);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isReadyForDispatchingToGecko() {
|
private boolean isReadyForDispatchingToGecko() {
|
||||||
return mStateHolder.isReady();
|
return mNativeQueue.isReady();
|
||||||
}
|
}
|
||||||
|
|
||||||
@WrapForJNI(dispatchTo = "gecko") @Override // JNIObject
|
@WrapForJNI(dispatchTo = "gecko") @Override // JNIObject
|
||||||
|
@ -301,8 +293,7 @@ public final class EventDispatcher extends JNIObject {
|
||||||
// Gecko, we make a special exception to queue this event until
|
// Gecko, we make a special exception to queue this event until
|
||||||
// Gecko(View) is ready. This way, Gecko can first register its
|
// Gecko(View) is ready. This way, Gecko can first register its
|
||||||
// listeners, and accept the event when it is ready.
|
// listeners, and accept the event when it is ready.
|
||||||
NativeQueue.queueUntil(mStateHolder,
|
mNativeQueue.queueUntilReady(this, "dispatchToGecko",
|
||||||
mStateHolder.getReadyState(), this, "dispatchToGecko",
|
|
||||||
String.class, type,
|
String.class, type,
|
||||||
GeckoBundle.class, message,
|
GeckoBundle.class, message,
|
||||||
EventCallback.class, JavaCallbackDelegate.wrap(callback));
|
EventCallback.class, JavaCallbackDelegate.wrap(callback));
|
||||||
|
|
|
@ -8,7 +8,6 @@ package org.mozilla.gecko;
|
||||||
import org.mozilla.gecko.annotation.RobocopTarget;
|
import org.mozilla.gecko.annotation.RobocopTarget;
|
||||||
import org.mozilla.gecko.annotation.WrapForJNI;
|
import org.mozilla.gecko.annotation.WrapForJNI;
|
||||||
import org.mozilla.gecko.mozglue.GeckoLoader;
|
import org.mozilla.gecko.mozglue.GeckoLoader;
|
||||||
import org.mozilla.gecko.NativeQueue.StateHolder;
|
|
||||||
import org.mozilla.gecko.util.FileUtils;
|
import org.mozilla.gecko.util.FileUtils;
|
||||||
import org.mozilla.gecko.util.ThreadUtils;
|
import org.mozilla.gecko.util.ThreadUtils;
|
||||||
|
|
||||||
|
@ -80,11 +79,11 @@ public class GeckoThread extends Thread {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final StateHolder sStateHolder =
|
private static final NativeQueue sNativeQueue =
|
||||||
new StateHolder(State.INITIAL, State.RUNNING);
|
new NativeQueue(State.INITIAL, State.RUNNING);
|
||||||
|
|
||||||
/* package */ static StateHolder getStateHolder() {
|
/* package */ static NativeQueue getNativeQueue() {
|
||||||
return sStateHolder;
|
return sNativeQueue;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final State MIN_STATE = State.INITIAL;
|
public static final State MIN_STATE = State.INITIAL;
|
||||||
|
@ -446,7 +445,7 @@ public class GeckoThread extends Thread {
|
||||||
* @return True if the current Gecko thread state matches
|
* @return True if the current Gecko thread state matches
|
||||||
*/
|
*/
|
||||||
public static boolean isState(final State state) {
|
public static boolean isState(final State state) {
|
||||||
return sStateHolder.getState().is(state);
|
return sNativeQueue.getState().is(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -457,7 +456,7 @@ public class GeckoThread extends Thread {
|
||||||
* @return True if the current Gecko thread state matches
|
* @return True if the current Gecko thread state matches
|
||||||
*/
|
*/
|
||||||
public static boolean isStateAtLeast(final State state) {
|
public static boolean isStateAtLeast(final State state) {
|
||||||
return sStateHolder.getState().isAtLeast(state);
|
return sNativeQueue.getState().isAtLeast(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -468,7 +467,7 @@ public class GeckoThread extends Thread {
|
||||||
* @return True if the current Gecko thread state matches
|
* @return True if the current Gecko thread state matches
|
||||||
*/
|
*/
|
||||||
public static boolean isStateAtMost(final State state) {
|
public static boolean isStateAtMost(final State state) {
|
||||||
return state.isAtLeast(sStateHolder.getState());
|
return state.isAtLeast(sNativeQueue.getState());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -485,13 +484,13 @@ public class GeckoThread extends Thread {
|
||||||
|
|
||||||
@WrapForJNI(calledFrom = "gecko")
|
@WrapForJNI(calledFrom = "gecko")
|
||||||
private static void setState(final State newState) {
|
private static void setState(final State newState) {
|
||||||
sStateHolder.setState(newState);
|
sNativeQueue.setState(newState);
|
||||||
}
|
}
|
||||||
|
|
||||||
@WrapForJNI(calledFrom = "gecko")
|
@WrapForJNI(calledFrom = "gecko")
|
||||||
private static boolean checkAndSetState(final State expectedState,
|
private static boolean checkAndSetState(final State expectedState,
|
||||||
final State newState) {
|
final State newState) {
|
||||||
return sStateHolder.checkAndSetState(expectedState, newState);
|
return sNativeQueue.checkAndSetState(expectedState, newState);
|
||||||
}
|
}
|
||||||
|
|
||||||
@WrapForJNI(stubName = "SpeculativeConnect")
|
@WrapForJNI(stubName = "SpeculativeConnect")
|
||||||
|
@ -561,7 +560,7 @@ public class GeckoThread extends Thread {
|
||||||
*/
|
*/
|
||||||
public static void queueNativeCall(final Class<?> cls, final String methodName,
|
public static void queueNativeCall(final Class<?> cls, final String methodName,
|
||||||
final Object... args) {
|
final Object... args) {
|
||||||
NativeQueue.queueUntil(getStateHolder(), State.RUNNING, cls, methodName, args);
|
sNativeQueue.queueUntilReady(cls, methodName, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -569,7 +568,7 @@ public class GeckoThread extends Thread {
|
||||||
*/
|
*/
|
||||||
public static void queueNativeCall(final Object obj, final String methodName,
|
public static void queueNativeCall(final Object obj, final String methodName,
|
||||||
final Object... args) {
|
final Object... args) {
|
||||||
NativeQueue.queueUntil(getStateHolder(), State.RUNNING, obj, methodName, args);
|
sNativeQueue.queueUntilReady(obj, methodName, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -577,7 +576,7 @@ public class GeckoThread extends Thread {
|
||||||
*/
|
*/
|
||||||
public static void queueNativeCallUntil(final State state, final Object obj, final String methodName,
|
public static void queueNativeCallUntil(final State state, final Object obj, final String methodName,
|
||||||
final Object... args) {
|
final Object... args) {
|
||||||
NativeQueue.queueUntil(getStateHolder(), state, obj, methodName, args);
|
sNativeQueue.queueUntil(state, obj, methodName, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -585,6 +584,6 @@ public class GeckoThread extends Thread {
|
||||||
*/
|
*/
|
||||||
public static void queueNativeCallUntil(final State state, final Class<?> cls, final String methodName,
|
public static void queueNativeCallUntil(final State state, final Class<?> cls, final String methodName,
|
||||||
final Object... args) {
|
final Object... args) {
|
||||||
NativeQueue.queueUntil(getStateHolder(), state, cls, methodName, args);
|
sNativeQueue.queueUntil(state, cls, methodName, args);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,6 @@ import org.mozilla.gecko.annotation.ReflectionTarget;
|
||||||
import org.mozilla.gecko.annotation.WrapForJNI;
|
import org.mozilla.gecko.annotation.WrapForJNI;
|
||||||
import org.mozilla.gecko.gfx.LayerView;
|
import org.mozilla.gecko.gfx.LayerView;
|
||||||
import org.mozilla.gecko.mozglue.JNIObject;
|
import org.mozilla.gecko.mozglue.JNIObject;
|
||||||
import org.mozilla.gecko.NativeQueue.StateHolder;
|
|
||||||
import org.mozilla.gecko.util.BundleEventListener;
|
import org.mozilla.gecko.util.BundleEventListener;
|
||||||
import org.mozilla.gecko.util.EventCallback;
|
import org.mozilla.gecko.util.EventCallback;
|
||||||
import org.mozilla.gecko.util.GeckoBundle;
|
import org.mozilla.gecko.util.GeckoBundle;
|
||||||
|
@ -47,7 +46,7 @@ public class GeckoView extends LayerView
|
||||||
@WrapForJNI INITIAL(0),
|
@WrapForJNI INITIAL(0),
|
||||||
@WrapForJNI READY(1);
|
@WrapForJNI READY(1);
|
||||||
|
|
||||||
private int mRank;
|
private final int mRank;
|
||||||
|
|
||||||
private State(int rank) {
|
private State(int rank) {
|
||||||
mRank = rank;
|
mRank = rank;
|
||||||
|
@ -60,18 +59,16 @@ public class GeckoView extends LayerView
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isAtLeast(final NativeQueue.State other) {
|
public boolean isAtLeast(final NativeQueue.State other) {
|
||||||
if (other instanceof State) {
|
return (other instanceof State) &&
|
||||||
return mRank >= ((State) other).mRank;
|
mRank >= ((State) other).mRank;
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final StateHolder sDummyStateHolder =
|
private final NativeQueue mNativeQueue =
|
||||||
new StateHolder(State.INITIAL, State.READY);
|
new NativeQueue(State.INITIAL, State.READY);
|
||||||
|
|
||||||
private final EventDispatcher mEventDispatcher =
|
private final EventDispatcher mEventDispatcher =
|
||||||
new EventDispatcher(sDummyStateHolder);
|
new EventDispatcher(mNativeQueue);
|
||||||
|
|
||||||
private ChromeDelegate mChromeDelegate;
|
private ChromeDelegate mChromeDelegate;
|
||||||
/* package */ ContentListener mContentListener;
|
/* package */ ContentListener mContentListener;
|
||||||
|
@ -88,11 +85,12 @@ public class GeckoView extends LayerView
|
||||||
@WrapForJNI(dispatchTo = "proxy")
|
@WrapForJNI(dispatchTo = "proxy")
|
||||||
protected static final class Window extends JNIObject {
|
protected static final class Window extends JNIObject {
|
||||||
@WrapForJNI(skip = true)
|
@WrapForJNI(skip = true)
|
||||||
/* package */ final StateHolder mStateHolder =
|
/* package */ NativeQueue mNativeQueue;
|
||||||
new StateHolder(State.INITIAL, State.READY);
|
|
||||||
|
|
||||||
@WrapForJNI(skip = true)
|
@WrapForJNI(skip = true)
|
||||||
/* package */ Window() {}
|
/* package */ Window(final NativeQueue queue) {
|
||||||
|
mNativeQueue = queue;
|
||||||
|
}
|
||||||
|
|
||||||
static native void open(Window instance, GeckoView view,
|
static native void open(Window instance, GeckoView view,
|
||||||
Object compositor, EventDispatcher dispatcher,
|
Object compositor, EventDispatcher dispatcher,
|
||||||
|
@ -109,8 +107,8 @@ public class GeckoView extends LayerView
|
||||||
native void loadUri(String uri, int flags);
|
native void loadUri(String uri, int flags);
|
||||||
|
|
||||||
@WrapForJNI(calledFrom = "gecko")
|
@WrapForJNI(calledFrom = "gecko")
|
||||||
private void setState(final State newState) {
|
private synchronized void setState(final State newState) {
|
||||||
mStateHolder.setState(newState);
|
mNativeQueue.setState(newState);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -287,7 +285,12 @@ public class GeckoView extends LayerView
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void reattachWindow() {
|
protected void reattachWindow() {
|
||||||
mEventDispatcher.setStateHolder(mWindow.mStateHolder);
|
synchronized (mWindow) {
|
||||||
|
if (mNativeQueue != mWindow.mNativeQueue) {
|
||||||
|
mNativeQueue.setState(mWindow.mNativeQueue.getState());
|
||||||
|
mWindow.mNativeQueue = mNativeQueue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (GeckoThread.isStateAtLeast(GeckoThread.State.PROFILE_READY)) {
|
if (GeckoThread.isStateAtLeast(GeckoThread.State.PROFILE_READY)) {
|
||||||
mWindow.reattach(this, getCompositor(), mEventDispatcher);
|
mWindow.reattach(this, getCompositor(), mEventDispatcher);
|
||||||
|
@ -304,8 +307,7 @@ public class GeckoView extends LayerView
|
||||||
|
|
||||||
if (mWindow == null) {
|
if (mWindow == null) {
|
||||||
// Open a new nsWindow if we didn't have one from before.
|
// Open a new nsWindow if we didn't have one from before.
|
||||||
mWindow = new Window();
|
mWindow = new Window(mNativeQueue);
|
||||||
mEventDispatcher.setStateHolder(mWindow.mStateHolder);
|
|
||||||
openWindow();
|
openWindow();
|
||||||
} else {
|
} else {
|
||||||
reattachWindow();
|
reattachWindow();
|
||||||
|
@ -336,7 +338,6 @@ public class GeckoView extends LayerView
|
||||||
mWindow, "disposeNative");
|
mWindow, "disposeNative");
|
||||||
}
|
}
|
||||||
|
|
||||||
mEventDispatcher.setStateHolder(sDummyStateHolder);
|
|
||||||
mOnAttachedToWindowCalled = false;
|
mOnAttachedToWindowCalled = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,42 +20,34 @@ public class NativeQueue {
|
||||||
boolean isAtLeast(final State other);
|
boolean isAtLeast(final State other);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class StateHolder {
|
private volatile State mState;
|
||||||
private volatile State mState;
|
private final State mReadyState;
|
||||||
private final State mReadyState;
|
|
||||||
|
|
||||||
public StateHolder(final State initial, final State ready) {
|
public NativeQueue(final State initial, final State ready) {
|
||||||
this.mState = initial;
|
mState = initial;
|
||||||
this.mReadyState = ready;
|
mReadyState = ready;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isReady() {
|
public boolean isReady() {
|
||||||
return getState().isAtLeast(mReadyState);
|
return getState().isAtLeast(mReadyState);
|
||||||
}
|
}
|
||||||
|
|
||||||
public State getReadyState() {
|
public State getState() {
|
||||||
return mReadyState;
|
return mState;
|
||||||
}
|
}
|
||||||
|
|
||||||
public State getState() {
|
public boolean setState(final State newState) {
|
||||||
return mState;
|
return checkAndSetState(null, newState);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean setState(final State newState) {
|
public synchronized boolean checkAndSetState(final State expectedState,
|
||||||
return checkAndSetState(null, newState);
|
final State newState) {
|
||||||
}
|
if (expectedState != null && !mState.is(expectedState)) {
|
||||||
|
return false;
|
||||||
public boolean checkAndSetState(final State expectedState,
|
|
||||||
final State newState) {
|
|
||||||
synchronized (NativeQueue.sQueue) {
|
|
||||||
if (expectedState != null && !mState.is(expectedState)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
NativeQueue.flushQueuedLocked(newState);
|
|
||||||
mState = newState;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
flushQueuedLocked(newState);
|
||||||
|
mState = newState;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class QueuedCall {
|
private static class QueuedCall {
|
||||||
|
@ -74,7 +66,7 @@ public class NativeQueue {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final int QUEUED_CALLS_COUNT = 16;
|
private static final int QUEUED_CALLS_COUNT = 16;
|
||||||
/* package */ static final ArrayList<QueuedCall> sQueue =
|
/* package */ final ArrayList<QueuedCall> mQueue =
|
||||||
new ArrayList<>(QUEUED_CALLS_COUNT);
|
new ArrayList<>(QUEUED_CALLS_COUNT);
|
||||||
|
|
||||||
// Invoke the given Method and handle checked Exceptions.
|
// Invoke the given Method and handle checked Exceptions.
|
||||||
|
@ -91,12 +83,11 @@ public class NativeQueue {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Queue a call to the given method.
|
// Queue a call to the given method.
|
||||||
private static void queueNativeCallLocked(final StateHolder stateHolder,
|
private void queueNativeCallLocked(final Class<?> cls,
|
||||||
final Class<?> cls,
|
final String methodName,
|
||||||
final String methodName,
|
final Object obj,
|
||||||
final Object obj,
|
final Object[] args,
|
||||||
final Object[] args,
|
final State state) {
|
||||||
final State state) {
|
|
||||||
final ArrayList<Class<?>> argTypes = new ArrayList<>(args.length);
|
final ArrayList<Class<?>> argTypes = new ArrayList<>(args.length);
|
||||||
final ArrayList<Object> argValues = new ArrayList<>(args.length);
|
final ArrayList<Object> argValues = new ArrayList<>(args.length);
|
||||||
|
|
||||||
|
@ -135,63 +126,82 @@ public class NativeQueue {
|
||||||
throw new UnsupportedOperationException("Not allowed to queue non-native methods");
|
throw new UnsupportedOperationException("Not allowed to queue non-native methods");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stateHolder.getState().isAtLeast(state)) {
|
if (getState().isAtLeast(state)) {
|
||||||
invokeMethod(method, obj, argValues.toArray());
|
invokeMethod(method, obj, argValues.toArray());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
sQueue.add(new QueuedCall(
|
mQueue.add(new QueuedCall(
|
||||||
method, obj, argValues.toArray(), state));
|
method, obj, argValues.toArray(), state));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Queue a call to the given instance method if the given current state does
|
||||||
|
* not satisfy the isReady condition.
|
||||||
|
*
|
||||||
|
* @param obj Object that declares the instance method.
|
||||||
|
* @param methodName Name of the instance method.
|
||||||
|
* @param args Args to call the instance method with; to specify a parameter
|
||||||
|
* type, pass in a Class instance first, followed by the value.
|
||||||
|
*/
|
||||||
|
public synchronized void queueUntilReady(final Object obj,
|
||||||
|
final String methodName,
|
||||||
|
final Object... args) {
|
||||||
|
queueNativeCallLocked(obj.getClass(), methodName, obj, args, mReadyState);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Queue a call to the given static method if the given current state does
|
||||||
|
* not satisfy the isReady condition.
|
||||||
|
*
|
||||||
|
* @param cls Class that declares the static method.
|
||||||
|
* @param methodName Name of the instance method.
|
||||||
|
* @param args Args to call the instance method with; to specify a parameter
|
||||||
|
* type, pass in a Class instance first, followed by the value.
|
||||||
|
*/
|
||||||
|
public synchronized void queueUntilReady(final Class<?> cls,
|
||||||
|
final String methodName,
|
||||||
|
final Object... args) {
|
||||||
|
queueNativeCallLocked(cls, methodName, null, args, mReadyState);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Queue a call to the given instance method if the given current state does
|
* Queue a call to the given instance method if the given current state does
|
||||||
* not satisfy the given state.
|
* not satisfy the given state.
|
||||||
*
|
*
|
||||||
* @param stateHolder The state holder used to query the current state.
|
|
||||||
* @param state The state in which the native call could be executed.
|
* @param state The state in which the native call could be executed.
|
||||||
* @param obj Object that declares the instance method.
|
* @param obj Object that declares the instance method.
|
||||||
* @param methodName Name of the instance method.
|
* @param methodName Name of the instance method.
|
||||||
* @param args Args to call the instance method with; to specify a parameter
|
* @param args Args to call the instance method with; to specify a parameter
|
||||||
* type, pass in a Class instance first, followed by the value.
|
* type, pass in a Class instance first, followed by the value.
|
||||||
*/
|
*/
|
||||||
public static void queueUntil(final StateHolder stateHolder,
|
public synchronized void queueUntil(final State state, final Object obj,
|
||||||
final State state,
|
final String methodName,
|
||||||
final Object obj,
|
final Object... args) {
|
||||||
final String methodName,
|
queueNativeCallLocked(obj.getClass(), methodName, obj, args, state);
|
||||||
final Object... args) {
|
|
||||||
synchronized (sQueue) {
|
|
||||||
queueNativeCallLocked(stateHolder, obj.getClass(), methodName, obj,
|
|
||||||
args, state);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Queue a call to the given static method if the given current state does
|
* Queue a call to the given static method if the given current state does
|
||||||
* not satisfy the given state.
|
* not satisfy the given state.
|
||||||
*
|
*
|
||||||
* @param stateHolder The state holder used to query the current state.
|
|
||||||
* @param state The state in which the native call could be executed.
|
* @param state The state in which the native call could be executed.
|
||||||
* @param cls Class that declares the static method.
|
* @param cls Class that declares the static method.
|
||||||
* @param methodName Name of the instance method.
|
* @param methodName Name of the instance method.
|
||||||
* @param args Args to call the instance method with; to specify a parameter
|
* @param args Args to call the instance method with; to specify a parameter
|
||||||
* type, pass in a Class instance first, followed by the value.
|
* type, pass in a Class instance first, followed by the value.
|
||||||
*/
|
*/
|
||||||
public static void queueUntil(final StateHolder stateHolder,
|
public synchronized void queueUntil(final State state, final Class<?> cls,
|
||||||
final State state,
|
final String methodName,
|
||||||
final Class<?> cls,
|
final Object... args) {
|
||||||
final String methodName,
|
queueNativeCallLocked(cls, methodName, null, args, state);
|
||||||
final Object... args) {
|
|
||||||
synchronized (sQueue) {
|
|
||||||
queueNativeCallLocked(stateHolder, cls, methodName, null, args, state);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run all queued methods
|
// Run all queued methods
|
||||||
private static void flushQueuedLocked(final State state) {
|
private void flushQueuedLocked(final State state) {
|
||||||
int lastSkipped = -1;
|
int lastSkipped = -1;
|
||||||
for (int i = 0; i < sQueue.size(); i++) {
|
for (int i = 0; i < mQueue.size(); i++) {
|
||||||
final QueuedCall call = sQueue.get(i);
|
final QueuedCall call = mQueue.get(i);
|
||||||
if (call == null) {
|
if (call == null) {
|
||||||
// We already handled the call.
|
// We already handled the call.
|
||||||
continue;
|
continue;
|
||||||
|
@ -202,18 +212,18 @@ public class NativeQueue {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// Mark as handled.
|
// Mark as handled.
|
||||||
sQueue.set(i, null);
|
mQueue.set(i, null);
|
||||||
|
|
||||||
invokeMethod(call.method, call.target, call.args);
|
invokeMethod(call.method, call.target, call.args);
|
||||||
}
|
}
|
||||||
if (lastSkipped < 0) {
|
if (lastSkipped < 0) {
|
||||||
// We're done here; release the memory
|
// We're done here; release the memory
|
||||||
sQueue.clear();
|
mQueue.clear();
|
||||||
sQueue.trimToSize();
|
mQueue.trimToSize();
|
||||||
} else if (lastSkipped < sQueue.size() - 1) {
|
} else if (lastSkipped < mQueue.size() - 1) {
|
||||||
// We skipped some; free up null entries at the end,
|
// We skipped some; free up null entries at the end,
|
||||||
// but keep all the previous entries for later.
|
// but keep all the previous entries for later.
|
||||||
sQueue.subList(lastSkipped + 1, sQueue.size()).clear();
|
mQueue.subList(lastSkipped + 1, mQueue.size()).clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Загрузка…
Ссылка в новой задаче