Index: content/public/android/java/src/org/chromium/content/browser/JoystickScrollProvider.java |
diff --git a/content/public/android/java/src/org/chromium/content/browser/JoystickScrollProvider.java b/content/public/android/java/src/org/chromium/content/browser/JoystickScrollProvider.java |
new file mode 100644 |
index 0000000000000000000000000000000000000000..4960d479b9cb0a8ea663d71b25031c14fbf783bf |
--- /dev/null |
+++ b/content/public/android/java/src/org/chromium/content/browser/JoystickScrollProvider.java |
@@ -0,0 +1,113 @@ |
+// Copyright 2015 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+package org.chromium.content.browser; |
+ |
+import android.graphics.PointF; |
+import android.util.Log; |
+import android.util.TypedValue; |
+import android.view.MotionEvent; |
+import android.view.animation.AnimationUtils; |
+ |
+/** |
+ * This class implements auto scrolling and panning |
+ * for gamepad left joystick motion event. |
+ */ |
+public class JoystickScrollProvider implements Runnable { |
+ private static final String TAG = "JoystickScrollProvider"; |
+ private static final float JOYSTICK_SCROLL_FACTOR_MULTIPLIER = 25f; |
+ // Joystick produces "noise", 0.20f has proven a safe value to |
+ // remove noise and still allow reasonable input range. |
+ private static final float JOYSTICK_SCROLL_DEADZONE = 0.2f; |
+ private static final float SCROLL_FACTOR_FALLBACK = 128f; |
+ |
+ private final ContentViewCore mView; |
+ private final PointF mScrollVelocity = new PointF(); |
+ private boolean mAutoScrollEnabled; |
+ private float mScrollFactor; |
+ private long mLastAnimateTimeMillis; |
+ |
+ JoystickScrollProvider(ContentViewCore contentView) { |
+ mView = contentView; |
+ mAutoScrollEnabled = false; |
+ } |
+ |
+ public void run() { |
+ if (mView.getSoftKeyboardShowFlag() || !mView.getContainerView().hasWindowFocus()) { |
+ stop(); |
+ return; |
+ } |
+ |
+ final long timeMillis = AnimationUtils.currentAnimationTimeMillis(); |
+ if (mLastAnimateTimeMillis != 0 && timeMillis > mLastAnimateTimeMillis) { |
sshelke
2015/05/12 12:03:47
Do we miss first event each time since we are chec
jdduke (slow)
2015/05/12 15:13:11
Yup, that sounds reasonable. Missing the first eve
|
+ final long dt = timeMillis - mLastAnimateTimeMillis; |
sshelke
2015/05/12 12:03:47
run() function always be called after animation in
jdduke (slow)
2015/05/12 15:13:11
Subtractions are cheap, I don't think we should ma
|
+ final int dx = (int) (mScrollVelocity.x * dt / 1000.f); |
+ final int dy = (int) (mScrollVelocity.y * dt / 1000.f); |
+ mView.scrollBy(dx, dy); |
jdduke (slow)
2015/05/18 21:40:59
Hmm, we should probably include the "pointer" coor
sshelke
2015/05/19 10:54:30
How can we get pointer location? since view can de
|
+ } |
+ mAutoScrollEnabled = true; |
+ mLastAnimateTimeMillis = timeMillis; |
+ mView.getContainerView().postOnAnimation(this); |
+ } |
+ |
+ /** |
+ * This function processes left joystick event and computes new |
+ * scroll offest in pixels which is propertional to axes movement. |
+ * It also starts runnable to scroll content view core equal to |
+ * scroll offset pixels. |
+ */ |
+ public void onMotion(MotionEvent event) { |
+ computeNewScrollVelocity(event); |
+ if (mScrollVelocity.x != 0 || mScrollVelocity.y != 0) { |
+ if (!mAutoScrollEnabled) { |
+ run(); |
+ } |
+ } else { |
+ stop(); |
+ } |
+ } |
+ |
+ private void stop() { |
+ mLastAnimateTimeMillis = 0; |
+ if (mAutoScrollEnabled) { |
+ mAutoScrollEnabled = false; |
+ mView.getContainerView().removeCallbacks(this); |
+ } |
+ } |
+ |
+ /** |
+ * Translates joystick axes movement to a scroll velocity. |
+ */ |
+ private void computeNewScrollVelocity(MotionEvent event) { |
+ if (mScrollFactor == 0) { |
+ TypedValue outValue = new TypedValue(); |
+ if (!mView.getContext().getTheme().resolveAttribute( |
+ android.R.attr.listPreferredItemHeight, outValue, true)) { |
+ mScrollFactor = outValue.getDimension( |
+ mView.getContext().getResources().getDisplayMetrics()); |
+ } else { |
+ Log.w(TAG, "Theme attribute listPreferredItemHeight not defined" |
+ + "switching to fallback scroll factor "); |
+ mScrollFactor = SCROLL_FACTOR_FALLBACK |
+ * mView.getRenderCoordinates().getDeviceScaleFactor(); |
+ } |
+ } |
+ mScrollVelocity.x = getFilteredAxisValue(event, MotionEvent.AXIS_X) * mScrollFactor |
+ * JOYSTICK_SCROLL_FACTOR_MULTIPLIER; |
+ mScrollVelocity.y = getFilteredAxisValue(event, MotionEvent.AXIS_Y) * mScrollFactor |
+ * JOYSTICK_SCROLL_FACTOR_MULTIPLIER; |
+ } |
+ |
+ /** |
+ * Removes noise from joystick motion events. |
+ */ |
+ private float getFilteredAxisValue(MotionEvent event, int axis) { |
+ float axisValWithNoise = event.getAxisValue(axis); |
+ return ((axisValWithNoise > JOYSTICK_SCROLL_DEADZONE) |
+ ? axisValWithNoise - JOYSTICK_SCROLL_DEADZONE |
+ : ((axisValWithNoise < -JOYSTICK_SCROLL_DEADZONE) |
+ ? axisValWithNoise + JOYSTICK_SCROLL_DEADZONE |
+ : 0)); |
+ } |
+} |