private void track(MotionEvent event) { mX.saveTouchPos(); mY.saveTouchPos(); for (int i = 0; i < event.getHistorySize(); i++) { track( event.getHistoricalX(0, i), event.getHistoricalY(0, i), event.getHistoricalEventTime(i)); } track(event.getX(0), event.getY(0), event.getEventTime()); if (stopped()) { if (mState == PanZoomState.PANNING) { setState(PanZoomState.PANNING_HOLD); } else if (mState == PanZoomState.PANNING_LOCKED) { setState(PanZoomState.PANNING_HOLD_LOCKED); } else { // should never happen, but handle anyway for robustness Log.e(LOGTAG, "Impossible case " + mState + " when stopped in track"); setState(PanZoomState.PANNING_HOLD_LOCKED); } } mX.startPan(); mY.startPan(); updatePosition(); }
/** This function must be called from the UI thread. */ public void abortAnimation() { checkMainThread(); // this happens when gecko changes the viewport on us or if the device is rotated. // if that's the case, abort any animation in progress and re-zoom so that the page // snaps to edges. for other cases (where the user's finger(s) are down) don't do // anything special. switch (mState) { case FLING: mX.stopFling(); mY.stopFling(); // fall through case BOUNCE: case ANIMATED_ZOOM: // the zoom that's in progress likely makes no sense any more (such as if // the screen orientation changed) so abort it setState(PanZoomState.NOTHING); // fall through case NOTHING: // Don't do animations here; they're distracting and can cause flashes on page // transitions. synchronized (mTarget.getLock()) { mTarget.setViewportMetrics(getValidViewportMetrics()); } break; } }
private void fling() { updatePosition(); stopAnimationTimer(); boolean stopped = stopped(); mX.startFling(stopped); mY.startFling(stopped); startAnimationTimer(new FlingRunnable()); }
private void track(float x, float y, long time) { float timeDelta = (float) (time - mLastEventTime); if (FloatUtils.fuzzyEquals(timeDelta, 0)) { // probably a duplicate event, ignore it. using a zero timeDelta will mess // up our velocity return; } mLastEventTime = time; mX.updateWithTouchAt(x, timeDelta); mY.updateWithTouchAt(y, timeDelta); }
private void updatePosition() { mX.displace(); mY.displace(); PointF displacement = resetDisplacement(); if (FloatUtils.fuzzyEquals(displacement.x, 0.0f) && FloatUtils.fuzzyEquals(displacement.y, 0.0f)) { return; } if (!mSubscroller.scrollBy(displacement)) { synchronized (mTarget.getLock()) { scrollBy(displacement.x, displacement.y); } } }
public PanZoomController(PanZoomTarget target, EventDispatcher eventDispatcher) { mTarget = target; mSubscroller = new SubdocumentScrollHelper(this, eventDispatcher); mX = new AxisX(mSubscroller); mY = new AxisY(mSubscroller); mMainThread = GeckoApp.mAppContext.getMainLooper().getThread(); checkMainThread(); setState(PanZoomState.NOTHING); mEventDispatcher = eventDispatcher; registerEventListener(MESSAGE_ZOOM_RECT); registerEventListener(MESSAGE_ZOOM_PAGE); Axis.initPrefs(); }
private void startPanning(float x, float y, long time) { float dx = mX.panDistance(x); float dy = mY.panDistance(y); double angle = Math.atan2(dy, dx); // range [-pi, pi] angle = Math.abs(angle); // range [0, pi] // When the touch move breaks through the pan threshold, reposition the touch down origin // so the page won't jump when we start panning. mX.startTouch(x); mY.startTouch(y); mLastEventTime = time; if (!mX.scrollable() || !mY.scrollable()) { setState(PanZoomState.PANNING); } else if (angle < AXIS_LOCK_ANGLE || angle > (Math.PI - AXIS_LOCK_ANGLE)) { mY.setScrollingDisabled(true); setState(PanZoomState.PANNING_LOCKED); } else if (Math.abs(angle - (Math.PI / 2)) < AXIS_LOCK_ANGLE) { mX.setScrollingDisabled(true); setState(PanZoomState.PANNING_LOCKED); } else { setState(PanZoomState.PANNING); } }
@Override public boolean onScale(SimpleScaleGestureDetector detector) { if (GeckoApp.mAppContext == null || GeckoApp.mAppContext.mDOMFullScreen) return false; if (mState != PanZoomState.PINCHING) return false; float prevSpan = detector.getPreviousSpan(); if (FloatUtils.fuzzyEquals(prevSpan, 0.0f)) { // let's eat this one to avoid setting the new zoom to infinity (bug 711453) return true; } float spanRatio = detector.getCurrentSpan() / prevSpan; /* * Apply edge resistance if we're zoomed out smaller than the page size by scaling the zoom * factor toward 1.0. */ float resistance = Math.min(mX.getEdgeResistance(true), mY.getEdgeResistance(true)); if (spanRatio > 1.0f) spanRatio = 1.0f + (spanRatio - 1.0f) * resistance; else spanRatio = 1.0f - (1.0f - spanRatio) * resistance; synchronized (mTarget.getLock()) { float newZoomFactor = getMetrics().zoomFactor * spanRatio; float minZoomFactor = 0.0f; float maxZoomFactor = MAX_ZOOM; ZoomConstraints constraints = mTarget.getZoomConstraints(); if (constraints.getMinZoom() > 0) minZoomFactor = constraints.getMinZoom(); if (constraints.getMaxZoom() > 0) maxZoomFactor = constraints.getMaxZoom(); if (newZoomFactor < minZoomFactor) { // apply resistance when zooming past minZoomFactor, // such that it asymptotically reaches minZoomFactor / 2.0 // but never exceeds that final float rate = 0.5f; // controls how quickly we approach the limit float excessZoom = minZoomFactor - newZoomFactor; excessZoom = 1.0f - (float) Math.exp(-excessZoom * rate); newZoomFactor = minZoomFactor * (1.0f - excessZoom / 2.0f); } if (newZoomFactor > maxZoomFactor) { // apply resistance when zooming past maxZoomFactor, // such that it asymptotically reaches maxZoomFactor + 1.0 // but never exceeds that float excessZoom = newZoomFactor - maxZoomFactor; excessZoom = 1.0f - (float) Math.exp(-excessZoom); newZoomFactor = maxZoomFactor + excessZoom; } scrollBy(mLastZoomFocus.x - detector.getFocusX(), mLastZoomFocus.y - detector.getFocusY()); PointF focus = new PointF(detector.getFocusX(), detector.getFocusY()); scaleWithFocus(newZoomFactor, focus); } mLastZoomFocus.set(detector.getFocusX(), detector.getFocusY()); GeckoEvent event = GeckoEvent.createNativeGestureEvent( GeckoEvent.ACTION_MAGNIFY, mLastZoomFocus, getMetrics().zoomFactor); GeckoAppShell.sendEventToGecko(event); return true; }
PointF resetDisplacement() { return new PointF(mX.resetDisplacement(), mY.resetDisplacement()); }
public PointF getVelocityVector() { return new PointF(mX.getRealVelocity(), mY.getRealVelocity()); }
private float getVelocity() { float xvel = mX.getRealVelocity(); float yvel = mY.getRealVelocity(); return FloatMath.sqrt(xvel * xvel + yvel * yvel); }
private float panDistance(MotionEvent move) { float dx = mX.panDistance(move.getX(0)); float dy = mY.panDistance(move.getY(0)); return FloatMath.sqrt(dx * dx + dy * dy); }
private void startTouch(float x, float y, long time) { mX.startTouch(x); mY.startTouch(y); setState(PanZoomState.TOUCHING); mLastEventTime = time; }
public int getOverScrollMode() { return mX.getOverScrollMode(); }
public void setOverScrollMode(int overscrollMode) { mX.setOverScrollMode(overscrollMode); mY.setOverScrollMode(overscrollMode); }