Bug 918079 - Show highlight when overscrolling. r=kats

This commit is contained in:
Wes Johnston 2013-09-26 22:57:57 -07:00
Родитель 1286b0b31d
Коммит 5edd4c1dab
8 изменённых файлов: 204 добавлений и 2 удалений

Просмотреть файл

@ -194,6 +194,7 @@ FENNEC_JAVA_FILES = \
gfx/LayerView.java \
gfx/NativePanZoomController.java \
gfx/NinePatchTileLayer.java \
gfx/Overscroll.java \
gfx/PanningPerfAPI.java \
gfx/PanZoomController.java \
gfx/PanZoomTarget.java \

Просмотреть файл

@ -154,6 +154,10 @@ abstract class Axis {
mRecentVelocities = new float[FLING_VELOCITY_POINTS];
}
// Implementors can override these to show effects when the axis overscrolls
protected void overscrollFling(float velocity) { }
protected void overscrollPan(float displacement) { }
public void setOverScrollMode(int overscrollMode) {
mOverscrollMode = overscrollMode;
}
@ -379,12 +383,22 @@ abstract class Axis {
// getOverscroll which doesn't take into account any new displacment being applied.
// If we using a subscroller, we don't want to alter the scrolling being done
if (getOverScrollMode() == View.OVER_SCROLL_NEVER && !mSubscroller.scrolling()) {
float originalDisplacement = mDisplacement;
if (mDisplacement + getOrigin() < getPageStart() - getMarginStart()) {
mDisplacement = getPageStart() - getMarginStart() - getOrigin();
stopFling();
} else if (mDisplacement + getViewportEnd() > getPageEnd() + getMarginEnd()) {
mDisplacement = getPageEnd() - getMarginEnd() - getViewportEnd();
stopFling();
}
// Return the amount of overscroll so that the overscroll controller can draw it for us
if (originalDisplacement != mDisplacement) {
if (mFlingState == FlingStates.FLINGING) {
overscrollFling(mVelocity / MS_PER_FRAME * 1000);
stopFling();
} else if (mFlingState == FlingStates.PANNING) {
overscrollPan(originalDisplacement - mDisplacement);
}
}
}
}

Просмотреть файл

