mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-25 05:41:12 +00:00
Bug 1416310 - 3. Merge GeckoLayerClient into other classes; r=rbarker
Move the GeckoLayerClient JNI callbacks to LayerSession.Compositor. Move the rest of the viewport code to LayerView. Finally, move the input event synthesis code to NativePanZoomController. MozReview-Commit-ID: 1FEAM43KcwL --HG-- extra : rebase_source : af2ded170a79f13afbb1f690ae466e77c7145ff6
This commit is contained in:
parent
75a417ee33
commit
85057e2e9a
@ -48,13 +48,13 @@ public class DynamicToolbarAnimator {
|
||||
|
||||
private final Set<PinReason> mPinFlags = Collections.synchronizedSet(EnumSet.noneOf(PinReason.class));
|
||||
|
||||
private final GeckoLayerClient mTarget;
|
||||
private final LayerView mTarget;
|
||||
private LayerSession.Compositor mCompositor;
|
||||
private final List<MetricsListener> mListeners;
|
||||
private ToolbarChromeProxy mToolbarChromeProxy;
|
||||
private int mMaxToolbarHeight;
|
||||
|
||||
public DynamicToolbarAnimator(GeckoLayerClient aTarget) {
|
||||
public DynamicToolbarAnimator(final LayerView aTarget) {
|
||||
mTarget = aTarget;
|
||||
mListeners = new ArrayList<MetricsListener>();
|
||||
}
|
||||
@ -154,8 +154,8 @@ public class DynamicToolbarAnimator {
|
||||
/* package-private */ IntSize getViewportSize() {
|
||||
ThreadUtils.assertOnUiThread();
|
||||
|
||||
int viewWidth = mTarget.getView().getWidth();
|
||||
int viewHeight = mTarget.getView().getHeight();
|
||||
int viewWidth = mTarget.getWidth();
|
||||
int viewHeight = mTarget.getHeight();
|
||||
if ((mToolbarChromeProxy != null) && mToolbarChromeProxy.isToolbarChromeVisible()) {
|
||||
viewHeight -= mMaxToolbarHeight;
|
||||
}
|
||||
@ -163,8 +163,7 @@ public class DynamicToolbarAnimator {
|
||||
}
|
||||
|
||||
public PointF getVisibleEndOfLayerView() {
|
||||
return new PointF(mTarget.getView().getWidth(),
|
||||
mTarget.getView().getHeight());
|
||||
return new PointF(mTarget.getWidth(), mTarget.getHeight());
|
||||
}
|
||||
|
||||
/* package-private */ void updateCompositor() {
|
||||
|
@ -31,6 +31,8 @@ public class LayerSession {
|
||||
protected class Compositor extends JNIObject {
|
||||
public LayerView layerView;
|
||||
|
||||
private volatile boolean mContentDocumentIsDisplayed;
|
||||
|
||||
public boolean isReady() {
|
||||
return LayerSession.this.isCompositorReady();
|
||||
}
|
||||
@ -55,8 +57,7 @@ public class LayerSession {
|
||||
@Override protected native void disposeNative();
|
||||
|
||||
@WrapForJNI(calledFrom = "any", dispatchTo = "gecko")
|
||||
public native void attachToJava(GeckoLayerClient layerClient,
|
||||
NativePanZoomController npzc);
|
||||
public native void attachToJava(NativePanZoomController npzc);
|
||||
|
||||
@WrapForJNI(calledFrom = "ui", dispatchTo = "gecko")
|
||||
public native void onBoundsChanged(int left, int top, int width, int height);
|
||||
@ -127,6 +128,28 @@ public class LayerSession {
|
||||
@WrapForJNI(calledFrom = "ui", dispatchTo = "current")
|
||||
public native void sendToolbarPixelsToCompositor(final int width, final int height,
|
||||
final int[] pixels);
|
||||
|
||||
@WrapForJNI(calledFrom = "gecko")
|
||||
private void contentDocumentChanged() {
|
||||
mContentDocumentIsDisplayed = false;
|
||||
}
|
||||
|
||||
@WrapForJNI(calledFrom = "gecko")
|
||||
private boolean isContentDocumentDisplayed() {
|
||||
return mContentDocumentIsDisplayed;
|
||||
}
|
||||
|
||||
// The compositor invokes this function just before compositing a frame where the
|
||||
// document is different from the document composited on the last frame. In these
|
||||
// cases, the viewport information we have in Java is no longer valid and needs to
|
||||
// be replaced with the new viewport information provided.
|
||||
@WrapForJNI(calledFrom = "ui")
|
||||
public void updateRootFrameMetrics(float scrollX, float scrollY, float zoom) {
|
||||
mContentDocumentIsDisplayed = true;
|
||||
if (layerView != null) {
|
||||
layerView.onMetricsChanged(scrollX, scrollY, zoom);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected final Compositor mCompositor = new Compositor();
|
||||
|
@ -49,12 +49,12 @@ public class LayerView extends FrameLayout {
|
||||
|
||||
private static AccessibilityManager sAccessibilityManager;
|
||||
|
||||
private GeckoLayerClient mLayerClient;
|
||||
private PanZoomController mPanZoomController;
|
||||
private DynamicToolbarAnimator mToolbarAnimator;
|
||||
private FullScreenState mFullScreenState;
|
||||
|
||||
private Listener mListener;
|
||||
// Accessed on UI thread.
|
||||
private ImmutableViewportMetrics mViewportMetrics;
|
||||
|
||||
/* This should only be modified on the Java UI thread. */
|
||||
private final Overscroll mOverscroll;
|
||||
@ -117,13 +117,13 @@ public class LayerView extends FrameLayout {
|
||||
case STATIC_TOOLBAR_READY:
|
||||
// Hide toolbar and send TOOLBAR_HIDDEN message to compositor
|
||||
mToolbarAnimator.onToggleChrome(false);
|
||||
mListener.surfaceChanged();
|
||||
adjustViewportSize();
|
||||
postCompositorMessage(TOOLBAR_HIDDEN);
|
||||
break;
|
||||
case TOOLBAR_SHOW:
|
||||
// Show toolbar.
|
||||
mToolbarAnimator.onToggleChrome(true);
|
||||
mListener.surfaceChanged();
|
||||
adjustViewportSize();
|
||||
postCompositorMessage(TOOLBAR_VISIBLE);
|
||||
break;
|
||||
case FIRST_PAINT:
|
||||
@ -166,13 +166,14 @@ public class LayerView extends FrameLayout {
|
||||
}
|
||||
|
||||
public void initializeView() {
|
||||
mLayerClient = new GeckoLayerClient(this);
|
||||
mToolbarAnimator = new DynamicToolbarAnimator(this);
|
||||
mPanZoomController = PanZoomController.Factory.create(this);
|
||||
if (mOverscroll != null) {
|
||||
mLayerClient.setOverscrollHandler(mOverscroll);
|
||||
mPanZoomController.setOverscrollHandler(mOverscroll);
|
||||
}
|
||||
|
||||
mPanZoomController = mLayerClient.getPanZoomController();
|
||||
mToolbarAnimator = mLayerClient.getDynamicToolbarAnimator();
|
||||
mViewportMetrics = new ImmutableViewportMetrics()
|
||||
.setViewportSize(getWidth(), getHeight());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -195,9 +196,9 @@ public class LayerView extends FrameLayout {
|
||||
(int)event.getToolMinor() / 2);
|
||||
}
|
||||
|
||||
public void destroy() {
|
||||
if (mLayerClient != null) {
|
||||
mLayerClient.destroy();
|
||||
protected void destroy() {
|
||||
if (mPanZoomController != null) {
|
||||
mPanZoomController.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
@ -206,7 +207,7 @@ public class LayerView extends FrameLayout {
|
||||
super.dispatchDraw(canvas);
|
||||
|
||||
// We must have a layer client to get valid viewport metrics
|
||||
if (mLayerClient != null && mOverscroll != null) {
|
||||
if (mOverscroll != null) {
|
||||
mOverscroll.draw(canvas, getViewportMetrics());
|
||||
}
|
||||
}
|
||||
@ -273,14 +274,11 @@ public class LayerView extends FrameLayout {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Don't expose GeckoLayerClient to things outside this package; only expose it as an Object
|
||||
GeckoLayerClient getLayerClient() { return mLayerClient; }
|
||||
|
||||
public PanZoomController getPanZoomController() { return mPanZoomController; }
|
||||
public DynamicToolbarAnimator getDynamicToolbarAnimator() { return mToolbarAnimator; }
|
||||
|
||||
public ImmutableViewportMetrics getViewportMetrics() {
|
||||
return mLayerClient.getViewportMetrics();
|
||||
return mViewportMetrics;
|
||||
}
|
||||
|
||||
public void setSurfaceBackgroundColor(int newColor) {
|
||||
@ -317,28 +315,23 @@ public class LayerView extends FrameLayout {
|
||||
}
|
||||
}
|
||||
|
||||
public void setListener(Listener listener) {
|
||||
mListener = listener;
|
||||
}
|
||||
|
||||
Listener getListener() {
|
||||
return mListener;
|
||||
}
|
||||
|
||||
protected void attachCompositor(final LayerSession session) {
|
||||
mCompositor = session.mCompositor;
|
||||
mCompositor.layerView = this;
|
||||
|
||||
// Reset the content-document-is-displayed flag.
|
||||
mCompositor.updateRootFrameMetrics(/* scroolX */ 0, /* scrollY */ 0,
|
||||
/* zoom */ 1.0f);
|
||||
|
||||
mToolbarAnimator.notifyCompositorCreated(mCompositor);
|
||||
|
||||
final NativePanZoomController npzc = (NativePanZoomController) mPanZoomController;
|
||||
|
||||
if (GeckoThread.isStateAtLeast(GeckoThread.State.PROFILE_READY)) {
|
||||
mCompositor.attachToJava(mLayerClient, npzc);
|
||||
mCompositor.attachToJava(npzc);
|
||||
} else {
|
||||
GeckoThread.queueNativeCallUntil(GeckoThread.State.PROFILE_READY,
|
||||
mCompositor, "attachToJava",
|
||||
GeckoLayerClient.class, mLayerClient,
|
||||
NativePanZoomController.class, npzc);
|
||||
}
|
||||
}
|
||||
@ -348,18 +341,31 @@ public class LayerView extends FrameLayout {
|
||||
return isCompositorReady() ? mCompositor : null;
|
||||
}
|
||||
|
||||
/* package */ void onSizeChanged(int width, int height) {
|
||||
if (mListener != null) {
|
||||
mListener.surfaceChanged();
|
||||
private void adjustViewportSize() {
|
||||
final IntSize viewportSize = mToolbarAnimator.getViewportSize();
|
||||
|
||||
if (mViewportMetrics.viewportRectWidth == viewportSize.width &&
|
||||
mViewportMetrics.viewportRectHeight == viewportSize.height) {
|
||||
return;
|
||||
}
|
||||
|
||||
mViewportMetrics = mViewportMetrics.setViewportSize(viewportSize.width,
|
||||
viewportSize.height);
|
||||
}
|
||||
|
||||
/* package */ void onSizeChanged(int width, int height) {
|
||||
adjustViewportSize();
|
||||
|
||||
if (mOverscroll != null) {
|
||||
mOverscroll.setSize(width, height);
|
||||
}
|
||||
}
|
||||
|
||||
public interface Listener {
|
||||
void surfaceChanged();
|
||||
/* package */ void onMetricsChanged(final float scrollX, final float scrollY,
|
||||
final float zoom) {
|
||||
mViewportMetrics = mViewportMetrics.setViewportOrigin(scrollX, scrollY)
|
||||
.setZoomFactor(zoom);
|
||||
mToolbarAnimator.onMetricsChanged(mViewportMetrics);
|
||||
}
|
||||
|
||||
@RobocopTarget
|
||||
@ -410,7 +416,7 @@ public class LayerView extends FrameLayout {
|
||||
}
|
||||
|
||||
public float getZoomFactor() {
|
||||
return getLayerClient().getViewportMetrics().zoomFactor;
|
||||
return getViewportMetrics().zoomFactor;
|
||||
}
|
||||
|
||||
public void setFullScreenState(FullScreenState state) {
|
||||
|
@ -13,13 +13,18 @@ import org.mozilla.gecko.util.ThreadUtils;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import android.graphics.PointF;
|
||||
import android.os.SystemClock;
|
||||
import android.util.Log;
|
||||
import android.util.TypedValue;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.InputDevice;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
class NativePanZoomController extends JNIObject implements PanZoomController {
|
||||
private static final String LOGTAG = "GeckoNPZC";
|
||||
private final float MAX_SCROLL;
|
||||
|
||||
private final LayerView mView;
|
||||
@ -29,6 +34,8 @@ class NativePanZoomController extends JNIObject implements PanZoomController {
|
||||
private float mPointerScrollFactor;
|
||||
private long mLastDownTime;
|
||||
|
||||
private SynthesizedEventState mPointerState;
|
||||
|
||||
@WrapForJNI(calledFrom = "ui")
|
||||
private native boolean handleMotionEvent(
|
||||
int action, int actionIndex, long time, int metaState,
|
||||
@ -256,4 +263,231 @@ class NativePanZoomController extends JNIObject implements PanZoomController {
|
||||
private void onSelectionDragState(boolean state) {
|
||||
mView.getDynamicToolbarAnimator().setPinned(state, PinReason.CARET_DRAG);
|
||||
}
|
||||
|
||||
private static class PointerInfo {
|
||||
// We reserve one pointer ID for the mouse, so that tests don't have
|
||||
// to worry about tracking pointer IDs if they just want to test mouse
|
||||
// event synthesization. If somebody tries to use this ID for a
|
||||
// synthesized touch event we'll throw an exception.
|
||||
public static final int RESERVED_MOUSE_POINTER_ID = 100000;
|
||||
|
||||
public int pointerId;
|
||||
public int source;
|
||||
public int screenX;
|
||||
public int screenY;
|
||||
public double pressure;
|
||||
public int orientation;
|
||||
|
||||
public MotionEvent.PointerCoords getCoords() {
|
||||
MotionEvent.PointerCoords coords = new MotionEvent.PointerCoords();
|
||||
coords.orientation = orientation;
|
||||
coords.pressure = (float)pressure;
|
||||
coords.x = screenX;
|
||||
coords.y = screenY;
|
||||
return coords;
|
||||
}
|
||||
}
|
||||
|
||||
private static class SynthesizedEventState {
|
||||
public final ArrayList<PointerInfo> pointers;
|
||||
public long downTime;
|
||||
|
||||
SynthesizedEventState() {
|
||||
pointers = new ArrayList<PointerInfo>();
|
||||
}
|
||||
|
||||
int getPointerIndex(int pointerId) {
|
||||
for (int i = 0; i < pointers.size(); i++) {
|
||||
if (pointers.get(i).pointerId == pointerId) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int addPointer(int pointerId, int source) {
|
||||
PointerInfo info = new PointerInfo();
|
||||
info.pointerId = pointerId;
|
||||
info.source = source;
|
||||
pointers.add(info);
|
||||
return pointers.size() - 1;
|
||||
}
|
||||
|
||||
int getPointerCount(int source) {
|
||||
int count = 0;
|
||||
for (int i = 0; i < pointers.size(); i++) {
|
||||
if (pointers.get(i).source == source) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
MotionEvent.PointerProperties[] getPointerProperties(int source) {
|
||||
MotionEvent.PointerProperties[] props =
|
||||
new MotionEvent.PointerProperties[getPointerCount(source)];
|
||||
int index = 0;
|
||||
for (int i = 0; i < pointers.size(); i++) {
|
||||
if (pointers.get(i).source == source) {
|
||||
MotionEvent.PointerProperties p = new MotionEvent.PointerProperties();
|
||||
p.id = pointers.get(i).pointerId;
|
||||
switch (source) {
|
||||
case InputDevice.SOURCE_TOUCHSCREEN:
|
||||
p.toolType = MotionEvent.TOOL_TYPE_FINGER;
|
||||
break;
|
||||
case InputDevice.SOURCE_MOUSE:
|
||||
p.toolType = MotionEvent.TOOL_TYPE_MOUSE;
|
||||
break;
|
||||
}
|
||||
props[index++] = p;
|
||||
}
|
||||
}
|
||||
return props;
|
||||
}
|
||||
|
||||
MotionEvent.PointerCoords[] getPointerCoords(int source) {
|
||||
MotionEvent.PointerCoords[] coords =
|
||||
new MotionEvent.PointerCoords[getPointerCount(source)];
|
||||
int index = 0;
|
||||
for (int i = 0; i < pointers.size(); i++) {
|
||||
if (pointers.get(i).source == source) {
|
||||
coords[index++] = pointers.get(i).getCoords();
|
||||
}
|
||||
}
|
||||
return coords;
|
||||
}
|
||||
}
|
||||
|
||||
private void synthesizeNativePointer(int source, int pointerId, int eventType,
|
||||
int screenX, int screenY, double pressure,
|
||||
int orientation)
|
||||
{
|
||||
final View view = mView;
|
||||
final int[] origin = new int[2];
|
||||
view.getLocationOnScreen(origin);
|
||||
screenX -= origin[0];
|
||||
screenY -= origin[1];
|
||||
|
||||
if (mPointerState == null) {
|
||||
mPointerState = new SynthesizedEventState();
|
||||
}
|
||||
|
||||
// Find the pointer if it already exists
|
||||
int pointerIndex = mPointerState.getPointerIndex(pointerId);
|
||||
|
||||
// Event-specific handling
|
||||
switch (eventType) {
|
||||
case MotionEvent.ACTION_POINTER_UP:
|
||||
if (pointerIndex < 0) {
|
||||
Log.w(LOGTAG, "Pointer-up for invalid pointer");
|
||||
return;
|
||||
}
|
||||
if (mPointerState.pointers.size() == 1) {
|
||||
// Last pointer is going up
|
||||
eventType = MotionEvent.ACTION_UP;
|
||||
}
|
||||
break;
|
||||
case MotionEvent.ACTION_CANCEL:
|
||||
if (pointerIndex < 0) {
|
||||
Log.w(LOGTAG, "Pointer-cancel for invalid pointer");
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case MotionEvent.ACTION_POINTER_DOWN:
|
||||
if (pointerIndex < 0) {
|
||||
// Adding a new pointer
|
||||
pointerIndex = mPointerState.addPointer(pointerId, source);
|
||||
if (pointerIndex == 0) {
|
||||
// first pointer
|
||||
eventType = MotionEvent.ACTION_DOWN;
|
||||
mPointerState.downTime = SystemClock.uptimeMillis();
|
||||
}
|
||||
} else {
|
||||
// We're moving an existing pointer
|
||||
eventType = MotionEvent.ACTION_MOVE;
|
||||
}
|
||||
break;
|
||||
case MotionEvent.ACTION_HOVER_MOVE:
|
||||
if (pointerIndex < 0) {
|
||||
// Mouse-move a pointer without it going "down". However
|
||||
// in order to send the right MotionEvent without a lot of
|
||||
// duplicated code, we add the pointer to mPointerState,
|
||||
// and then remove it at the bottom of this function.
|
||||
pointerIndex = mPointerState.addPointer(pointerId, source);
|
||||
} else {
|
||||
// We're moving an existing mouse pointer that went down.
|
||||
eventType = MotionEvent.ACTION_MOVE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// Update the pointer with the new info
|
||||
PointerInfo info = mPointerState.pointers.get(pointerIndex);
|
||||
info.screenX = screenX;
|
||||
info.screenY = screenY;
|
||||
info.pressure = pressure;
|
||||
info.orientation = orientation;
|
||||
|
||||
// Dispatch the event
|
||||
int action = 0;
|
||||
if (eventType == MotionEvent.ACTION_POINTER_DOWN ||
|
||||
eventType == MotionEvent.ACTION_POINTER_UP) {
|
||||
// for pointer-down and pointer-up events we need to add the
|
||||
// index of the relevant pointer.
|
||||
action = (pointerIndex << MotionEvent.ACTION_POINTER_INDEX_SHIFT);
|
||||
action &= MotionEvent.ACTION_POINTER_INDEX_MASK;
|
||||
}
|
||||
action |= (eventType & MotionEvent.ACTION_MASK);
|
||||
boolean isButtonDown = (source == InputDevice.SOURCE_MOUSE) &&
|
||||
(eventType == MotionEvent.ACTION_DOWN ||
|
||||
eventType == MotionEvent.ACTION_MOVE);
|
||||
final MotionEvent event = MotionEvent.obtain(
|
||||
/*downTime*/ mPointerState.downTime,
|
||||
/*eventTime*/ SystemClock.uptimeMillis(),
|
||||
/*action*/ action,
|
||||
/*pointerCount*/ mPointerState.getPointerCount(source),
|
||||
/*pointerProperties*/ mPointerState.getPointerProperties(source),
|
||||
/*pointerCoords*/ mPointerState.getPointerCoords(source),
|
||||
/*metaState*/ 0,
|
||||
/*buttonState*/ (isButtonDown ? MotionEvent.BUTTON_PRIMARY : 0),
|
||||
/*xPrecision*/ 0,
|
||||
/*yPrecision*/ 0,
|
||||
/*deviceId*/ 0,
|
||||
/*edgeFlags*/ 0,
|
||||
/*source*/ source,
|
||||
/*flags*/ 0);
|
||||
view.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
view.dispatchTouchEvent(event);
|
||||
}
|
||||
});
|
||||
|
||||
// Forget about removed pointers
|
||||
if (eventType == MotionEvent.ACTION_POINTER_UP ||
|
||||
eventType == MotionEvent.ACTION_UP ||
|
||||
eventType == MotionEvent.ACTION_CANCEL ||
|
||||
eventType == MotionEvent.ACTION_HOVER_MOVE)
|
||||
{
|
||||
mPointerState.pointers.remove(pointerIndex);
|
||||
}
|
||||
}
|
||||
|
||||
@WrapForJNI(calledFrom = "gecko")
|
||||
private void synthesizeNativeTouchPoint(int pointerId, int eventType, int screenX,
|
||||
int screenY, double pressure, int orientation)
|
||||
{
|
||||
if (pointerId == PointerInfo.RESERVED_MOUSE_POINTER_ID) {
|
||||
throw new IllegalArgumentException("Pointer ID reserved for mouse");
|
||||
}
|
||||
synthesizeNativePointer(InputDevice.SOURCE_TOUCHSCREEN, pointerId,
|
||||
eventType, screenX, screenY, pressure, orientation);
|
||||
}
|
||||
|
||||
@WrapForJNI(calledFrom = "gecko")
|
||||
private void synthesizeNativeMouseEvent(int eventType, int screenX, int screenY) {
|
||||
synthesizeNativePointer(InputDevice.SOURCE_MOUSE,
|
||||
PointerInfo.RESERVED_MOUSE_POINTER_ID,
|
||||
eventType, screenX, screenY, 0, 0);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user