Exemplo n.º 1
0
 /** 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;
   }
 }
Exemplo n.º 2
0
  public void handleMessage(String event, JSONObject message) {
    try {
      if (MESSAGE_ZOOM_RECT.equals(event)) {
        float x = (float) message.getDouble("x");
        float y = (float) message.getDouble("y");
        final RectF zoomRect =
            new RectF(x, y, x + (float) message.getDouble("w"), y + (float) message.getDouble("h"));
        mTarget.post(
            new Runnable() {
              public void run() {
                animatedZoomTo(zoomRect);
              }
            });
      } else if (MESSAGE_ZOOM_PAGE.equals(event)) {
        ImmutableViewportMetrics metrics = getMetrics();
        RectF cssPageRect = metrics.getCssPageRect();

        RectF viewableRect = metrics.getCssViewport();
        float y = viewableRect.top;
        // attempt to keep zoom keep focused on the center of the viewport
        float newHeight = viewableRect.height() * cssPageRect.width() / viewableRect.width();
        float dh = viewableRect.height() - newHeight; // increase in the height
        final RectF r = new RectF(0.0f, y + dh / 2, cssPageRect.width(), y + dh / 2 + newHeight);
        mTarget.post(
            new Runnable() {
              public void run() {
                animatedZoomTo(r);
              }
            });
      }
    } catch (Exception e) {
      Log.e(LOGTAG, "Exception handling message \"" + event + "\":", e);
    }
  }
Exemplo n.º 3
0
 /** This must be called on the UI thread. */
 public void pageRectUpdated() {
   if (mState == PanZoomState.NOTHING) {
     synchronized (mTarget.getLock()) {
       ImmutableViewportMetrics validated = getValidViewportMetrics();
       if (!getMetrics().fuzzyEquals(validated)) {
         // page size changed such that we are now in overscroll. snap to the
         // the nearest valid viewport
         mTarget.setViewportMetrics(validated);
       }
     }
   }
 }
Exemplo n.º 4
0
  private boolean onTouchStart(MotionEvent event) {
    // user is taking control of movement, so stop
    // any auto-movement we have going
    stopAnimationTimer();

    switch (mState) {
      case ANIMATED_ZOOM:
        // We just interrupted a double-tap animation, so force a redraw in
        // case this touchstart is just a tap that doesn't end up triggering
        // a redraw
        mTarget.setForceRedraw();
        // fall through
      case FLING:
      case BOUNCE:
      case NOTHING:
      case WAITING_LISTENERS:
        startTouch(event.getX(0), event.getY(0), event.getEventTime());
        return false;
      case TOUCHING:
      case PANNING:
      case PANNING_LOCKED:
      case PANNING_HOLD:
      case PANNING_HOLD_LOCKED:
      case PINCHING:
        Log.e(LOGTAG, "Received impossible touch down while in " + mState);
        return false;
    }
    Log.e(LOGTAG, "Unhandled case " + mState + " in onTouchStart");
    return false;
  }
Exemplo n.º 5
0
 @Override
 public boolean onDoubleTap(MotionEvent motionEvent) {
   if (mTarget.getZoomConstraints().getAllowZoom()) {
     sendPointToGecko("Gesture:DoubleTap", motionEvent);
   }
   return true;
 }
Exemplo n.º 6
0
 @Override
 public boolean onSingleTapConfirmed(MotionEvent motionEvent) {
   // When zooming is disabled, we handle this in onSingleTapUp.
   if (mTarget.getZoomConstraints().getAllowZoom()) {
     sendPointToGecko("Gesture:SingleTap", motionEvent);
   }
   return true;
 }
Exemplo n.º 7
0
  private void finishAnimation() {
    checkMainThread();

    stopAnimationTimer();

    // Force a viewport synchronisation
    mTarget.setForceRedraw();
  }
Exemplo n.º 8
0
 @Override
 public boolean onSingleTapUp(MotionEvent motionEvent) {
   // When zooming is enabled, wait to see if there's a double-tap.
   if (!mTarget.getZoomConstraints().getAllowZoom()) {
     sendPointToGecko("Gesture:SingleTap", motionEvent);
   }
   // return false because we still want to get the ACTION_UP event that triggers this
   return false;
 }