@ -132,6 +132,10 @@ public class GeckoLayerClient implements LayerView.Listener, PanZoomTarget
mContentDocumentIsDisplayed = true;
}
public void setOverscrollHandler(final Overscroll listener) {
mPanZoomController.setOverscrollHandler(listener);
}
/** Attaches to root layer so that Gecko appears. */
public void notifyGeckoReady() {
mGeckoIsReady = true;

Просмотреть файл

@ -129,6 +129,9 @@ class JavaPanZoomController
/* Used to change the scrollY direction */
private boolean mNegateWheelScrollY;
// Handler to be notified when overscroll occurs
private Overscroll mOverscroll;
public JavaPanZoomController(PanZoomTarget target, View view, EventDispatcher eventDispatcher) {
mTarget = target;
mSubscroller = new SubdocumentScrollHelper(eventDispatcher);
@ -1113,6 +1116,18 @@ class JavaPanZoomController
RectF maxMargins = mTarget.getMaxMargins();
return (metrics.marginLeft < maxMargins.left || metrics.marginRight < maxMargins.right);
}
@Override
protected void overscrollFling(final float velocity) {
if (mOverscroll != null) {
mOverscroll.setVelocity(velocity, Overscroll.Axis.X);
}
}
@Override
protected void overscrollPan(final float distance) {
if (mOverscroll != null) {
mOverscroll.setDistance(distance, Overscroll.Axis.X);
}
}
}
private class AxisY extends Axis {
@ -1135,6 +1150,18 @@ class JavaPanZoomController
RectF maxMargins = mTarget.getMaxMargins();
return (metrics.marginTop < maxMargins.top || metrics.marginBottom < maxMargins.bottom);
}
@Override
protected void overscrollFling(final float velocity) {
if (mOverscroll != null) {
mOverscroll.setVelocity(velocity, Overscroll.Axis.Y);
}
}
@Override
protected void overscrollPan(final float distance) {
if (mOverscroll != null) {
mOverscroll.setDistance(distance, Overscroll.Axis.Y);
}
}
}
/*
@ -1434,4 +1461,9 @@ class JavaPanZoomController
public void updateScrollOffset(float cssX, float cssY) {
// Nothing to update, this class doesn't store the scroll offset locally.
}
@Override
public void setOverscrollHandler(final Overscroll handler) {
mOverscroll = handler;
}
}

Просмотреть файл

@ -18,6 +18,7 @@ import org.mozilla.gecko.util.EventDispatcher;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.PixelFormat;
import android.graphics.PointF;
@ -67,6 +68,7 @@ public class LayerView extends FrameLayout {
/* This should only be modified on the Java UI thread. */
private final ArrayList<TouchEventInterceptor> mTouchInterceptors;
private final Overscroll mOverscroll;
/* Flags used to determine when to show the painted surface. */
public static final int PAINT_START = 0;
@ -104,10 +106,13 @@ public class LayerView extends FrameLayout {
mBackgroundColor = Color.WHITE;
mTouchInterceptors = new ArrayList<TouchEventInterceptor>();
mOverscroll = new Overscroll(this);
}
public void initializeView(EventDispatcher eventDispatcher) {
mLayerClient = new GeckoLayerClient(getContext(), this, eventDispatcher);
mLayerClient.setOverscrollHandler(mOverscroll);
mPanZoomController = mLayerClient.getPanZoomController();
mMarginsAnimator = mLayerClient.getLayerMarginsAnimator();
@ -218,6 +223,16 @@ public class LayerView extends FrameLayout {
return result;
}
@Override
public void dispatchDraw(final Canvas canvas) {
super.dispatchDraw(canvas);
// We must have a layer client to get valid viewport metrics
if (mLayerClient != null) {
mOverscroll.draw(canvas, getViewportMetrics());
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
@ -487,6 +502,8 @@ public class LayerView extends FrameLayout {
if (mListener != null) {
mListener.sizeChanged(width, height);
}
mOverscroll.setSize(width, height);
}
private void surfaceChanged(int width, int height) {
@ -495,6 +512,8 @@ public class LayerView extends FrameLayout {
if (mListener != null) {
mListener.surfaceChanged(width, height);
}
mOverscroll.setSize(width, height);
}
private void onDestroyed() {

Просмотреть файл

@ -104,4 +104,7 @@ class NativePanZoomController implements PanZoomController, GeckoEventListener {
}
public native void updateScrollOffset(float cssX, float cssY);
public void setOverscrollHandler(final Overscroll listener) {
}
}

Просмотреть файл

@ -0,0 +1,127 @@
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package org.mozilla.gecko.gfx;
import android.content.Context;
import android.graphics.Canvas;
import android.support.v4.widget.EdgeEffectCompat;
import android.support.v4.view.ViewCompat;
import android.view.View;
public class Overscroll {
// Used to index particular edges in the edges array
private static final int TOP = 0;
private static final int BOTTOM = 1;
private static final int LEFT = 2;
private static final int RIGHT = 3;
// All four edges of the screen
private final EdgeEffectCompat[] mEdges = new EdgeEffectCompat[4];
// The view we're showing this overscroll on.
private final View mView;
// The axis to show overscroll on.
public enum Axis {
X,
Y,
};
public Overscroll(final View v) {
mView = v;
Context context = v.getContext();
for (int i = 0; i < 4; i++) {
mEdges[i] = new EdgeEffectCompat(context);
}
}
public void setSize(final int width, final int height) {
mEdges[LEFT].setSize(height, width);
mEdges[RIGHT].setSize(height, width);
mEdges[TOP].setSize(width, height);
mEdges[BOTTOM].setSize(width, height);
}
private EdgeEffectCompat getEdgeForAxisAndSide(final Axis axis, final float side) {
if (axis == Axis.Y) {
if (side < 0) {
return mEdges[TOP];
} else {
return mEdges[BOTTOM];
}
} else {
if (side < 0) {
return mEdges[LEFT];
} else {
return mEdges[RIGHT];
}
}
}
public void setVelocity(final float velocity, final Axis axis) {
final EdgeEffectCompat edge = getEdgeForAxisAndSide(axis, velocity);
// If we're showing overscroll already, start fading it out.
if (!edge.isFinished()) {
edge.onRelease();
} else {
// Otherwise, show an absorb effect
edge.onAbsorb((int)velocity);
}
ViewCompat.postInvalidateOnAnimation(mView);
}
public void setDistance(final float distance, final Axis axis) {
// The first overscroll event often has zero distance. Throw it out
if (distance == 0.0f) {
return;
}
final EdgeEffectCompat edge = getEdgeForAxisAndSide(axis, (int)distance);
edge.onPull(distance / (axis == Axis.X ? mView.getWidth() : mView.getHeight()));
ViewCompat.postInvalidateOnAnimation(mView);
}
public void draw(final Canvas canvas, final ImmutableViewportMetrics metrics) {
if (metrics == null) {
return;
}
// If we're pulling an edge, or fading it out, draw!
boolean invalidate = false;
if (!mEdges[TOP].isFinished()) {
invalidate |= draw(mEdges[TOP], canvas, metrics.marginLeft, metrics.marginTop, 0);
}
if (!mEdges[BOTTOM].isFinished()) {
invalidate |= draw(mEdges[BOTTOM], canvas, mView.getWidth(), mView.getHeight(), 180);
}
if (!mEdges[LEFT].isFinished()) {
invalidate |= draw(mEdges[LEFT], canvas, metrics.marginLeft, mView.getHeight(), 270);
}
if (!mEdges[RIGHT].isFinished()) {
invalidate |= draw(mEdges[RIGHT], canvas, mView.getWidth(), metrics.marginTop, 90);
}
// If the edge effect is animating off screen, invalidate.
if (invalidate) {
ViewCompat.postInvalidateOnAnimation(mView);
}
}
public boolean draw(final EdgeEffectCompat edge, final Canvas canvas, final float translateX, final float translateY, final float rotation) {
final int state = canvas.save();
canvas.translate(translateX, translateY);
canvas.rotate(rotation);
boolean invalidate = edge.draw(canvas);
canvas.restoreToCount(state);
return invalidate;
}
}

Просмотреть файл

@ -42,4 +42,6 @@ public interface PanZoomController {
public int getOverScrollMode();
public void updateScrollOffset(float cssX, float cssY);
public void setOverscrollHandler(final Overscroll controller);
}