diff --git a/mobile/android/base/gfx/JavaPanZoomController.java b/mobile/android/base/gfx/JavaPanZoomController.java index 0b74ef290499..bde80ae5e517 100644 --- a/mobile/android/base/gfx/JavaPanZoomController.java +++ b/mobile/android/base/gfx/JavaPanZoomController.java @@ -66,6 +66,9 @@ class JavaPanZoomController // The maximum amount we would like to scroll with the mouse private static final float MAX_SCROLL = 0.075f * GeckoAppShell.getDpi(); + // The maximum zoom factor adjustment per frame of the AUTONAV animation + private static final float MAX_ZOOM_DELTA = 0.125f; + private enum PanZoomState { NOTHING, /* no touch-start events received */ FLING, /* all touches removed, but we're still scrolling page */ @@ -104,6 +107,8 @@ class JavaPanZoomController private long mLastEventTime; /* Current state the pan/zoom UI is in. */ private PanZoomState mState; + /* The per-frame zoom delta for the currently-running AUTONAV animation. */ + private float mAutonavZoomDelta; public JavaPanZoomController(PanZoomTarget target, View view, EventDispatcher eventDispatcher) { mTarget = target; @@ -252,7 +257,7 @@ class JavaPanZoomController break; case InputDevice.SOURCE_CLASS_JOYSTICK: switch (event.getAction() & MotionEvent.ACTION_MASK) { - case MotionEvent.ACTION_MOVE: return handleJoystickScroll(event); + case MotionEvent.ACTION_MOVE: return handleJoystickNav(event); } break; } @@ -502,24 +507,36 @@ class JavaPanZoomController return false; } - private float normalizeJoystick(float value, InputDevice.MotionRange range) { + private float filterDeadZone(float value, InputDevice.MotionRange range) { // The 1e-2 here should really be range.getFlat() + range.getFuzz() but the // values those functions return on the Ouya are zero so we're just hard-coding // it for now. if (Math.abs(value) < 1e-2) { return 0; } - // joystick axis positions are already normalized to [-1, 1] so just scale it up by how much we want - return value * MAX_SCROLL; + return value; + } + + private float normalizeJoystickScroll(float value, InputDevice.MotionRange range) { + return filterDeadZone(value, range) * MAX_SCROLL; + } + + private float normalizeJoystickZoom(float value, InputDevice.MotionRange range) { + // negate MAX_ZOOM_DELTA so that pushing up on the stick zooms in + return filterDeadZone(value, range) * -MAX_ZOOM_DELTA; } // Since this event is a position-based event rather than a motion-based event, we need to // set up an AUTONAV animation to keep scrolling even while we don't get events. - private boolean handleJoystickScroll(MotionEvent event) { - float velocityX = normalizeJoystick(event.getX(0), event.getDevice().getMotionRange(MotionEvent.AXIS_X)); - float velocityY = normalizeJoystick(event.getY(0), event.getDevice().getMotionRange(MotionEvent.AXIS_Y)); + private boolean handleJoystickNav(MotionEvent event) { + float velocityX = normalizeJoystickScroll(event.getAxisValue(MotionEvent.AXIS_X), + event.getDevice().getMotionRange(MotionEvent.AXIS_X)); + float velocityY = normalizeJoystickScroll(event.getAxisValue(MotionEvent.AXIS_Y), + event.getDevice().getMotionRange(MotionEvent.AXIS_Y)); + float zoomDelta = normalizeJoystickZoom(event.getAxisValue(MotionEvent.AXIS_RZ), + event.getDevice().getMotionRange(MotionEvent.AXIS_RZ)); - if (velocityX == 0 && velocityY == 0) { + if (velocityX == 0 && velocityY == 0 && zoomDelta == 0) { if (mState == PanZoomState.AUTONAV) { bounce(); // if not needed, this will automatically go to state NOTHING return true; @@ -534,6 +551,7 @@ class JavaPanZoomController if (mState == PanZoomState.AUTONAV) { mX.setAutoscrollVelocity(velocityX); mY.setAutoscrollVelocity(velocityY); + mAutonavZoomDelta = zoomDelta; return true; } return false; @@ -755,6 +773,9 @@ class JavaPanZoomController } updatePosition(); + synchronized (mTarget.getLock()) { + mTarget.setViewportMetrics(applyZoomDelta(getMetrics(), mAutonavZoomDelta)); + } } } @@ -1031,17 +1052,22 @@ class JavaPanZoomController return true; } + private ImmutableViewportMetrics applyZoomDelta(ImmutableViewportMetrics metrics, float zoomDelta) { + float oldZoom = metrics.zoomFactor; + float newZoom = oldZoom + zoomDelta; + float adjustedZoom = getAdjustedZoomFactor(newZoom / oldZoom); + // since we don't have a particular focus to zoom to, just use the center + PointF center = new PointF(metrics.getWidth() / 2.0f, metrics.getHeight() / 2.0f); + metrics = metrics.scaleTo(adjustedZoom, center); + return metrics; + } + private boolean animatedScale(float zoomDelta) { if (mState != PanZoomState.NOTHING && mState != PanZoomState.BOUNCE) { return false; } synchronized (mTarget.getLock()) { - ImmutableViewportMetrics metrics = getMetrics(); - float oldZoom = metrics.zoomFactor; - float newZoom = oldZoom + zoomDelta; - float adjustedZoom = getAdjustedZoomFactor(newZoom / oldZoom); - PointF center = new PointF(metrics.getWidth() / 2.0f, metrics.getHeight() / 2.0f); - metrics = metrics.scaleTo(adjustedZoom, center); + ImmutableViewportMetrics metrics = applyZoomDelta(getMetrics(), zoomDelta); bounce(getValidViewportMetrics(metrics), PanZoomState.BOUNCE); } return true;