michael@0: /* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*- michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this file, michael@0: * You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: package org.mozilla.gecko; michael@0: michael@0: import java.util.Timer; michael@0: import java.util.TimerTask; michael@0: michael@0: import org.mozilla.gecko.util.GamepadUtils; michael@0: michael@0: import android.view.InputDevice; michael@0: import android.view.MotionEvent; michael@0: import android.view.View; michael@0: michael@0: public class ScrollAnimator implements View.OnGenericMotionListener { michael@0: private Timer mScrollTimer; michael@0: private int mX; michael@0: private int mY; michael@0: michael@0: // Assuming 60fps, this will make the view scroll once per frame michael@0: static final long MS_PER_FRAME = 1000 / 60; michael@0: michael@0: // Maximum number of pixels that can be scrolled per frame michael@0: static final float MAX_SCROLL = 0.075f * GeckoAppShell.getDpi(); michael@0: michael@0: private class ScrollRunnable extends TimerTask { michael@0: private View mView; michael@0: michael@0: public ScrollRunnable(View view) { michael@0: mView = view; michael@0: } michael@0: michael@0: @Override michael@0: public final void run() { michael@0: mView.scrollBy(mX, mY); michael@0: } michael@0: } michael@0: michael@0: @Override michael@0: public boolean onGenericMotion(View view, MotionEvent event) { michael@0: if ((event.getSource() & InputDevice.SOURCE_CLASS_JOYSTICK) != 0) { michael@0: switch (event.getAction()) { michael@0: case MotionEvent.ACTION_MOVE: michael@0: // Cancel the animation if the joystick is in a neutral position michael@0: if (GamepadUtils.isValueInDeadZone(event, MotionEvent.AXIS_X) && michael@0: GamepadUtils.isValueInDeadZone(event, MotionEvent.AXIS_Y)) { michael@0: if (mScrollTimer != null) { michael@0: mScrollTimer.cancel(); michael@0: mScrollTimer = null; michael@0: } michael@0: return true; michael@0: } michael@0: michael@0: // Scroll with a velocity relative to the screen DPI michael@0: mX = (int) (event.getAxisValue(MotionEvent.AXIS_X) * MAX_SCROLL); michael@0: mY = (int) (event.getAxisValue(MotionEvent.AXIS_Y) * MAX_SCROLL); michael@0: michael@0: // Start the timer; the view will continue to scroll as long as michael@0: // the joystick is not in the deadzone. michael@0: if (mScrollTimer == null) { michael@0: mScrollTimer = new Timer(); michael@0: ScrollRunnable task = new ScrollRunnable(view); michael@0: mScrollTimer.scheduleAtFixedRate(task, 0, MS_PER_FRAME); michael@0: } michael@0: michael@0: return true; michael@0: } michael@0: } michael@0: michael@0: return false; michael@0: } michael@0: michael@0: /** michael@0: * Cancels the running scroll animation if it is in progress. michael@0: */ michael@0: public void cancel() { michael@0: if (mScrollTimer != null) { michael@0: mScrollTimer.cancel(); michael@0: mScrollTimer = null; michael@0: } michael@0: } michael@0: }