NumberPicker.java revision cedc446684e94c9971c38c3206f1f224314bda2a
19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/* 29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2008 The Android Open Source Project 39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License"); 59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License. 69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at 79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0 99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software 119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, 129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and 149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License. 159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1768f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrookpackage android.widget; 189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 198bcbebd4178b2e9aca9ee3bd9e1e12c42e74c8dbAdam Powellimport com.android.internal.R; 208bcbebd4178b2e9aca9ee3bd9e1e12c42e74c8dbAdam Powell 21206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganovimport android.animation.Animator; 22206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganovimport android.animation.AnimatorListenerAdapter; 23206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganovimport android.animation.AnimatorSet; 24206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganovimport android.animation.ObjectAnimator; 25206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganovimport android.animation.ValueAnimator; 2668f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrookimport android.annotation.Widget; 279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Context; 28206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganovimport android.content.res.ColorStateList; 29206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganovimport android.content.res.TypedArray; 30206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganovimport android.graphics.Canvas; 31206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganovimport android.graphics.Color; 32206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganovimport android.graphics.Paint; 3350f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganovimport android.graphics.Rect; 34e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganovimport android.graphics.Paint.Align; 359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.text.InputFilter; 369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.text.InputType; 379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.text.Spanned; 38206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganovimport android.text.TextUtils; 399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.text.method.NumberKeyListener; 409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.AttributeSet; 41206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganovimport android.util.SparseArray; 42206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganovimport android.view.KeyEvent; 439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.LayoutInflater; 44206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganovimport android.view.MotionEvent; 45206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganovimport android.view.VelocityTracker; 469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.View; 47206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganovimport android.view.ViewConfiguration; 48e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganovimport android.view.LayoutInflater.Filter; 49206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganovimport android.view.animation.OvershootInterpolator; 50206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganovimport android.view.inputmethod.InputMethodManager; 519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5268f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook/** 534bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * A widget that enables the user to select a number form a predefined range. 544bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * The widget presents an input filed and up and down buttons for selecting the 554bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * current value. Pressing/long pressing the up and down buttons increments and 564bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * decrements the current value respectively. Touching the input filed shows a 574bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * scroll wheel, tapping on which while shown and not moving allows direct edit 584bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * of the current value. Sliding motions up or down hide the buttons and the 594bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * input filed, show the scroll wheel, and rotate the latter. Flinging is 604bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * also supported. The widget enables mapping from positions to strings such 614bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * that instead the position index the corresponding string is displayed. 624bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * <p> 634bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * For an example of using this widget, see {@link android.widget.TimePicker}. 644bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * </p> 6568f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook */ 6668f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook@Widget 6768f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrookpublic class NumberPicker extends LinearLayout { 68fdf6db6748b32f620a7f68b13a67c38b4e59e5edTom Taylor 6968f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook /** 70e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * The default update interval during long press. 71e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov */ 72e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov private static final long DEFAULT_LONG_PRESS_UPDATE_INTERVAL = 300; 73e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov 74e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov /** 75206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * The index of the middle selector item. 7668f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook */ 77206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private static final int SELECTOR_MIDDLE_ITEM_INDEX = 2; 789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7968f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook /** 80206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * The coefficient by which to adjust (divide) the max fling velocity. 8168f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook */ 82206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private static final int SELECTOR_MAX_FLING_VELOCITY_ADJUSTMENT = 8; 839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 84206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 85206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * The the duration for adjusting the selector wheel. 86206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 87206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private static final int SELECTOR_ADJUSTMENT_DURATION_MILLIS = 800; 88fdf6db6748b32f620a7f68b13a67c38b4e59e5edTom Taylor 89206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 90206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * The the delay for showing the input controls after a single tap on the 91206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * input text. 92206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 93206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private static final int SHOW_INPUT_CONTROLS_DELAY_MILLIS = ViewConfiguration 94206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov .getDoubleTapTimeout(); 95206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 96206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 97206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * The update step for incrementing the current value. 98206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 99206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private static final int UPDATE_STEP_INCREMENT = 1; 100206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 101206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 102206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * The update step for decrementing the current value. 103206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 104206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private static final int UPDATE_STEP_DECREMENT = -1; 105206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 106206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 107206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * The strength of fading in the top and bottom while drawing the selector. 108206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 109206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private static final float TOP_AND_BOTTOM_FADING_EDGE_STRENGTH = 0.9f; 110206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 111206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 112206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * The numbers accepted by the input text's {@link Filter} 113206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 114206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private static final char[] DIGIT_CHARACTERS = new char[] { 115206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' 116206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov }; 117206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 118206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 119206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Use a custom NumberPicker formatting callback to use two-digit minutes 120206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * strings like "01". Keeping a static formatter etc. is the most efficient 121206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * way to do this; it avoids creating temporary objects on every call to 122206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * format(). 123e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * 124e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @hide 125206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 126206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov public static final NumberPicker.Formatter TWO_DIGIT_FORMATTER = new NumberPicker.Formatter() { 127206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov final StringBuilder mBuilder = new StringBuilder(); 128206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 129f0ef665299d795df7905897e1c337e37891dafefJean-Baptiste Queru final java.util.Formatter mFmt = new java.util.Formatter(mBuilder, java.util.Locale.US); 130206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 131206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov final Object[] mArgs = new Object[1]; 132206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 133e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov public String format(int value) { 134206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mArgs[0] = value; 135206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mBuilder.delete(0, mBuilder.length()); 136206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mFmt.format("%02d", mArgs); 137206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return mFmt.toString(); 1389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project }; 1409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 141206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 142206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * The increment button. 143206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 144206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private final ImageButton mIncrementButton; 145206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 146206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 147206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * The decrement button. 148206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 149206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private final ImageButton mDecrementButton; 150206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 151206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 152206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * The text for showing the current value. 153206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 154206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private final EditText mInputText; 155206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 156206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 157206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * The height of the text. 158206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 159206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private final int mTextSize; 1609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 161206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 162206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * The values to be displayed instead the indices. 163206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 1649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private String[] mDisplayedValues; 16568f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook 16668f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook /** 16768f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook * Lower value of the range of numbers allowed for the NumberPicker 16868f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook */ 169e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov private int mMinValue; 17068f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook 17168f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook /** 17268f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook * Upper value of the range of numbers allowed for the NumberPicker 17368f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook */ 174e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov private int mMaxValue; 17568f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook 17668f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook /** 17768f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook * Current value of this NumberPicker 17868f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook */ 179e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov private int mValue; 18068f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook 18168f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook /** 182206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Listener to be notified upon current value change. 18368f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook */ 184cedc446684e94c9971c38c3206f1f224314bda2aSvetoslav Ganov private OnValueChangeListener mOnValueChangeListener; 18550f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 18650f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov /** 18750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * Listener to be notified upon scroll state change. 18850f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov */ 18950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov private OnScrollListener mOnScrollListener; 190206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 191206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 192206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Formatter for for displaying the current value. 193206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 1949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private Formatter mFormatter; 195fdf6db6748b32f620a7f68b13a67c38b4e59e5edTom Taylor 196206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 197206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * The speed for updating the value form long press. 198206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 199e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov private long mLongPressUpdateInterval = DEFAULT_LONG_PRESS_UPDATE_INTERVAL; 200fdf6db6748b32f620a7f68b13a67c38b4e59e5edTom Taylor 20168f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook /** 202206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Cache for the string representation of selector indices. 203206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 204206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private final SparseArray<String> mSelectorIndexToStringCache = new SparseArray<String>(); 205206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 206206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 207206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * The selector indices whose value are show by the selector. 208206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 209206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private final int[] mSelectorIndices = new int[] { 210206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov Integer.MIN_VALUE, Integer.MIN_VALUE, Integer.MIN_VALUE, Integer.MIN_VALUE, 211206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov Integer.MIN_VALUE 212206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov }; 213206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 214206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 215206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * The {@link Paint} for drawing the selector. 216206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 217206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private final Paint mSelectorPaint; 218206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 219206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 220206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * The height of a selector element (text + gap). 221206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 222206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private int mSelectorElementHeight; 223206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 224206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 225206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * The initial offset of the scroll selector. 226206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 227206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private int mInitialScrollOffset = Integer.MIN_VALUE; 228206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 229206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 230206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * The current offset of the scroll selector. 231206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 232206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private int mCurrentScrollOffset; 233206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 234206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 235206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * The {@link Scroller} responsible for flinging the selector. 236206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 237206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private final Scroller mFlingScroller; 238206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 239206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 240206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * The {@link Scroller} responsible for adjusting the selector. 241206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 242206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private final Scroller mAdjustScroller; 243206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 244206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 245206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * The previous Y coordinate while scrolling the selector. 246206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 247206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private int mPreviousScrollerY; 248206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 249206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 250206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Handle to the reusable command for setting the input text selection. 251206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 252206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private SetSelectionCommand mSetSelectionCommand; 253206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 254206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 255206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Handle to the reusable command for adjusting the scroller. 256206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 257206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private AdjustScrollerCommand mAdjustScrollerCommand; 258206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 259206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 260206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Handle to the reusable command for updating the current value from long 261206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * press. 262206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 263206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private UpdateValueFromLongPressCommand mUpdateFromLongPressCommand; 264206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 265206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 266206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * {@link Animator} for showing the up/down arrows. 267206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 268206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private final AnimatorSet mShowInputControlsAnimator; 269206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 270206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 271206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * The Y position of the last down event. 272206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 273206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private float mLastDownEventY; 274206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 275206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 276206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * The Y position of the last motion event. 277206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 278206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private float mLastMotionEventY; 279206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 280206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 281206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Flag if to begin edit on next up event. 282206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 283206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private boolean mBeginEditOnUpEvent; 284206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 285206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 286206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Flag if to adjust the selector wheel on next up event. 287206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 288206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private boolean mAdjustScrollerOnUpEvent; 289206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 290206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 291206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Flag if to draw the selector wheel. 292206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 293206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private boolean mDrawSelectorWheel; 294206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 295206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 296206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Determines speed during touch scrolling. 297206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 298206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private VelocityTracker mVelocityTracker; 299206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 300206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 301206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * @see ViewConfiguration#getScaledTouchSlop() 302206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 303206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private int mTouchSlop; 304206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 305206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 306206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * @see ViewConfiguration#getScaledMinimumFlingVelocity() 307206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 308206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private int mMinimumFlingVelocity; 309206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 310206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 311206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * @see ViewConfiguration#getScaledMaximumFlingVelocity() 312206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 313206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private int mMaximumFlingVelocity; 314206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 315206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 316206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Flag whether the selector should wrap around. 317206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 318e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov private boolean mWrapSelectorWheel; 319206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 320206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 321206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * The back ground color used to optimize scroller fading. 32268f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook */ 323206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private final int mSolidColor; 324206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 325206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 3264243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov * Flag indicating if this widget supports flinging. 3274243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov */ 3284243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov private final boolean mFlingable; 3294243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov 3304243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov /** 331206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Reusable {@link Rect} instance. 332206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 333206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private final Rect mTempRect = new Rect(); 334206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 335206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 33650f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * The current scroll state of the number picker. 33750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov */ 33850f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov private int mScrollState = OnScrollListener.SCROLL_STATE_IDLE; 33950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 34050f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov /** 341e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * Interface to listen for changes of the current value. 342206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 343cedc446684e94c9971c38c3206f1f224314bda2aSvetoslav Ganov public interface OnValueChangeListener { 344e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov 345206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 3464bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * Called upon a change of the current value. 3474bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * 348206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * @param picker The NumberPicker associated with this listener. 349206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * @param oldVal The previous value. 350206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * @param newVal The new value. 351206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 352e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov void onValueChange(NumberPicker picker, int oldVal, int newVal); 353206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 354206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 355206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 356e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * Interface to listen for the picker scroll state. 35750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov */ 35850f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov public interface OnScrollListener { 35950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 36050f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov /** 36150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * The view is not scrolling. 36250f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov */ 36350f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov public static int SCROLL_STATE_IDLE = 0; 36450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 36550f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov /** 36650f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * The user is scrolling using touch, and their finger is still on the screen. 36750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov */ 36850f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov public static int SCROLL_STATE_TOUCH_SCROLL = 1; 36950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 37050f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov /** 37150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * The user had previously been scrolling using touch and performed a fling. 37250f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov */ 37350f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov public static int SCROLL_STATE_FLING = 2; 37450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 37550f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov /** 376e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * Callback invoked while the number picker scroll state has changed. 37750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * 378e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @param view The view whose scroll state is being reported. 379e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @param scrollState The current scroll state. One of 380e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * {@link #SCROLL_STATE_IDLE}, 381e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * {@link #SCROLL_STATE_TOUCH_SCROLL} or 382e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * {@link #SCROLL_STATE_IDLE}. 38350f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov */ 3844bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov public void onScrollStateChange(NumberPicker view, int scrollState); 38550f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov } 38650f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 38750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov /** 388e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * Interface used to format current value into a string for presentation. 389206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 390206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov public interface Formatter { 3914bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov 3924bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov /** 393e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * Formats a string representation of the current value. 3944bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * 3954bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * @param value The currently selected value. 3964bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * @return A formatted string representation. 3974bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov */ 398e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov public String format(int value); 3999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 400fdf6db6748b32f620a7f68b13a67c38b4e59e5edTom Taylor 40168f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook /** 4024bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * Create a new number picker. 4034bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * 4044bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * @param context The application environment. 4054bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov */ 4064bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov public NumberPicker(Context context) { 4074bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov this(context, null); 4084bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov } 4094bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov 4104bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov /** 4114bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * Create a new number picker. 412206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * 413206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * @param context The application environment. 414206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * @param attrs A collection of attributes. 41568f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook */ 4169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public NumberPicker(Context context, AttributeSet attrs) { 417206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov this(context, attrs, R.attr.numberPickerStyle); 418206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 419206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 420206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 421206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Create a new number picker 422206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * 423206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * @param context the application environment. 424206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * @param attrs a collection of attributes. 425206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * @param defStyle The default style to apply to this view. 426206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 427206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov public NumberPicker(Context context, AttributeSet attrs, int defStyle) { 428206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov super(context, attrs, defStyle); 429206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 430206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // process style attributes 431206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov TypedArray attributesArray = context.obtainStyledAttributes(attrs, 432206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov R.styleable.NumberPicker, defStyle, 0); 433206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mSolidColor = attributesArray.getColor(R.styleable.NumberPicker_solidColor, 0); 4344243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov mFlingable = attributesArray.getBoolean(R.styleable.NumberPicker_flingable, true); 435206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov attributesArray.recycle(); 436206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 437206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // By default Linearlayout that we extend is not drawn. This is 438206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // its draw() method is not called but dispatchDraw() is called 439206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // directly (see ViewGroup.drawChild()). However, this class uses 440206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // the fading edge effect implemented by View and we need our 441206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // draw() method to be called. Therefore, we declare we will draw. 442206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov setWillNotDraw(false); 443206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov setDrawSelectorWheel(false); 444206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 445206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov LayoutInflater inflater = (LayoutInflater) getContext().getSystemService( 446206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov Context.LAYOUT_INFLATER_SERVICE); 4479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project inflater.inflate(R.layout.number_picker, this, true); 44868f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook 449206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov OnClickListener onClickListener = new OnClickListener() { 45068f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook public void onClick(View v) { 451206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mInputText.clearFocus(); 452206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (v.getId() == R.id.increment) { 453e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov changeCurrent(mValue + 1); 454206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } else { 455e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov changeCurrent(mValue - 1); 45668f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook } 45768f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook } 45868f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook }; 45968f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook 460206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov OnLongClickListener onLongClickListener = new OnLongClickListener() { 461206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov public boolean onLongClick(View v) { 462206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mInputText.clearFocus(); 463206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (v.getId() == R.id.increment) { 464206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov postUpdateValueFromLongPress(UPDATE_STEP_INCREMENT); 465206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } else { 466206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov postUpdateValueFromLongPress(UPDATE_STEP_DECREMENT); 467206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 468206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return true; 469206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 470206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov }; 47168f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook 472206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // increment button 473206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mIncrementButton = (ImageButton) findViewById(R.id.increment); 474206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mIncrementButton.setOnClickListener(onClickListener); 475206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mIncrementButton.setOnLongClickListener(onLongClickListener); 476206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 477206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // decrement button 478206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mDecrementButton = (ImageButton) findViewById(R.id.decrement); 479206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mDecrementButton.setOnClickListener(onClickListener); 480206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mDecrementButton.setOnLongClickListener(onLongClickListener); 481206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 482206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // input text 483012dd5a461f18a2e5dad38c60282fac1c21ff7feSvetoslav Ganov mInputText = (EditText) findViewById(R.id.numberpicker_input); 484206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mInputText.setOnFocusChangeListener(new OnFocusChangeListener() { 485206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov public void onFocusChange(View v, boolean hasFocus) { 48668f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook if (!hasFocus) { 487206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov validateInputTextView(v); 48868f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook } 48968f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook } 490206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov }); 491206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mInputText.setFilters(new InputFilter[] { 492206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov new InputTextFilter() 493206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov }); 49468f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook 495206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mInputText.setRawInputType(InputType.TYPE_CLASS_NUMBER); 496206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 497206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // initialize constants 498206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mTouchSlop = ViewConfiguration.getTapTimeout(); 499206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov ViewConfiguration configuration = ViewConfiguration.get(context); 500206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mTouchSlop = configuration.getScaledTouchSlop(); 501206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mMinimumFlingVelocity = configuration.getScaledMinimumFlingVelocity(); 502206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mMaximumFlingVelocity = configuration.getScaledMaximumFlingVelocity() 503206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov / SELECTOR_MAX_FLING_VELOCITY_ADJUSTMENT; 504206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mTextSize = (int) mInputText.getTextSize(); 505206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 506206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // create the selector wheel paint 507206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov Paint paint = new Paint(); 508206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov paint.setAntiAlias(true); 509206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov paint.setTextAlign(Align.CENTER); 510206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov paint.setTextSize(mTextSize); 511206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov paint.setTypeface(mInputText.getTypeface()); 512206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov ColorStateList colors = mInputText.getTextColors(); 513206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov int color = colors.getColorForState(ENABLED_STATE_SET, Color.WHITE); 514206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov paint.setColor(color); 515206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mSelectorPaint = paint; 516206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 517206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // create the animator for showing the input controls 518206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov final ValueAnimator fadeScroller = ObjectAnimator.ofInt(this, "selectorPaintAlpha", 255, 0); 519206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov final ObjectAnimator showIncrementButton = ObjectAnimator.ofFloat(mIncrementButton, 520206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov "alpha", 0, 1); 521206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov final ObjectAnimator showDecrementButton = ObjectAnimator.ofFloat(mDecrementButton, 522206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov "alpha", 0, 1); 523206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mShowInputControlsAnimator = new AnimatorSet(); 524206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mShowInputControlsAnimator.playTogether(fadeScroller, showIncrementButton, 525206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov showDecrementButton); 526206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mShowInputControlsAnimator.setDuration(getResources().getInteger( 527206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov R.integer.config_longAnimTime)); 528206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mShowInputControlsAnimator.addListener(new AnimatorListenerAdapter() { 529206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private boolean mCanceled = false; 530206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 531206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov @Override 532206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov public void onAnimationEnd(Animator animation) { 533206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (!mCanceled) { 534206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // if canceled => we still want the wheel drawn 535206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov setDrawSelectorWheel(false); 53668f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook } 537206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mCanceled = false; 538206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mSelectorPaint.setAlpha(255); 539206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov invalidate(); 54068f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook } 54168f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook 542206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov @Override 543206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov public void onAnimationCancel(Animator animation) { 544206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (mShowInputControlsAnimator.isRunning()) { 545206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mCanceled = true; 546206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 547206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 548206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov }); 54968f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook 550206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // create the fling and adjust scrollers 551bf80562d22b2bbe7944d80d0524c69d0238010cbSvetoslav Ganov mFlingScroller = new Scroller(getContext(), null, true); 552206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mAdjustScroller = new Scroller(getContext(), new OvershootInterpolator()); 553fdf6db6748b32f620a7f68b13a67c38b4e59e5edTom Taylor 554206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov updateInputTextView(); 555206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov updateIncrementAndDecrementButtonsVisibilityState(); 556206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 557206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 558206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov @Override 559206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov public void onWindowFocusChanged(boolean hasWindowFocus) { 560206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov super.onWindowFocusChanged(hasWindowFocus); 561206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (!hasWindowFocus) { 562206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov removeAllCallbacks(); 563206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 564206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 565206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 566206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov @Override 567206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov public boolean onInterceptTouchEvent(MotionEvent event) { 5684243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov if (!isEnabled() || !mFlingable) { 56951c52edad7d40697d7fb2a091f850506fa897643Svetoslav Ganov return false; 57051c52edad7d40697d7fb2a091f850506fa897643Svetoslav Ganov } 571206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov switch (event.getActionMasked()) { 572206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov case MotionEvent.ACTION_DOWN: 573206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mLastMotionEventY = mLastDownEventY = event.getY(); 574206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov removeAllCallbacks(); 575206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mBeginEditOnUpEvent = false; 576206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mAdjustScrollerOnUpEvent = true; 577206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (mDrawSelectorWheel) { 57850f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov boolean scrollersFinished = mFlingScroller.isFinished() 579206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov && mAdjustScroller.isFinished(); 58050f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov if (!scrollersFinished) { 58150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov mFlingScroller.forceFinished(true); 58250f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov mAdjustScroller.forceFinished(true); 58350f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov tryNotifyScrollListener(OnScrollListener.SCROLL_STATE_IDLE); 58450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov } 58550f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov mBeginEditOnUpEvent = scrollersFinished; 586206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mAdjustScrollerOnUpEvent = true; 587206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov hideInputControls(); 588206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return true; 589206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 590206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (isEventInInputText(event)) { 591206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mAdjustScrollerOnUpEvent = false; 592206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov setDrawSelectorWheel(true); 593206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov hideInputControls(); 594206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return true; 595206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 596206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov break; 597206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov case MotionEvent.ACTION_MOVE: 598206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov float currentMoveY = event.getY(); 599206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov int deltaDownY = (int) Math.abs(currentMoveY - mLastDownEventY); 600206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (deltaDownY > mTouchSlop) { 601206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mBeginEditOnUpEvent = false; 60250f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov tryNotifyScrollListener(OnScrollListener.SCROLL_STATE_TOUCH_SCROLL); 603206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov setDrawSelectorWheel(true); 604206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov hideInputControls(); 605206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return true; 606206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 607206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov break; 608206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 609206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return false; 610206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 611206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 612206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov @Override 613206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov public boolean onTouchEvent(MotionEvent ev) { 61451c52edad7d40697d7fb2a091f850506fa897643Svetoslav Ganov if (!isEnabled()) { 61551c52edad7d40697d7fb2a091f850506fa897643Svetoslav Ganov return false; 61651c52edad7d40697d7fb2a091f850506fa897643Svetoslav Ganov } 617206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (mVelocityTracker == null) { 618206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mVelocityTracker = VelocityTracker.obtain(); 619206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 620206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mVelocityTracker.addMovement(ev); 621206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov int action = ev.getActionMasked(); 622206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov switch (action) { 623206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov case MotionEvent.ACTION_MOVE: 624206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov float currentMoveY = ev.getY(); 62550f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov if (mBeginEditOnUpEvent 62650f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov || mScrollState != OnScrollListener.SCROLL_STATE_TOUCH_SCROLL) { 627206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov int deltaDownY = (int) Math.abs(currentMoveY - mLastDownEventY); 628206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (deltaDownY > mTouchSlop) { 629206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mBeginEditOnUpEvent = false; 63050f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov tryNotifyScrollListener(OnScrollListener.SCROLL_STATE_TOUCH_SCROLL); 631206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 632206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 633206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov int deltaMoveY = (int) (currentMoveY - mLastMotionEventY); 634206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov scrollBy(0, deltaMoveY); 635206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov invalidate(); 636206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mLastMotionEventY = currentMoveY; 637206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov break; 638206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov case MotionEvent.ACTION_UP: 639206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (mBeginEditOnUpEvent) { 640206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov setDrawSelectorWheel(false); 641206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov showInputControls(); 642206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mInputText.requestFocus(); 643206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov InputMethodManager imm = (InputMethodManager) getContext().getSystemService( 644206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov Context.INPUT_METHOD_SERVICE); 645206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov imm.showSoftInput(mInputText, 0); 64650f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov mInputText.setSelection(0, mInputText.getText().length()); 647206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return true; 648206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 649206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov VelocityTracker velocityTracker = mVelocityTracker; 650206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov velocityTracker.computeCurrentVelocity(1000, mMaximumFlingVelocity); 651206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov int initialVelocity = (int) velocityTracker.getYVelocity(); 652206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (Math.abs(initialVelocity) > mMinimumFlingVelocity) { 653206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov fling(initialVelocity); 65450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov tryNotifyScrollListener(OnScrollListener.SCROLL_STATE_FLING); 655206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } else { 656206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (mAdjustScrollerOnUpEvent) { 657206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (mFlingScroller.isFinished() && mAdjustScroller.isFinished()) { 658206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov postAdjustScrollerCommand(0); 659206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 660206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } else { 661206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov postAdjustScrollerCommand(SHOW_INPUT_CONTROLS_DELAY_MILLIS); 662206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 663206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 664206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mVelocityTracker.recycle(); 665206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mVelocityTracker = null; 666206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov break; 667206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 668206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return true; 669206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 670206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 671206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov @Override 672206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov public boolean dispatchTouchEvent(MotionEvent event) { 673206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov int action = event.getActionMasked(); 674206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if ((action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) 675206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov && !isEventInInputText(event)) { 676206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov removeAllCallbacks(); 677206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 678206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return super.dispatchTouchEvent(event); 679206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 680206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 681206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov @Override 682206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov public boolean dispatchKeyEvent(KeyEvent event) { 683206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov int keyCode = event.getKeyCode(); 684206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER || keyCode == KeyEvent.KEYCODE_ENTER) { 685206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov removeAllCallbacks(); 686206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 687206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return super.dispatchKeyEvent(event); 688206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 689206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 690206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov @Override 691206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov public boolean dispatchTrackballEvent(MotionEvent event) { 692206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov int action = event.getActionMasked(); 693206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) { 694206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov removeAllCallbacks(); 695206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 696206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return super.dispatchTrackballEvent(event); 697206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 6989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 699206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov @Override 700206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov public void computeScroll() { 701206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (!mDrawSelectorWheel) { 702206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return; 703206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 704206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov Scroller scroller = mFlingScroller; 705206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (scroller.isFinished()) { 706206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov scroller = mAdjustScroller; 707206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (scroller.isFinished()) { 708206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return; 709206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 710206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 711206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov scroller.computeScrollOffset(); 712206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov int currentScrollerY = scroller.getCurrY(); 713206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (mPreviousScrollerY == 0) { 714206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mPreviousScrollerY = scroller.getStartY(); 715206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 716206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov scrollBy(0, currentScrollerY - mPreviousScrollerY); 717206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mPreviousScrollerY = currentScrollerY; 718206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (scroller.isFinished()) { 719206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov onScrollerFinished(scroller); 720206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } else { 721206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov invalidate(); 7229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 724fdf6db6748b32f620a7f68b13a67c38b4e59e5edTom Taylor 7259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 7269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void setEnabled(boolean enabled) { 7279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project super.setEnabled(enabled); 7289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mIncrementButton.setEnabled(enabled); 7299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mDecrementButton.setEnabled(enabled); 730206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mInputText.setEnabled(enabled); 731206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 732206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 733206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov @Override 734206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov public void scrollBy(int x, int y) { 735206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov int[] selectorIndices = getSelectorIndices(); 736206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (mInitialScrollOffset == Integer.MIN_VALUE) { 737206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov int totalTextHeight = selectorIndices.length * mTextSize; 738206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov int totalTextGapHeight = (mBottom - mTop) - totalTextHeight; 739206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov int textGapCount = selectorIndices.length - 1; 740206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov int selectorTextGapHeight = totalTextGapHeight / textGapCount; 741206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // compensate for integer division loss of the components used to 742206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // calculate the text gap 743206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov int integerDivisionLoss = (mTextSize + mBottom - mTop) % textGapCount; 744206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mInitialScrollOffset = mCurrentScrollOffset = mTextSize - integerDivisionLoss / 2; 745206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mSelectorElementHeight = mTextSize + selectorTextGapHeight; 746206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 747206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 74834c0688ceafbeef2648bd2287b3b3c3801679448Svetoslav Ganov if (!mWrapSelectorWheel && y > 0 74934c0688ceafbeef2648bd2287b3b3c3801679448Svetoslav Ganov && selectorIndices[SELECTOR_MIDDLE_ITEM_INDEX] <= mMinValue) { 750206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mCurrentScrollOffset = mInitialScrollOffset; 751206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return; 752206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 75334c0688ceafbeef2648bd2287b3b3c3801679448Svetoslav Ganov if (!mWrapSelectorWheel && y < 0 75434c0688ceafbeef2648bd2287b3b3c3801679448Svetoslav Ganov && selectorIndices[SELECTOR_MIDDLE_ITEM_INDEX] >= mMaxValue) { 755206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mCurrentScrollOffset = mInitialScrollOffset; 756206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return; 757206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 758206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mCurrentScrollOffset += y; 7596c742f1e95dfe1f808bf02fadd5fbf9660b95050Svetoslav Ganov while (mCurrentScrollOffset - mInitialScrollOffset >= mSelectorElementHeight) { 760206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mCurrentScrollOffset -= mSelectorElementHeight; 761206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov decrementSelectorIndices(selectorIndices); 762206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov changeCurrent(selectorIndices[SELECTOR_MIDDLE_ITEM_INDEX]); 763e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov if (selectorIndices[SELECTOR_MIDDLE_ITEM_INDEX] <= mMinValue) { 764206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mCurrentScrollOffset = mInitialScrollOffset; 765206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 766206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 7676c742f1e95dfe1f808bf02fadd5fbf9660b95050Svetoslav Ganov while (mCurrentScrollOffset - mInitialScrollOffset <= -mSelectorElementHeight) { 768206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mCurrentScrollOffset += mSelectorElementHeight; 769206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov incrementScrollSelectorIndices(selectorIndices); 770206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov changeCurrent(selectorIndices[SELECTOR_MIDDLE_ITEM_INDEX]); 771e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov if (selectorIndices[SELECTOR_MIDDLE_ITEM_INDEX] >= mMaxValue) { 772206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mCurrentScrollOffset = mInitialScrollOffset; 773206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 774206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 7759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 776fdf6db6748b32f620a7f68b13a67c38b4e59e5edTom Taylor 7774bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov @Override 7784bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov public int getSolidColor() { 7794bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov return mSolidColor; 7804bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov } 7814bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov 78268f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook /** 7834bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * Sets the listener to be notified on change of the current value. 784206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * 785e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @param onValueChangedListener The listener. 78668f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook */ 787cedc446684e94c9971c38c3206f1f224314bda2aSvetoslav Ganov public void setOnValueChangedListener(OnValueChangeListener onValueChangedListener) { 788cedc446684e94c9971c38c3206f1f224314bda2aSvetoslav Ganov mOnValueChangeListener = onValueChangedListener; 78950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov } 79050f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 79150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov /** 7924bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * Set listener to be notified for scroll state changes. 79350f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * 794e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @param onScrollListener The listener. 79550f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov */ 79650f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov public void setOnScrollListener(OnScrollListener onScrollListener) { 79750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov mOnScrollListener = onScrollListener; 7989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 799fdf6db6748b32f620a7f68b13a67c38b4e59e5edTom Taylor 80068f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook /** 8014bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * Set the formatter to be used for formatting the current value. 8024bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * <p> 803e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * Note: If you have provided alternative values for the values this 804e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * formatter is never invoked. 8054bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * </p> 806206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * 807e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @param formatter The formatter object. If formatter is <code>null</code>, 808e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * {@link String#valueOf(int)} will be used. 8094bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * 810e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @see #setDisplayedValues(String[]) 81168f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook */ 8129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void setFormatter(Formatter formatter) { 813e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov if (formatter == mFormatter) { 814e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov return; 815e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov } 8169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mFormatter = formatter; 817e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov resetSelectorWheelIndices(); 818206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 819206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 820206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 821e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * Set the current value for the number picker. 8224bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * <p> 823e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * If the argument is less than the {@link NumberPicker#getMinValue()} and 824e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * {@link NumberPicker#getWrapSelectorWheel()} is <code>false</code> the 825e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * current value is set to the {@link NumberPicker#getMinValue()} value. 826e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * </p> 827e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * <p> 828e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * If the argument is less than the {@link NumberPicker#getMinValue()} and 829e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * {@link NumberPicker#getWrapSelectorWheel()} is <code>true</code> the 830e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * current value is set to the {@link NumberPicker#getMaxValue()} value. 831e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * </p> 832e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * <p> 833e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * If the argument is less than the {@link NumberPicker#getMaxValue()} and 834e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * {@link NumberPicker#getWrapSelectorWheel()} is <code>false</code> the 835e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * current value is set to the {@link NumberPicker#getMaxValue()} value. 836e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * </p> 837e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * <p> 838e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * If the argument is less than the {@link NumberPicker#getMaxValue()} and 839e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * {@link NumberPicker#getWrapSelectorWheel()} is <code>true</code> the 840e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * current value is set to the {@link NumberPicker#getMinValue()} value. 8414bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * </p> 842206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * 843e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @param value The current value. 8444bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * @see #setWrapSelectorWheel(boolean) 845e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @see #setMinValue(int) 846e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @see #setMaxValue(int) 847206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 848e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov public void setValue(int value) { 849e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov if (mValue == value) { 850a911d4a2b1be7e9ea909a579167826e4a5bac1a3Svetoslav Ganov return; 851a911d4a2b1be7e9ea909a579167826e4a5bac1a3Svetoslav Ganov } 852e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov if (value < mMinValue) { 853e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov value = mWrapSelectorWheel ? mMaxValue : mMinValue; 854206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 855e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov if (value > mMaxValue) { 856e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov value = mWrapSelectorWheel ? mMinValue : mMaxValue; 8578bcbebd4178b2e9aca9ee3bd9e1e12c42e74c8dbAdam Powell } 858e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov mValue = value; 859e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov updateInputTextView(); 860e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov updateIncrementAndDecrementButtonsVisibilityState(); 8619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 862fdf6db6748b32f620a7f68b13a67c38b4e59e5edTom Taylor 86368f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook /** 864e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * Gets whether the selector wheel wraps when reaching the min/max value. 86568f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook * 866e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @return True if the selector wheel wraps. 8674bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * 868e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @see #getMinValue() 869e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @see #getMaxValue() 87068f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook */ 871e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov public boolean getWrapSelectorWheel() { 872e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov return mWrapSelectorWheel; 873206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 874206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 875206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 876e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * Sets whether the selector wheel shown during flinging/scrolling should 877e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * wrap around the {@link NumberPicker#getMinValue()} and 878e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * {@link NumberPicker#getMaxValue()} values. 879e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * <p> 880e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * By default if the range (max - min) is more than five (the number of 881e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * items shown on the selector wheel) the selector wheel wrapping is 882e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * enabled. 883e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * </p> 884206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * 885206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * @param wrapSelector Whether to wrap. 886206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 8874bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov public void setWrapSelectorWheel(boolean wrapSelector) { 888e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov if (wrapSelector && (mMaxValue - mMinValue) < mSelectorIndices.length) { 889206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov throw new IllegalStateException("Range less than selector items count."); 890206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 891e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov if (wrapSelector != mWrapSelectorWheel) { 892206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // force the selector indices array to be reinitialized 893206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mSelectorIndices[SELECTOR_MIDDLE_ITEM_INDEX] = Integer.MAX_VALUE; 894e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov mWrapSelectorWheel = wrapSelector; 895206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 8969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 8994bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * Sets the speed at which the numbers be incremented and decremented when 9004bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * the up and down buttons are long pressed respectively. 901e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * <p> 902e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * The default value is 300 ms. 903e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * </p> 90468f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook * 9054bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * @param intervalMillis The speed (in milliseconds) at which the numbers 906e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * will be incremented and decremented. 9079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 9084bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov public void setOnLongPressUpdateInterval(long intervalMillis) { 9094bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov mLongPressUpdateInterval = intervalMillis; 9109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 911fdf6db6748b32f620a7f68b13a67c38b4e59e5edTom Taylor 912206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 913e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * Returns the value of the picker. 914e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * 915e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @return The value. 916e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov */ 917e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov public int getValue() { 918e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov return mValue; 919e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov } 920e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov 921e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov /** 922e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * Returns the min value of the picker. 923e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * 924e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @return The min value 925e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov */ 926e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov public int getMinValue() { 927e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov return mMinValue; 928e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov } 929e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov 930e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov /** 931e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * Sets the min value of the picker. 932206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * 933e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @param minValue The min value. 934206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 935e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov public void setMinValue(int minValue) { 936e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov if (mMinValue == minValue) { 937e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov return; 938e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov } 939e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov if (minValue < 0) { 940e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov throw new IllegalArgumentException("minValue must be >= 0"); 941e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov } 942e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov mMinValue = minValue; 943e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov if (mMinValue > mValue) { 944e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov mValue = mMinValue; 945e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov } 946e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov boolean wrapSelectorWheel = mMaxValue - mMinValue > mSelectorIndices.length; 947e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov setWrapSelectorWheel(wrapSelectorWheel); 948e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov resetSelectorWheelIndices(); 949e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov updateInputTextView(); 950e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov updateIncrementAndDecrementButtonsVisibilityState(); 951206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 952206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 9534bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov /** 954e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * Returns the max value of the picker. 9554bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * 956e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @return The max value. 9574bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov */ 958e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov public int getMaxValue() { 959e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov return mMaxValue; 9604bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov } 9614bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov 9624bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov /** 963e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * Sets the max value of the picker. 9644bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * 965e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @param maxValue The max value. 9664bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov */ 967e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov public void setMaxValue(int maxValue) { 968e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov if (mMaxValue == maxValue) { 969e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov return; 970e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov } 971e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov if (maxValue < 0) { 972e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov throw new IllegalArgumentException("maxValue must be >= 0"); 973e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov } 974e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov mMaxValue = maxValue; 975e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov if (mMaxValue < mValue) { 976e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov mValue = mMaxValue; 977e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov } 978e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov boolean wrapSelectorWheel = mMaxValue - mMinValue > mSelectorIndices.length; 979e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov setWrapSelectorWheel(wrapSelectorWheel); 980e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov resetSelectorWheelIndices(); 981e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov updateInputTextView(); 982e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov updateIncrementAndDecrementButtonsVisibilityState(); 983e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov } 984e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov 985e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov /** 986e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * Gets the values to be displayed instead of string values. 987e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * 988e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @return The displayed values. 989e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov */ 990e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov public String[] getDisplayedValues() { 991e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov return mDisplayedValues; 992e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov } 993e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov 994e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov /** 995e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * Sets the values to be displayed. 996e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * 997e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @param displayedValues The displayed values. 998e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov */ 999e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov public void setDisplayedValues(String[] displayedValues) { 1000e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov if (mDisplayedValues == displayedValues) { 1001e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov return; 1002e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov } 1003e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov mDisplayedValues = displayedValues; 1004e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov if (mDisplayedValues != null) { 1005e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov // Allow text entry rather than strictly numeric entry. 1006e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov mInputText.setRawInputType(InputType.TYPE_CLASS_TEXT 1007e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov | InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS); 1008e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov } else { 1009e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov mInputText.setRawInputType(InputType.TYPE_CLASS_NUMBER); 1010e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov } 1011e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov updateInputTextView(); 1012e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov resetSelectorWheelIndices(); 1013206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1014206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 1015206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov @Override 1016206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov protected float getTopFadingEdgeStrength() { 1017206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return TOP_AND_BOTTOM_FADING_EDGE_STRENGTH; 1018206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1019206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 1020206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov @Override 1021206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov protected float getBottomFadingEdgeStrength() { 1022206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return TOP_AND_BOTTOM_FADING_EDGE_STRENGTH; 1023206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1024206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 1025206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov @Override 1026206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov protected void onDetachedFromWindow() { 1027206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov removeAllCallbacks(); 1028206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1029206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 1030206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov @Override 1031206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov protected void dispatchDraw(Canvas canvas) { 1032206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // There is a good reason for doing this. See comments in draw(). 1033206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1034206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 1035206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov @Override 1036206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov public void draw(Canvas canvas) { 1037206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // Dispatch draw to our children only if we are not currently running 1038206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // the animation for simultaneously fading out the scroll wheel and 1039206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // showing in the buttons. This class takes advantage of the View 1040206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // implementation of fading edges effect to draw the selector wheel. 1041206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // However, in View.draw(), the fading is applied after all the children 1042206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // have been drawn and we do not want this fading to be applied to the 1043206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // buttons which are currently showing in. Therefore, we draw our 1044206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // children 1045206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // after we have completed drawing ourselves. 1046206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 1047c75ec3324e9e3e6500148cc2978caab90ea962e4Chet Haase super.draw(canvas); 1048206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 1049206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // Draw our children if we are not showing the selector wheel of fading 1050206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // it out 1051206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (mShowInputControlsAnimator.isRunning() || !mDrawSelectorWheel) { 1052206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov long drawTime = getDrawingTime(); 1053206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov for (int i = 0, count = getChildCount(); i < count; i++) { 1054206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov View child = getChildAt(i); 1055206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (!child.isShown()) { 1056206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov continue; 1057206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1058206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov drawChild(canvas, getChildAt(i), drawTime); 1059206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1060206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1061206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1062206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 1063206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov @Override 1064206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov protected void onDraw(Canvas canvas) { 1065206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // we only draw the selector wheel 1066206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (!mDrawSelectorWheel) { 1067206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return; 1068206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1069206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov float x = (mRight - mLeft) / 2; 1070206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov float y = mCurrentScrollOffset; 1071206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 1072206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov int[] selectorIndices = getSelectorIndices(); 1073206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov for (int i = 0; i < selectorIndices.length; i++) { 1074206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov int selectorIndex = selectorIndices[i]; 1075206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov String scrollSelectorValue = mSelectorIndexToStringCache.get(selectorIndex); 1076206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov canvas.drawText(scrollSelectorValue, x, y, mSelectorPaint); 1077206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov y += mSelectorElementHeight; 1078206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 10799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1080fdf6db6748b32f620a7f68b13a67c38b4e59e5edTom Taylor 108168f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook /** 1082a911d4a2b1be7e9ea909a579167826e4a5bac1a3Svetoslav Ganov * Resets the selector indices and clear the cached 1083a911d4a2b1be7e9ea909a579167826e4a5bac1a3Svetoslav Ganov * string representation of these indices. 1084a911d4a2b1be7e9ea909a579167826e4a5bac1a3Svetoslav Ganov */ 1085e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov private void resetSelectorWheelIndices() { 1086a911d4a2b1be7e9ea909a579167826e4a5bac1a3Svetoslav Ganov mSelectorIndexToStringCache.clear(); 1087a911d4a2b1be7e9ea909a579167826e4a5bac1a3Svetoslav Ganov int[] selectorIdices = getSelectorIndices(); 1088a911d4a2b1be7e9ea909a579167826e4a5bac1a3Svetoslav Ganov for (int i = 0; i < selectorIdices.length; i++) { 1089a911d4a2b1be7e9ea909a579167826e4a5bac1a3Svetoslav Ganov selectorIdices[i] = Integer.MIN_VALUE; 1090a911d4a2b1be7e9ea909a579167826e4a5bac1a3Svetoslav Ganov } 1091a911d4a2b1be7e9ea909a579167826e4a5bac1a3Svetoslav Ganov } 1092a911d4a2b1be7e9ea909a579167826e4a5bac1a3Svetoslav Ganov 1093a911d4a2b1be7e9ea909a579167826e4a5bac1a3Svetoslav Ganov /** 1094206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Sets the current value of this NumberPicker, and sets mPrevious to the 1095206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * previous value. If current is greater than mEnd less than mStart, the 1096206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * value of mCurrent is wrapped around. Subclasses can override this to 1097206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * change the wrapping behavior 109868f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook * 109968f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook * @param current the new value of the NumberPicker 110068f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook */ 1101206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private void changeCurrent(int current) { 1102e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov if (mValue == current) { 1103206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return; 1104206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 11059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Wrap around the values if we go past the start or end 1106e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov if (mWrapSelectorWheel) { 1107206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov current = getWrappedSelectorIndex(current); 11089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1109e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov int previous = mValue; 1110e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov setValue(current); 1111206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov notifyChange(previous, current); 11129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1113fdf6db6748b32f620a7f68b13a67c38b4e59e5edTom Taylor 111468f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook /** 1115206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Sets the <code>alpha</code> of the {@link Paint} for drawing the selector 1116206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * wheel. 111768f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook */ 1118206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov @SuppressWarnings("unused") 1119206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // Called by ShowInputControlsAnimator via reflection 1120206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private void setSelectorPaintAlpha(int alpha) { 1121206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mSelectorPaint.setAlpha(alpha); 1122206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (mDrawSelectorWheel) { 1123206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov invalidate(); 11249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 112768f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook /** 1128206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * @return If the <code>event</code> is in the input text. 112968f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook */ 1130206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private boolean isEventInInputText(MotionEvent event) { 1131206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mInputText.getHitRect(mTempRect); 1132206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return mTempRect.contains((int) event.getX(), (int) event.getY()); 1133206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1134206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 1135206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 1136206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Sets if to <code>drawSelectionWheel</code>. 1137206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 1138206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private void setDrawSelectorWheel(boolean drawSelectorWheel) { 1139206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mDrawSelectorWheel = drawSelectorWheel; 1140206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // do not fade if the selector wheel not shown 1141206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov setVerticalFadingEdgeEnabled(drawSelectorWheel); 1142206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1143206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 1144206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 1145206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Callback invoked upon completion of a given <code>scroller</code>. 1146206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 1147206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private void onScrollerFinished(Scroller scroller) { 1148206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (scroller == mFlingScroller) { 1149206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov postAdjustScrollerCommand(0); 115050f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov tryNotifyScrollListener(OnScrollListener.SCROLL_STATE_IDLE); 11519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 1152206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov updateInputTextView(); 11536c742f1e95dfe1f808bf02fadd5fbf9660b95050Svetoslav Ganov showInputControls(); 11549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1156fdf6db6748b32f620a7f68b13a67c38b4e59e5edTom Taylor 1157206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 115850f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * Notifies the scroll listener for the given <code>scrollState</code> 115950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * if the scroll state differs from the current scroll state. 116050f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov */ 116150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov private void tryNotifyScrollListener(int scrollState) { 116250f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov if (mOnScrollListener != null && mScrollState != scrollState) { 116350f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov mScrollState = scrollState; 11644bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov mOnScrollListener.onScrollStateChange(this, scrollState); 116550f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov } 116650f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov } 116750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 116850f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov /** 1169206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Flings the selector with the given <code>velocityY</code>. 1170206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 1171206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private void fling(int velocityY) { 1172206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mPreviousScrollerY = 0; 1173206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov Scroller flingScroller = mFlingScroller; 1174206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 1175e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov if (mWrapSelectorWheel) { 1176206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (velocityY > 0) { 1177206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov flingScroller.fling(0, 0, 0, velocityY, 0, 0, 0, Integer.MAX_VALUE); 1178206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } else { 1179206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov flingScroller.fling(0, Integer.MAX_VALUE, 0, velocityY, 0, 0, 0, Integer.MAX_VALUE); 1180206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1181206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } else { 1182206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (velocityY > 0) { 1183e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov int maxY = mTextSize * (mValue - mMinValue); 1184206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov flingScroller.fling(0, 0, 0, velocityY, 0, 0, 0, maxY); 1185206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } else { 1186e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov int startY = mTextSize * (mMaxValue - mValue); 1187206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov int maxY = startY; 1188206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov flingScroller.fling(0, startY, 0, velocityY, 0, 0, 0, maxY); 11892bf761c20253222a763bce9a63d14c48ab08a556Suchi Amalapurapu } 11909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1191206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 1192206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov postAdjustScrollerCommand(flingScroller.getDuration()); 1193206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov invalidate(); 11949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1196206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 1197206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Hides the input controls which is the up/down arrows and the text field. 1198206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 1199206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private void hideInputControls() { 1200206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mShowInputControlsAnimator.cancel(); 1201206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mIncrementButton.setVisibility(INVISIBLE); 1202206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mDecrementButton.setVisibility(INVISIBLE); 1203206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mInputText.setVisibility(INVISIBLE); 1204206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1205c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 1206206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 1207206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Show the input controls by making them visible and animating the alpha 1208206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * property up/down arrows. 1209206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 1210206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private void showInputControls() { 1211206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov updateIncrementAndDecrementButtonsVisibilityState(); 1212206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mInputText.setVisibility(VISIBLE); 1213206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mShowInputControlsAnimator.start(); 1214206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1215c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 1216206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 1217206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Updates the visibility state of the increment and decrement buttons. 1218206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 1219206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private void updateIncrementAndDecrementButtonsVisibilityState() { 1220e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov if (mWrapSelectorWheel || mValue < mMaxValue) { 1221206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mIncrementButton.setVisibility(VISIBLE); 1222206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } else { 1223206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mIncrementButton.setVisibility(INVISIBLE); 1224206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1225e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov if (mWrapSelectorWheel || mValue > mMinValue) { 1226206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mDecrementButton.setVisibility(VISIBLE); 1227206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } else { 1228206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mDecrementButton.setVisibility(INVISIBLE); 12299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1233206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * @return The selector indices array with proper values with the current as 1234206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * the middle one. 12359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1236206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private int[] getSelectorIndices() { 1237e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov int current = getValue(); 1238206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (mSelectorIndices[SELECTOR_MIDDLE_ITEM_INDEX] != current) { 1239206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov for (int i = 0; i < mSelectorIndices.length; i++) { 1240206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov int selectorIndex = current + (i - SELECTOR_MIDDLE_ITEM_INDEX); 1241e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov if (mWrapSelectorWheel) { 1242206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov selectorIndex = getWrappedSelectorIndex(selectorIndex); 1243206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1244206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mSelectorIndices[i] = selectorIndex; 1245206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov ensureCachedScrollSelectorValue(mSelectorIndices[i]); 1246206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1247206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1248206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return mSelectorIndices; 12499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1250fdf6db6748b32f620a7f68b13a67c38b4e59e5edTom Taylor 125168f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook /** 1252206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * @return The wrapped index <code>selectorIndex</code> value. 125368f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook */ 1254206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private int getWrappedSelectorIndex(int selectorIndex) { 1255e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov if (selectorIndex > mMaxValue) { 1256e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov return mMinValue + (selectorIndex - mMaxValue) % (mMaxValue - mMinValue) - 1; 1257e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov } else if (selectorIndex < mMinValue) { 1258e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov return mMaxValue - (mMinValue - selectorIndex) % (mMaxValue - mMinValue) + 1; 1259206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1260206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return selectorIndex; 12619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1262fdf6db6748b32f620a7f68b13a67c38b4e59e5edTom Taylor 1263206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 1264206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Increments the <code>selectorIndices</code> whose string representations 1265206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * will be displayed in the selector. 1266206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 1267206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private void incrementScrollSelectorIndices(int[] selectorIndices) { 1268206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov for (int i = 0; i < selectorIndices.length - 1; i++) { 1269206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov selectorIndices[i] = selectorIndices[i + 1]; 1270206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1271206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov int nextScrollSelectorIndex = selectorIndices[selectorIndices.length - 2] + 1; 1272e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov if (mWrapSelectorWheel && nextScrollSelectorIndex > mMaxValue) { 1273e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov nextScrollSelectorIndex = mMinValue; 1274206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1275206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov selectorIndices[selectorIndices.length - 1] = nextScrollSelectorIndex; 1276206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov ensureCachedScrollSelectorValue(nextScrollSelectorIndex); 1277206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1278fdf6db6748b32f620a7f68b13a67c38b4e59e5edTom Taylor 1279206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 1280206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Decrements the <code>selectorIndices</code> whose string representations 1281206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * will be displayed in the selector. 1282206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 1283206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private void decrementSelectorIndices(int[] selectorIndices) { 1284206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov for (int i = selectorIndices.length - 1; i > 0; i--) { 1285206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov selectorIndices[i] = selectorIndices[i - 1]; 1286206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1287206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov int nextScrollSelectorIndex = selectorIndices[1] - 1; 1288e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov if (mWrapSelectorWheel && nextScrollSelectorIndex < mMinValue) { 1289e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov nextScrollSelectorIndex = mMaxValue; 1290206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1291206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov selectorIndices[0] = nextScrollSelectorIndex; 1292206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov ensureCachedScrollSelectorValue(nextScrollSelectorIndex); 1293206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1294fdf6db6748b32f620a7f68b13a67c38b4e59e5edTom Taylor 1295206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 1296206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Ensures we have a cached string representation of the given <code> 1297206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * selectorIndex</code> 1298206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * to avoid multiple instantiations of the same string. 1299206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 1300206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private void ensureCachedScrollSelectorValue(int selectorIndex) { 1301206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov SparseArray<String> cache = mSelectorIndexToStringCache; 1302206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov String scrollSelectorValue = cache.get(selectorIndex); 1303206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (scrollSelectorValue != null) { 1304206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return; 1305206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1306e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov if (selectorIndex < mMinValue || selectorIndex > mMaxValue) { 1307206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov scrollSelectorValue = ""; 1308206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } else { 1309206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (mDisplayedValues != null) { 1310e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov int displayedValueIndex = selectorIndex - mMinValue; 131150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov scrollSelectorValue = mDisplayedValues[displayedValueIndex]; 1312206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } else { 1313206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov scrollSelectorValue = formatNumber(selectorIndex); 13149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1316206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov cache.put(selectorIndex, scrollSelectorValue); 13179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1318fdf6db6748b32f620a7f68b13a67c38b4e59e5edTom Taylor 1319206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private String formatNumber(int value) { 1320e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov return (mFormatter != null) ? mFormatter.format(value) : String.valueOf(value); 1321206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 13229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1323206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private void validateInputTextView(View v) { 1324206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov String str = String.valueOf(((TextView) v).getText()); 1325206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (TextUtils.isEmpty(str)) { 1326206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // Restore to the old value as we don't allow empty values 1327206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov updateInputTextView(); 1328206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } else { 1329206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // Check the new value and ensure it's in range 1330206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov int current = getSelectedPos(str.toString()); 1331206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov changeCurrent(current); 13329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1333206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1334fdf6db6748b32f620a7f68b13a67c38b4e59e5edTom Taylor 1335206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 1336206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Updates the view of this NumberPicker. If displayValues were specified in 1337206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * {@link #setRange}, the string corresponding to the index specified by the 1338206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * current value will be returned. Otherwise, the formatter specified in 1339206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * {@link #setFormatter} will be used to format the number. 1340206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 1341206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private void updateInputTextView() { 1342206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /* 1343206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * If we don't have displayed values then use the current number else 1344206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * find the correct value in the displayed values for the current 1345206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * number. 1346206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 1347206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (mDisplayedValues == null) { 1348e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov mInputText.setText(formatNumber(mValue)); 1349206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } else { 1350e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov mInputText.setText(mDisplayedValues[mValue - mMinValue]); 13519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1352206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mInputText.setSelection(mInputText.getText().length()); 1353206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1354fdf6db6748b32f620a7f68b13a67c38b4e59e5edTom Taylor 1355206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 1356206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Notifies the listener, if registered, of a change of the value of this 1357206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * NumberPicker. 1358206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 1359206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private void notifyChange(int previous, int current) { 1360cedc446684e94c9971c38c3206f1f224314bda2aSvetoslav Ganov if (mOnValueChangeListener != null) { 1361cedc446684e94c9971c38c3206f1f224314bda2aSvetoslav Ganov mOnValueChangeListener.onValueChange(this, previous, mValue); 1362206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1363206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 13649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1365206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 1366206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Posts a command for updating the current value every <code>updateMillis 1367206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * </code>. 1368206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 1369206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private void postUpdateValueFromLongPress(int updateMillis) { 1370206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mInputText.clearFocus(); 1371206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov removeAllCallbacks(); 1372206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (mUpdateFromLongPressCommand == null) { 1373206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mUpdateFromLongPressCommand = new UpdateValueFromLongPressCommand(); 1374206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1375206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mUpdateFromLongPressCommand.setUpdateStep(updateMillis); 1376206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov post(mUpdateFromLongPressCommand); 1377206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 13789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1379206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 1380206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Removes all pending callback from the message queue. 1381206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 1382206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private void removeAllCallbacks() { 1383206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (mUpdateFromLongPressCommand != null) { 1384206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov removeCallbacks(mUpdateFromLongPressCommand); 1385206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1386206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (mAdjustScrollerCommand != null) { 1387206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov removeCallbacks(mAdjustScrollerCommand); 1388206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1389206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (mSetSelectionCommand != null) { 1390206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov removeCallbacks(mSetSelectionCommand); 13919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1394206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 1395206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * @return The selected index given its displayed <code>value</code>. 1396206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 1397206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private int getSelectedPos(String value) { 13989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mDisplayedValues == null) { 1399aa516beb79693ceffbd81a7c9d14c940e412cccbRomain Guy try { 1400206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return Integer.parseInt(value); 1401aa516beb79693ceffbd81a7c9d14c940e412cccbRomain Guy } catch (NumberFormatException e) { 1402206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // Ignore as if it's not a number we don't care 1403aa516beb79693ceffbd81a7c9d14c940e412cccbRomain Guy } 14049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 14059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < mDisplayedValues.length; i++) { 1406206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // Don't force the user to type in jan when ja will do 1407206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov value = value.toLowerCase(); 1408206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (mDisplayedValues[i].toLowerCase().startsWith(value)) { 1409e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov return mMinValue + i; 14109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1412fdf6db6748b32f620a7f68b13a67c38b4e59e5edTom Taylor 1413206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /* 1414206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * The user might have typed in a number into the month field i.e. 14159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 10 instead of OCT so support that too. 14169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 14179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 1418206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return Integer.parseInt(value); 14199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (NumberFormatException e) { 1420fdf6db6748b32f620a7f68b13a67c38b4e59e5edTom Taylor 1421206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // Ignore as if it's not a number we don't care 14229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1424e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov return mMinValue; 14259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 14279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1428206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Posts an {@link SetSelectionCommand} from the given <code>selectionStart 1429206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * </code> to 1430206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * <code>selectionEnd</code>. 14319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1432206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private void postSetSelectionCommand(int selectionStart, int selectionEnd) { 1433206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (mSetSelectionCommand == null) { 1434206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mSetSelectionCommand = new SetSelectionCommand(); 1435206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } else { 1436206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov removeCallbacks(mSetSelectionCommand); 1437206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1438206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mSetSelectionCommand.mSelectionStart = selectionStart; 1439206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mSetSelectionCommand.mSelectionEnd = selectionEnd; 1440206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov post(mSetSelectionCommand); 14419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 144268f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook 144368f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook /** 1444206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Posts an {@link AdjustScrollerCommand} within the given <code> 1445206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * delayMillis</code> 1446206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * . 144768f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook */ 1448206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private void postAdjustScrollerCommand(int delayMillis) { 1449206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (mAdjustScrollerCommand == null) { 1450206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mAdjustScrollerCommand = new AdjustScrollerCommand(); 1451206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } else { 1452206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov removeCallbacks(mAdjustScrollerCommand); 1453206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1454206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov postDelayed(mAdjustScrollerCommand, delayMillis); 145568f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook } 145668f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook 145768f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook /** 1458206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Filter for accepting only valid indices or prefixes of the string 1459206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * representation of valid indices. 146068f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook */ 1461206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov class InputTextFilter extends NumberKeyListener { 1462206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 1463206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // XXX This doesn't allow for range limits when controlled by a 1464206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // soft input method! 1465206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov public int getInputType() { 1466206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return InputType.TYPE_CLASS_TEXT; 1467206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1468206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 1469206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov @Override 1470206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov protected char[] getAcceptedChars() { 1471206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return DIGIT_CHARACTERS; 1472206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1473206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 1474206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov @Override 1475206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov public CharSequence filter(CharSequence source, int start, int end, Spanned dest, 1476206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov int dstart, int dend) { 1477206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (mDisplayedValues == null) { 1478206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov CharSequence filtered = super.filter(source, start, end, dest, dstart, dend); 1479206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (filtered == null) { 1480206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov filtered = source.subSequence(start, end); 1481206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1482206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 1483206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov String result = String.valueOf(dest.subSequence(0, dstart)) + filtered 1484206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov + dest.subSequence(dend, dest.length()); 1485206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 1486206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if ("".equals(result)) { 1487206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return result; 1488206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1489206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov int val = getSelectedPos(result); 1490206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 1491206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /* 1492206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Ensure the user can't type in a value greater than the max 1493206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * allowed. We have to allow less than min as the user might 1494206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * want to delete some numbers and then type a new number. 1495206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 1496e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov if (val > mMaxValue) { 1497206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return ""; 1498206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } else { 1499206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return filtered; 1500206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1501206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } else { 1502206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov CharSequence filtered = String.valueOf(source.subSequence(start, end)); 1503206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (TextUtils.isEmpty(filtered)) { 1504206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return ""; 1505206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1506206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov String result = String.valueOf(dest.subSequence(0, dstart)) + filtered 1507206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov + dest.subSequence(dend, dest.length()); 1508206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov String str = String.valueOf(result).toLowerCase(); 1509206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov for (String val : mDisplayedValues) { 1510206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov String valLowerCase = val.toLowerCase(); 1511206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (valLowerCase.startsWith(str)) { 1512206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov postSetSelectionCommand(result.length(), val.length()); 1513206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return val.subSequence(dstart, val.length()); 1514206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1515206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1516206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return ""; 1517206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1518206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1519206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1520206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 1521206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 1522206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Command for setting the input text selection. 1523206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 1524206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov class SetSelectionCommand implements Runnable { 1525206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private int mSelectionStart; 1526206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 1527206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private int mSelectionEnd; 1528206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 1529206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov public void run() { 1530206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mInputText.setSelection(mSelectionStart, mSelectionEnd); 1531206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1532206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1533206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 1534206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 1535206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Command for adjusting the scroller to show in its center the closest of 1536206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * the displayed items. 1537206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 1538206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov class AdjustScrollerCommand implements Runnable { 1539206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov public void run() { 1540206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mPreviousScrollerY = 0; 154134c0688ceafbeef2648bd2287b3b3c3801679448Svetoslav Ganov if (mInitialScrollOffset == mCurrentScrollOffset) { 154234c0688ceafbeef2648bd2287b3b3c3801679448Svetoslav Ganov updateInputTextView(); 15436c742f1e95dfe1f808bf02fadd5fbf9660b95050Svetoslav Ganov showInputControls(); 154434c0688ceafbeef2648bd2287b3b3c3801679448Svetoslav Ganov return; 154534c0688ceafbeef2648bd2287b3b3c3801679448Svetoslav Ganov } 154634c0688ceafbeef2648bd2287b3b3c3801679448Svetoslav Ganov // adjust to the closest value 1547206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov int deltaY = mInitialScrollOffset - mCurrentScrollOffset; 154834c0688ceafbeef2648bd2287b3b3c3801679448Svetoslav Ganov if (Math.abs(deltaY) > mSelectorElementHeight / 2) { 154934c0688ceafbeef2648bd2287b3b3c3801679448Svetoslav Ganov deltaY += (deltaY > 0) ? -mSelectorElementHeight : mSelectorElementHeight; 155034c0688ceafbeef2648bd2287b3b3c3801679448Svetoslav Ganov } 1551206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov float delayCoef = (float) Math.abs(deltaY) / (float) mTextSize; 1552206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov int duration = (int) (delayCoef * SELECTOR_ADJUSTMENT_DURATION_MILLIS); 1553206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mAdjustScroller.startScroll(0, 0, 0, deltaY, duration); 1554206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov invalidate(); 1555206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1556206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1557206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 1558206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 1559206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Command for updating the current value from a long press. 1560206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 1561206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov class UpdateValueFromLongPressCommand implements Runnable { 1562206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private int mUpdateStep = 0; 1563206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 1564206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private void setUpdateStep(int updateStep) { 1565206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mUpdateStep = updateStep; 1566206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1567206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 1568206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov public void run() { 1569e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov changeCurrent(mValue + mUpdateStep); 15704bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov postDelayed(this, mLongPressUpdateInterval); 1571206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 157268f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook } 15737762d93621f508f4410fd37b5bbdfec0071b0420Paul Westbrook} 1574