Chromium Code Reviews| 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)); |
| + } |
| +} |