1 /* 2 * Copyright (C) 2011 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.gallery3d.ui; 18 19 20 // This is a customized version of Scroller, with a interface similar to 21 // android.widget.Scroller. It does fling only, not scroll. 22 // 23 // The differences between the this Scroller and the system one are: 24 // 25 // (1) The velocity does not change because of min/max limit. 26 // (2) The duration is different. 27 // (3) The deceleration curve is different. 28 class FlingScroller { 29 @SuppressWarnings("unused") 30 private static final String TAG = "FlingController"; 31 32 // The fling duration (in milliseconds) when velocity is 1 pixel/second 33 private static final float FLING_DURATION_PARAM = 50f; 34 private static final int DECELERATED_FACTOR = 4; 35 36 private int mStartX, mStartY; 37 private int mMinX, mMinY, mMaxX, mMaxY; 38 private double mSinAngle; 39 private double mCosAngle; 40 private int mDuration; 41 private int mDistance; 42 private int mFinalX, mFinalY; 43 44 private int mCurrX, mCurrY; 45 private double mCurrV; 46 47 public int getFinalX() { 48 return mFinalX; 49 } 50 51 public int getFinalY() { 52 return mFinalY; 53 } 54 55 public int getDuration() { 56 return mDuration; 57 } 58 59 public int getCurrX() { 60 return mCurrX; 61 62 } 63 64 public int getCurrY() { 65 return mCurrY; 66 } 67 68 public int getCurrVelocityX() { 69 return (int)Math.round(mCurrV * mCosAngle); 70 } 71 72 public int getCurrVelocityY() { 73 return (int)Math.round(mCurrV * mSinAngle); 74 } 75 76 public void fling(int startX, int startY, int velocityX, int velocityY, 77 int minX, int maxX, int minY, int maxY) { 78 mStartX = startX; 79 mStartY = startY; 80 mMinX = minX; 81 mMinY = minY; 82 mMaxX = maxX; 83 mMaxY = maxY; 84 85 double velocity = Math.hypot(velocityX, velocityY); 86 mSinAngle = velocityY / velocity; 87 mCosAngle = velocityX / velocity; 88 // 89 // The position formula: x(t) = s + (e - s) * (1 - (1 - t / T) ^ d) 90 // velocity formula: v(t) = d * (e - s) * (1 - t / T) ^ (d - 1) / T 91 // Thus, 92 // v0 = d * (e - s) / T => (e - s) = v0 * T / d 93 // 94 95 // Ta = T_ref * (Va / V_ref) ^ (1 / (d - 1)); V_ref = 1 pixel/second; 96 mDuration = (int)Math.round(FLING_DURATION_PARAM 97 * Math.pow(Math.abs(velocity), 1.0 / (DECELERATED_FACTOR - 1))); 98 99 // (e - s) = v0 * T / d 100 mDistance = (int)Math.round( 101 velocity * mDuration / DECELERATED_FACTOR / 1000); 102 103 mFinalX = getX(1.0f); 104 mFinalY = getY(1.0f); 105 } 106 107 public void computeScrollOffset(float progress) { 108 progress = Math.min(progress, 1); 109 float f = 1 - progress; 110 f = 1 - (float) Math.pow(f, DECELERATED_FACTOR); 111 mCurrX = getX(f); 112 mCurrY = getY(f); 113 mCurrV = getV(progress); 114 } 115 116 private int getX(float f) { 117 int r = (int) Math.round(mStartX + f * mDistance * mCosAngle); 118 if (mCosAngle > 0 && mStartX <= mMaxX) { 119 r = Math.min(r, mMaxX); 120 } else if (mCosAngle < 0 && mStartX >= mMinX) { 121 r = Math.max(r, mMinX); 122 } 123 return r; 124 } 125 126 private int getY(float f) { 127 int r = (int) Math.round(mStartY + f * mDistance * mSinAngle); 128 if (mSinAngle > 0 && mStartY <= mMaxY) { 129 r = Math.min(r, mMaxY); 130 } else if (mSinAngle < 0 && mStartY >= mMinY) { 131 r = Math.max(r, mMinY); 132 } 133 return r; 134 } 135 136 private double getV(float progress) { 137 // velocity formula: v(t) = d * (e - s) * (1 - t / T) ^ (d - 1) / T 138 return DECELERATED_FACTOR * mDistance * 1000 * 139 Math.pow(1 - progress, DECELERATED_FACTOR - 1) / mDuration; 140 } 141 } 142