diff options
author | Tomaž Vajngerl <tomaz.vajngerl@collabora.com> | 2014-09-19 12:48:11 +0200 |
---|---|---|
committer | Tomaž Vajngerl <tomaz.vajngerl@collabora.com> | 2014-09-21 23:10:25 +0200 |
commit | 9bc2a66b236985a049c4709405e9b66960f27fcb (patch) | |
tree | 20c6d4595d115684ce69ad501a685ef63aaef0cc /android | |
parent | 1deaa9d304239b2d603cc85bbcb8b8f50d8714da (diff) |
android: upgrade gestures and scrolling to newer code
Change-Id: I84b9f66036891f6ad384ee71d078c654511a6e38
Diffstat (limited to 'android')
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; } - } |