summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTomaž Vajngerl <tomaz.vajngerl@collabora.com>2014-09-19 12:48:11 +0200
committerTomaž Vajngerl <tomaz.vajngerl@collabora.com>2014-09-21 23:10:25 +0200
commit9bc2a66b236985a049c4709405e9b66960f27fcb (patch)
tree20c6d4595d115684ce69ad501a685ef63aaef0cc
parent1deaa9d304239b2d603cc85bbcb8b8f50d8714da (diff)
android: upgrade gestures and scrolling to newer code
Change-Id: I84b9f66036891f6ad384ee71d078c654511a6e38
-rw-r--r--android/experimental/LOAndroid3/src/java/org/mozilla/gecko/ui/Axis.java132
-rw-r--r--android/experimental/LOAndroid3/src/java/org/mozilla/gecko/ui/SimpleScaleGestureDetector.java99
-rw-r--r--android/experimental/LOAndroid3/src/java/org/mozilla/gecko/ui/SubdocumentScrollHelper.java83
3 files changed, 155 insertions, 159 deletions
diff --git a/android/experimental/LOAndroid3/src/java/org/mozilla/gecko/ui/Axis.java b/android/experimental/LOAndroid3/src/java/org/mozilla/gecko/ui/Axis.java
index 521e60a1ecd6..d5e3de87675e 100644
--- a/android/experimental/LOAndroid3/src/java/org/mozilla/gecko/ui/Axis.java
+++ b/android/experimental/LOAndroid3/src/java/org/mozilla/gecko/ui/Axis.java
@@ -1,45 +1,17 @@
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
- * ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is Mozilla Android code.
- *
- * The Initial Developer of the Original Code is Mozilla Foundation.
- * Portions created by the Initial Developer are Copyright (C) 2012
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- * Patrick Walton <pcwalton@mozilla.com>
- * Kartikaya Gupta <kgupta@mozilla.com>
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either the GNU General Public License Version 2 or later (the "GPL"), or
- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
+ * 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.ui;
+import android.util.Log;
+
+import org.json.JSONArray;
import org.mozilla.gecko.util.FloatUtils;
+import java.util.Map;
+
/**
* This class represents the physics for one axis of movement (i.e. either
* horizontal or vertical). It tracks the different properties of movement
@@ -47,25 +19,73 @@ import org.mozilla.gecko.util.FloatUtils;
* a particular axis.
*/
abstract class Axis {
+ private static final String LOGTAG = "GeckoAxis";
+
+ private static final String PREF_SCROLLING_FRICTION_SLOW = "ui.scrolling.friction_slow";
+ private static final String PREF_SCROLLING_FRICTION_FAST = "ui.scrolling.friction_fast";
+ private static final String PREF_SCROLLING_VELOCITY_THRESHOLD = "ui.scrolling.velocity_threshold";
+ private static final String PREF_SCROLLING_MAX_EVENT_ACCELERATION = "ui.scrolling.max_event_acceleration";
+ private static final String PREF_SCROLLING_OVERSCROLL_DECEL_RATE = "ui.scrolling.overscroll_decel_rate";
+ private static final String PREF_SCROLLING_OVERSCROLL_SNAP_LIMIT = "ui.scrolling.overscroll_snap_limit";
+ private static final String PREF_SCROLLING_MIN_SCROLLABLE_DISTANCE = "ui.scrolling.min_scrollable_distance";
+
// This fraction of velocity remains after every animation frame when the velocity is low.
- private static final float FRICTION_SLOW = 0.85f;
+ private static float FRICTION_SLOW;
// This fraction of velocity remains after every animation frame when the velocity is high.
- private static final float FRICTION_FAST = 0.97f;
+ private static float FRICTION_FAST;
// Below this velocity (in pixels per frame), the friction starts increasing from FRICTION_FAST
// to FRICTION_SLOW.
- private static final float VELOCITY_THRESHOLD = 10.0f;
+ private static float VELOCITY_THRESHOLD;
// The maximum velocity change factor between events, per ms, in %.
// Direction changes are excluded.
- private static final float MAX_EVENT_ACCELERATION = 0.012f;
+ private static float MAX_EVENT_ACCELERATION;
// The rate of deceleration when the surface has overscrolled.
- private static final float OVERSCROLL_DECEL_RATE = 0.04f;
+ private static float OVERSCROLL_DECEL_RATE;
// The percentage of the surface which can be overscrolled before it must snap back.
- private static final float SNAP_LIMIT = 0.75f;
+ private static float SNAP_LIMIT;
// The minimum amount of space that must be present for an axis to be considered scrollable,
// in pixels.
- private static final float MIN_SCROLLABLE_DISTANCE = 0.5f;
+ private static float MIN_SCROLLABLE_DISTANCE;
+
+ private static float getFloatPref(Map<String, Integer> prefs, String prefName, int defaultValue) {
+ Integer value = (prefs == null ? null : prefs.get(prefName));
+ return (float)(value == null || value < 0 ? defaultValue : value) / 1000f;
+ }
+
+ private static int getIntPref(Map<String, Integer> prefs, String prefName, int defaultValue) {
+ Integer value = (prefs == null ? null : prefs.get(prefName));
+ return (value == null || value < 0 ? defaultValue : value);
+ }
+
+ static void addPrefNames(JSONArray prefs) {
+ prefs.put(PREF_SCROLLING_FRICTION_FAST);
+ prefs.put(PREF_SCROLLING_FRICTION_SLOW);
+ prefs.put(PREF_SCROLLING_VELOCITY_THRESHOLD);
+ prefs.put(PREF_SCROLLING_MAX_EVENT_ACCELERATION);
+ prefs.put(PREF_SCROLLING_OVERSCROLL_DECEL_RATE);
+ prefs.put(PREF_SCROLLING_OVERSCROLL_SNAP_LIMIT);
+ prefs.put(PREF_SCROLLING_MIN_SCROLLABLE_DISTANCE);
+ }
+
+ static void setPrefs(Map<String, Integer> prefs) {
+ FRICTION_SLOW = getFloatPref(prefs, PREF_SCROLLING_FRICTION_SLOW, 850);
+ FRICTION_FAST = getFloatPref(prefs, PREF_SCROLLING_FRICTION_FAST, 970);
+ VELOCITY_THRESHOLD = getIntPref(prefs, PREF_SCROLLING_VELOCITY_THRESHOLD, 10);
+ MAX_EVENT_ACCELERATION = getFloatPref(prefs, PREF_SCROLLING_MAX_EVENT_ACCELERATION, 12);
+ OVERSCROLL_DECEL_RATE = getFloatPref(prefs, PREF_SCROLLING_OVERSCROLL_DECEL_RATE, 40);
+ SNAP_LIMIT = getFloatPref(prefs, PREF_SCROLLING_OVERSCROLL_SNAP_LIMIT, 300);
+ MIN_SCROLLABLE_DISTANCE = getFloatPref(prefs, PREF_SCROLLING_MIN_SCROLLABLE_DISTANCE, 500);
+ Log.i(LOGTAG, "Prefs: " + FRICTION_SLOW + "," + FRICTION_FAST + "," + VELOCITY_THRESHOLD + ","
+ + MAX_EVENT_ACCELERATION + "," + OVERSCROLL_DECEL_RATE + "," + SNAP_LIMIT + "," + MIN_SCROLLABLE_DISTANCE);
+ }
+
+ static {
+ // set the scrolling parameters to default values on startup
+ setPrefs(null);
+ }
+
// The number of milliseconds per frame assuming 60 fps
private static final float MS_PER_FRAME = 1000.0f / 60.0f;
@@ -147,7 +167,7 @@ abstract class Axis {
}
private Overscroll getOverscroll() {
- boolean minus = getOrigin() < 0.0f;
+ boolean minus = (getOrigin() < 0.0f);
boolean plus = (getViewportEnd() > getPageLength());
if (minus && plus) {
return Overscroll.BOTH;
@@ -164,14 +184,10 @@ abstract class Axis {
// overscrolled on this axis, returns 0.
private float getExcess() {
switch (getOverscroll()) {
- case MINUS:
- return -getOrigin();
- case PLUS:
- return getViewportEnd() - getPageLength();
- case BOTH:
- return getViewportEnd() - getPageLength() - getOrigin();
- default:
- return 0.0f;
+ case MINUS: return -getOrigin();
+ case PLUS: return getViewportEnd() - getPageLength();
+ case BOTH: return getViewportEnd() - getPageLength() - getOrigin();
+ default: return 0.0f;
}
}
@@ -180,7 +196,14 @@ abstract class Axis {
* possible and this axis has not been scroll locked while panning. Otherwise, returns false.
*/
private boolean scrollable() {
- return getViewportLength() <= getPageLength() - MIN_SCROLLABLE_DISTANCE && !mScrollingDisabled;
+ // If we're scrolling a subdocument, ignore the viewport length restrictions (since those
+ // apply to the top-level document) and only take into account axis locking.
+ if (mSubscroller.scrolling()) {
+ return !mScrollingDisabled;
+ } else {
+ return getViewportLength() <= getPageLength() - MIN_SCROLLABLE_DISTANCE &&
+ !mScrollingDisabled;
+ }
}
/*
@@ -257,8 +280,9 @@ abstract class Axis {
// Performs displacement of the viewport position according to the current velocity.
void displace() {
- if (!mSubscroller.scrolling() && !scrollable())
+ if (!scrollable()) {
return;
+ }
if (mFlingState == FlingStates.PANNING)
mDisplacement += (mLastTouchPos - mTouchPos) * getEdgeResistance();
diff --git a/android/experimental/LOAndroid3/src/java/org/mozilla/gecko/ui/SimpleScaleGestureDetector.java b/android/experimental/LOAndroid3/src/java/org/mozilla/gecko/ui/SimpleScaleGestureDetector.java
index 4f9e39857e81..6f920cafb218 100644
--- a/android/experimental/LOAndroid3/src/java/org/mozilla/gecko/ui/SimpleScaleGestureDetector.java
+++ b/android/experimental/LOAndroid3/src/java/org/mozilla/gecko/ui/SimpleScaleGestureDetector.java
@@ -1,47 +1,17 @@
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
- * ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is Mozilla Android code.
- *
- * The Initial Developer of the Original Code is Mozilla Foundation.
- * Portions created by the Initial Developer are Copyright (C) 2012
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- * Patrick Walton <pcwalton@mozilla.com>
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either the GNU General Public License Version 2 or later (the "GPL"), or
- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
+ * 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.ui;
-import org.mozilla.gecko.gfx.PointUtils;
-import org.json.JSONException;
import android.graphics.PointF;
import android.util.Log;
import android.view.MotionEvent;
+
+import org.json.JSONException;
+import org.mozilla.gecko.gfx.PointUtils;
+
import java.util.LinkedList;
import java.util.ListIterator;
import java.util.Stack;
@@ -82,18 +52,18 @@ public class SimpleScaleGestureDetector {
/** Forward touch events to this function. */
public void onTouchEvent(MotionEvent event) {
switch (event.getAction() & MotionEvent.ACTION_MASK) {
- case MotionEvent.ACTION_DOWN:
- case MotionEvent.ACTION_POINTER_DOWN:
- onTouchStart(event);
- break;
- case MotionEvent.ACTION_MOVE:
- onTouchMove(event);
- break;
- case MotionEvent.ACTION_POINTER_UP:
- case MotionEvent.ACTION_UP:
- case MotionEvent.ACTION_CANCEL:
- onTouchEnd(event);
- break;
+ case MotionEvent.ACTION_DOWN:
+ case MotionEvent.ACTION_POINTER_DOWN:
+ onTouchStart(event);
+ break;
+ case MotionEvent.ACTION_MOVE:
+ onTouchMove(event);
+ break;
+ case MotionEvent.ACTION_POINTER_UP:
+ case MotionEvent.ACTION_UP:
+ case MotionEvent.ACTION_CANCEL:
+ onTouchEnd(event);
+ break;
}
}
@@ -103,7 +73,7 @@ public class SimpleScaleGestureDetector {
private int getActionIndex(MotionEvent event) {
return (event.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK)
- >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
+ >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
}
private void onTouchStart(MotionEvent event) {
@@ -131,11 +101,12 @@ public class SimpleScaleGestureDetector {
private void onTouchEnd(MotionEvent event) {
mLastEventTime = event.getEventTime();
+ boolean isCancel = (event.getAction() & MotionEvent.ACTION_MASK) == MotionEvent.ACTION_CANCEL;
int id = event.getPointerId(getActionIndex(event));
ListIterator<PointerInfo> iterator = mPointerInfo.listIterator();
while (iterator.hasNext()) {
PointerInfo pointerInfo = iterator.next();
- if (pointerInfo.getId() != id) {
+ if (!(isCancel || pointerInfo.getId() == id)) {
continue;
}
@@ -156,11 +127,11 @@ public class SimpleScaleGestureDetector {
*/
public float getFocusX() {
switch (getPointersDown()) {
- case 1:
- return mPointerInfo.getFirst().getCurrent().x;
- case 2:
- PointerInfo pointerA = mPointerInfo.getFirst(), pointerB = mPointerInfo.getLast();
- return (pointerA.getCurrent().x + pointerB.getCurrent().x) / 2.0f;
+ case 1:
+ return mPointerInfo.getFirst().getCurrent().x;
+ case 2:
+ PointerInfo pointerA = mPointerInfo.getFirst(), pointerB = mPointerInfo.getLast();
+ return (pointerA.getCurrent().x + pointerB.getCurrent().x) / 2.0f;
}
Log.e(LOGTAG, "No gesture taking place in getFocusX()!");
@@ -173,11 +144,11 @@ public class SimpleScaleGestureDetector {
*/
public float getFocusY() {
switch (getPointersDown()) {
- case 1:
- return mPointerInfo.getFirst().getCurrent().y;
- case 2:
- PointerInfo pointerA = mPointerInfo.getFirst(), pointerB = mPointerInfo.getLast();
- return (pointerA.getCurrent().y + pointerB.getCurrent().y) / 2.0f;
+ case 1:
+ return mPointerInfo.getFirst().getCurrent().y;
+ case 2:
+ PointerInfo pointerA = mPointerInfo.getFirst(), pointerB = mPointerInfo.getLast();
+ return (pointerA.getCurrent().y + pointerB.getCurrent().y) / 2.0f;
}
Log.e(LOGTAG, "No gesture taking place in getFocusY()!");
@@ -225,9 +196,9 @@ public class SimpleScaleGestureDetector {
/* Sends the requested scale gesture notification to the listener. */
private void sendScaleGesture(EventType eventType) {
switch (eventType) {
- case BEGIN: mListener.onScaleBegin(this); break;
- case CONTINUE: mListener.onScale(this); break;
- case END: mListener.onScaleEnd(this); break;
+ case BEGIN: mListener.onScaleBegin(this); break;
+ case CONTINUE: mListener.onScale(this); break;
+ case END: mListener.onScaleEnd(this); break;
}
}
diff --git a/android/experimental/LOAndroid3/src/java/org/mozilla/gecko/ui/SubdocumentScrollHelper.java b/android/experimental/LOAndroid3/src/java/org/mozilla/gecko/ui/SubdocumentScrollHelper.java
index 30b4b30a5a99..8e7de558e18d 100644
--- a/android/experimental/LOAndroid3/src/java/org/mozilla/gecko/ui/SubdocumentScrollHelper.java
+++ b/android/experimental/LOAndroid3/src/java/org/mozilla/gecko/ui/SubdocumentScrollHelper.java
@@ -1,74 +1,76 @@
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
- * ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is Mozilla Android code.
- *
- * The Initial Developer of the Original Code is Mozilla Foundation.
- * Portions created by the Initial Developer are Copyright (C) 2012
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- * Kartikaya Gupta <kgupta@mozilla.com>
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either the GNU General Public License Version 2 or later (the "GPL"), or
- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
+ * 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.ui;
-
import android.graphics.PointF;
import android.os.Handler;
+import android.util.Log;
+
+import org.json.JSONException;
+import org.json.JSONObject;
-class SubdocumentScrollHelper {
- private static final String LOGTAG = SubdocumentScrollHelper.class.getSimpleName();
+class SubdocumentScrollHelper {
+ private static final String LOGTAG = "GeckoSubdocumentScrollHelper";
private final PanZoomController mPanZoomController;
private final Handler mUiHandler;
+ /* This is the amount of displacement we have accepted but not yet sent to JS; this is
+ * only valid when mOverrideScrollPending is true. */
+ private final PointF mPendingDisplacement;
+
+ /* When this is true, we're sending scroll events to JS to scroll the active subdocument. */
private boolean mOverridePanning;
+
+ /* When this is true, we have received an ack for the last scroll event we sent to JS, and
+ * are ready to send the next scroll event. Note we only ever have one scroll event inflight
+ * at a time. */
private boolean mOverrideScrollAck;
+
+ /* When this is true, we have a pending scroll that we need to send to JS; we were unable
+ * to send it when it was initially requested because mOverrideScrollAck was not true. */
private boolean mOverrideScrollPending;
+
+ /* When this is true, the last scroll event we sent actually did some amount of scrolling on
+ * the subdocument; we use this to decide when we have reached the end of the subdocument. */
private boolean mScrollSucceeded;
SubdocumentScrollHelper(PanZoomController controller) {
mPanZoomController = controller;
+ // mUiHandler will be bound to the UI thread since that's where this constructor runs
mUiHandler = new Handler();
+ mPendingDisplacement = new PointF();
}
boolean scrollBy(PointF displacement) {
- if (!mOverridePanning) {
+ if (! mOverridePanning) {
return false;
}
- if (!mOverrideScrollAck) {
+ if (! mOverrideScrollAck) {
mOverrideScrollPending = true;
+ mPendingDisplacement.x += displacement.x;
+ mPendingDisplacement.y += displacement.y;
return true;
}
+ JSONObject json = new JSONObject();
+ try {
+ json.put("x", displacement.x);
+ json.put("y", displacement.y);
+ } catch (JSONException e) {
+ Log.e(LOGTAG, "Error forming subwindow scroll message: ", e);
+ }
+
mOverrideScrollAck = false;
mOverrideScrollPending = false;
+ // clear the |mPendingDisplacement| after serializing |displacement| to
+ // JSON because they might be the same object
+ mPendingDisplacement.x = 0;
+ mPendingDisplacement.y = 0;
return true;
}
@@ -84,5 +86,4 @@ class SubdocumentScrollHelper {
boolean lastScrollSucceeded() {
return mScrollSucceeded;
}
-
}