Exemplo n.º 9
0
  private ImmutableViewportMetrics getValidViewportMetrics(
      ImmutableViewportMetrics viewportMetrics) {
    /* First, we adjust the zoom factor so that we can make no overscrolled area visible. */
    float zoomFactor = viewportMetrics.zoomFactor;
    RectF pageRect = viewportMetrics.getPageRect();
    RectF viewport = viewportMetrics.getViewport();

    float focusX = viewport.width() / 2.0f;
    float focusY = viewport.height() / 2.0f;

    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 (!constraints.getAllowZoom()) {
      // If allowZoom is false, clamp to the default zoom level.
      maxZoomFactor = minZoomFactor = constraints.getDefaultZoom();
    }

    // Ensure minZoomFactor keeps the page at least as big as the viewport.
    if (pageRect.width() > 0) {
      float scaleFactor = viewport.width() / pageRect.width();
      minZoomFactor = Math.max(minZoomFactor, zoomFactor * scaleFactor);
      if (viewport.width() > pageRect.width()) focusX = 0.0f;
    }
    if (pageRect.height() > 0) {
      float scaleFactor = viewport.height() / pageRect.height();
      minZoomFactor = Math.max(minZoomFactor, zoomFactor * scaleFactor);
      if (viewport.height() > pageRect.height()) focusY = 0.0f;
    }

    maxZoomFactor = Math.max(maxZoomFactor, minZoomFactor);

    if (zoomFactor < minZoomFactor) {
      // if one (or both) of the page dimensions is smaller than the viewport,
      // zoom using the top/left as the focus on that axis. this prevents the
      // scenario where, if both dimensions are smaller than the viewport, but
      // by different scale factors, we end up scrolled to the end on one axis
      // after applying the scale
      PointF center = new PointF(focusX, focusY);
      viewportMetrics = viewportMetrics.scaleTo(minZoomFactor, center);
    } else if (zoomFactor > maxZoomFactor) {
      PointF center = new PointF(viewport.width() / 2.0f, viewport.height() / 2.0f);
      viewportMetrics = viewportMetrics.scaleTo(maxZoomFactor, center);
    }

    /* Now we pan to the right origin. */
    viewportMetrics = viewportMetrics.clamp();

    return viewportMetrics;
  }
Exemplo n.º 10
0
 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);
     }
   }
 }
Exemplo n.º 11
0
  private void sendPointToGecko(String event, MotionEvent motionEvent) {
    String json;
    try {
      PointF point = new PointF(motionEvent.getX(), motionEvent.getY());
      point = mTarget.convertViewPointToLayerPoint(point);
      if (point == null) {
        return;
      }
      json = PointUtils.toJSON(point).toString();
    } catch (Exception e) {
      Log.e(LOGTAG, "Unable to convert point to JSON for " + event, e);
      return;
    }

    GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent(event, json));
  }
Exemplo n.º 12
0
  /*
   * Zooming
   */
  @Override
  public boolean onScaleBegin(SimpleScaleGestureDetector detector) {
    if (mState == PanZoomState.ANIMATED_ZOOM) return false;

    if (!mTarget.getZoomConstraints().getAllowZoom()) return false;

    setState(PanZoomState.PINCHING);
    mLastZoomFocus = new PointF(detector.getFocusX(), detector.getFocusY());
    cancelTouch();

    GeckoAppShell.sendEventToGecko(
        GeckoEvent.createNativeGestureEvent(
            GeckoEvent.ACTION_MAGNIFY_START, mLastZoomFocus, getMetrics().zoomFactor));

    return true;
  }
Exemplo n.º 13
0
  /* Performs a bounce-back animation to the given viewport metrics. */
  private void bounce(ImmutableViewportMetrics metrics) {
    stopAnimationTimer();

    ImmutableViewportMetrics bounceStartMetrics = getMetrics();
    if (bounceStartMetrics.fuzzyEquals(metrics)) {
      setState(PanZoomState.NOTHING);
      return;
    }

    // At this point we have already set mState to BOUNCE or ANIMATED_ZOOM, so
    // getRedrawHint() is returning false. This means we can safely call
    // setAnimationTarget to set the new final display port and not have it get
    // clobbered by display ports from intermediate animation frames.
    mTarget.setAnimationTarget(metrics);
    startAnimationTimer(new BounceRunnable(bounceStartMetrics, metrics));
  }
Exemplo n.º 14
0
  @Override
  public void onScaleEnd(SimpleScaleGestureDetector detector) {
    if (mState == PanZoomState.ANIMATED_ZOOM) return;

    // switch back to the touching state
    startTouch(detector.getFocusX(), detector.getFocusY(), detector.getEventTime());

    // Force a viewport synchronisation
    mTarget.setForceRedraw();

    PointF point = new PointF(detector.getFocusX(), detector.getFocusY());
    GeckoEvent event =
        GeckoEvent.createNativeGestureEvent(
            GeckoEvent.ACTION_MAGNIFY_END, point, getMetrics().zoomFactor);

    if (event == null) {
      return;
    }

    GeckoAppShell.sendEventToGecko(event);
  }
Exemplo n.º 15
0
 /**
  * Scales the viewport, keeping the given focus point in the same place before and after the scale
  * operation. You must hold the monitor while calling this.
  */
 private void scaleWithFocus(float zoomFactor, PointF focus) {
   ImmutableViewportMetrics viewportMetrics = getMetrics();
   viewportMetrics = viewportMetrics.scaleTo(zoomFactor, focus);
   mTarget.setViewportMetrics(viewportMetrics);
 }
Exemplo n.º 16
0
  @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;
  }
Exemplo n.º 17
0
 private ImmutableViewportMetrics getMetrics() {
   return mTarget.getViewportMetrics();
 }
Exemplo n.º 18
0
 private void scrollBy(float dx, float dy) {
   ImmutableViewportMetrics scrolled = getMetrics().offsetViewportBy(dx, dy);
   mTarget.setViewportMetrics(scrolled);
 }