NumberPicker.java revision 234484a9fb53786aa8b7ed2a3df7e24d41817689
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 19206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganovimport android.animation.Animator; 20206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganovimport android.animation.AnimatorListenerAdapter; 21206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganovimport android.animation.AnimatorSet; 22206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganovimport android.animation.ObjectAnimator; 2368f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrookimport android.annotation.Widget; 249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Context; 25206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganovimport android.content.res.ColorStateList; 26206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganovimport android.content.res.TypedArray; 27206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganovimport android.graphics.Canvas; 28206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganovimport android.graphics.Color; 29206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganovimport android.graphics.Paint; 30e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganovimport android.graphics.Paint.Align; 31b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganovimport android.graphics.Rect; 329cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganovimport android.graphics.drawable.Drawable; 339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.text.InputFilter; 349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.text.InputType; 359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.text.Spanned; 36206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganovimport android.text.TextUtils; 379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.text.method.NumberKeyListener; 389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.AttributeSet; 39206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganovimport android.util.SparseArray; 409cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganovimport android.util.TypedValue; 41206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganovimport android.view.KeyEvent; 429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.LayoutInflater; 43b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganovimport android.view.LayoutInflater.Filter; 44206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganovimport android.view.MotionEvent; 45206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganovimport android.view.VelocityTracker; 469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.View; 47206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganovimport android.view.ViewConfiguration; 483fec3fe0e3a83c5e0d1264f34bcc55b158537bc6Svetoslav Ganovimport android.view.accessibility.AccessibilityEvent; 493fec3fe0e3a83c5e0d1264f34bcc55b158537bc6Svetoslav Ganovimport android.view.accessibility.AccessibilityManager; 509cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganovimport android.view.animation.DecelerateInterpolator; 51206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganovimport android.view.inputmethod.InputMethodManager; 529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 53b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganovimport com.android.internal.R; 54b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov 5568f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook/** 564bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * A widget that enables the user to select a number form a predefined range. 574bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * The widget presents an input filed and up and down buttons for selecting the 584bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * current value. Pressing/long pressing the up and down buttons increments and 594bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * decrements the current value respectively. Touching the input filed shows a 604bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * scroll wheel, tapping on which while shown and not moving allows direct edit 614bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * of the current value. Sliding motions up or down hide the buttons and the 624bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * input filed, show the scroll wheel, and rotate the latter. Flinging is 634bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * also supported. The widget enables mapping from positions to strings such 644bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * that instead the position index the corresponding string is displayed. 654bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * <p> 664bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * For an example of using this widget, see {@link android.widget.TimePicker}. 674bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * </p> 6868f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook */ 6968f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook@Widget 7068f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrookpublic class NumberPicker extends LinearLayout { 71fdf6db6748b32f620a7f68b13a67c38b4e59e5edTom Taylor 7268f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook /** 73e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * The default update interval during long press. 74e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov */ 75e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov private static final long DEFAULT_LONG_PRESS_UPDATE_INTERVAL = 300; 76e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov 77e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov /** 78206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * The index of the middle selector item. 7968f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook */ 80206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private static final int SELECTOR_MIDDLE_ITEM_INDEX = 2; 819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8268f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook /** 83206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * The coefficient by which to adjust (divide) the max fling velocity. 8468f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook */ 85206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private static final int SELECTOR_MAX_FLING_VELOCITY_ADJUSTMENT = 8; 869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 87206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 88206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * The the duration for adjusting the selector wheel. 89206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 90206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private static final int SELECTOR_ADJUSTMENT_DURATION_MILLIS = 800; 91fdf6db6748b32f620a7f68b13a67c38b4e59e5edTom Taylor 92206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 93b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov * The duration of scrolling to the next/previous value while changing 94b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov * the current value by one, i.e. increment or decrement. 95b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov */ 96b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov private static final int CHANGE_CURRENT_BY_ONE_SCROLL_DURATION = 300; 97b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov 98b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov /** 99206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * The the delay for showing the input controls after a single tap on the 100206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * input text. 101206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 102206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private static final int SHOW_INPUT_CONTROLS_DELAY_MILLIS = ViewConfiguration 103206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov .getDoubleTapTimeout(); 104206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 105206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 106b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov * The strength of fading in the top and bottom while drawing the selector. 107206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 108b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov private static final float TOP_AND_BOTTOM_FADING_EDGE_STRENGTH = 0.9f; 109206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 110206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 111b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov * The default unscaled height of the selection divider. 112206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 113b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov private static final int UNSCALED_DEFAULT_SELECTION_DIVIDER_HEIGHT = 2; 114206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 115206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 116b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov * In this state the selector wheel is not shown. 117206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 118b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov private static final int SELECTOR_WHEEL_STATE_NONE = 0; 119206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 120206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 121b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov * In this state the selector wheel is small. 122b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov */ 123b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov private static final int SELECTOR_WHEEL_STATE_SMALL = 1; 124b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov 125b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov /** 126b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov * In this state the selector wheel is large. 127b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov */ 128b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov private static final int SELECTOR_WHEEL_STATE_LARGE = 2; 129b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov 130b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov /** 131b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov * The alpha of the selector wheel when it is bright. 1329cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov */ 133b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov private static final int SELECTOR_WHEEL_BRIGHT_ALPHA = 255; 134b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov 135b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov /** 136b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov * The alpha of the selector wheel when it is dimmed. 137b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov */ 138b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov private static final int SELECTOR_WHEEL_DIM_ALPHA = 60; 139b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov 140b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov /** 141b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov * The alpha for the increment/decrement button when it is transparent. 142b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov */ 143b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov private static final int BUTTON_ALPHA_TRANSPARENT = 0; 144b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov 145b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov /** 146b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov * The alpha for the increment/decrement button when it is opaque. 147b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov */ 148b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov private static final int BUTTON_ALPHA_OPAQUE = 1; 149b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov 150b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov /** 151b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov * The property for setting the selector paint. 152b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov */ 153b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov private static final String PROPERTY_SELECTOR_PAINT_ALPHA = "selectorPaintAlpha"; 154b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov 155b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov /** 156b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov * The property for setting the increment/decrement button alpha. 157b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov */ 158b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov private static final String PROPERTY_BUTTON_ALPHA = "alpha"; 1599cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov 1609cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov /** 161206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * The numbers accepted by the input text's {@link Filter} 162206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 163206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private static final char[] DIGIT_CHARACTERS = new char[] { 164206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' 165206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov }; 166206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 167206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 1689f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov * Constant for unspecified size. 1699f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov */ 1709f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov private static final int SIZE_UNSPECIFIED = -1; 1719f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov 1729f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov /** 173206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Use a custom NumberPicker formatting callback to use two-digit minutes 174206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * strings like "01". Keeping a static formatter etc. is the most efficient 175206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * way to do this; it avoids creating temporary objects on every call to 176206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * format(). 177e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * 178e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @hide 179206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 180206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov public static final NumberPicker.Formatter TWO_DIGIT_FORMATTER = new NumberPicker.Formatter() { 181206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov final StringBuilder mBuilder = new StringBuilder(); 182206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 183f0ef665299d795df7905897e1c337e37891dafefJean-Baptiste Queru final java.util.Formatter mFmt = new java.util.Formatter(mBuilder, java.util.Locale.US); 184206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 185206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov final Object[] mArgs = new Object[1]; 186206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 187e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov public String format(int value) { 188206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mArgs[0] = value; 189206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mBuilder.delete(0, mBuilder.length()); 190206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mFmt.format("%02d", mArgs); 191206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return mFmt.toString(); 1929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project }; 1949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 195206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 196206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * The increment button. 197206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 198206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private final ImageButton mIncrementButton; 199206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 200206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 201206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * The decrement button. 202206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 203206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private final ImageButton mDecrementButton; 204206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 205206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 206206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * The text for showing the current value. 207206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 208206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private final EditText mInputText; 209206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 210206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 211ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov * The min height of this widget. 212ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov */ 213ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov private final int mMinHeight; 214ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov 215ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov /** 216e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov * The max height of this widget. 217e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov */ 218e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov private final int mMaxHeight; 219e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov 220e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov /** 221e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov * The max width of this widget. 222e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov */ 223ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov private final int mMinWidth; 224ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov 225ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov /** 226ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov * The max width of this widget. 227ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov */ 228ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov private int mMaxWidth; 229ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov 230ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov /** 231ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov * Flag whether to compute the max width. 232ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov */ 233ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov private final boolean mComputeMaxWidth; 234e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov 235e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov /** 236206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * The height of the text. 237206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 238206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private final int mTextSize; 2399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 240206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 241b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov * The height of the gap between text elements if the selector wheel. 242b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov */ 243b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov private int mSelectorTextGapHeight; 244b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov 245b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov /** 246206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * The values to be displayed instead the indices. 247206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 2489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private String[] mDisplayedValues; 24968f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook 25068f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook /** 25168f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook * Lower value of the range of numbers allowed for the NumberPicker 25268f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook */ 253e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov private int mMinValue; 25468f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook 25568f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook /** 25668f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook * Upper value of the range of numbers allowed for the NumberPicker 25768f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook */ 258e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov private int mMaxValue; 25968f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook 26068f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook /** 26168f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook * Current value of this NumberPicker 26268f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook */ 263e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov private int mValue; 26468f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook 26568f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook /** 266206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Listener to be notified upon current value change. 26768f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook */ 268cedc446684e94c9971c38c3206f1f224314bda2aSvetoslav Ganov private OnValueChangeListener mOnValueChangeListener; 26950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 27050f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov /** 27150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * Listener to be notified upon scroll state change. 27250f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov */ 27350f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov private OnScrollListener mOnScrollListener; 274206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 275206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 276206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Formatter for for displaying the current value. 277206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 2789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private Formatter mFormatter; 279fdf6db6748b32f620a7f68b13a67c38b4e59e5edTom Taylor 280206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 281206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * The speed for updating the value form long press. 282206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 283e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov private long mLongPressUpdateInterval = DEFAULT_LONG_PRESS_UPDATE_INTERVAL; 284fdf6db6748b32f620a7f68b13a67c38b4e59e5edTom Taylor 28568f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook /** 286206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Cache for the string representation of selector indices. 287206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 288206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private final SparseArray<String> mSelectorIndexToStringCache = new SparseArray<String>(); 289206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 290206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 291206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * The selector indices whose value are show by the selector. 292206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 293206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private final int[] mSelectorIndices = new int[] { 294206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov Integer.MIN_VALUE, Integer.MIN_VALUE, Integer.MIN_VALUE, Integer.MIN_VALUE, 295206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov Integer.MIN_VALUE 296206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov }; 297206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 298206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 299206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * The {@link Paint} for drawing the selector. 300206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 301b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov private final Paint mSelectorWheelPaint; 302206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 303206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 304206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * The height of a selector element (text + gap). 305206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 306206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private int mSelectorElementHeight; 307206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 308206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 309206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * The initial offset of the scroll selector. 310206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 311206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private int mInitialScrollOffset = Integer.MIN_VALUE; 312206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 313206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 314206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * The current offset of the scroll selector. 315206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 316206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private int mCurrentScrollOffset; 317206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 318206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 319206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * The {@link Scroller} responsible for flinging the selector. 320206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 321206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private final Scroller mFlingScroller; 322206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 323206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 324206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * The {@link Scroller} responsible for adjusting the selector. 325206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 326206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private final Scroller mAdjustScroller; 327206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 328206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 329206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * The previous Y coordinate while scrolling the selector. 330206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 331206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private int mPreviousScrollerY; 332206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 333206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 334206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Handle to the reusable command for setting the input text selection. 335206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 336206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private SetSelectionCommand mSetSelectionCommand; 337206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 338206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 339206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Handle to the reusable command for adjusting the scroller. 340206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 341206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private AdjustScrollerCommand mAdjustScrollerCommand; 342206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 343206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 344b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov * Handle to the reusable command for changing the current value from long 345b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov * press by one. 346206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 347b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov private ChangeCurrentByOneFromLongPressCommand mChangeCurrentByOneFromLongPressCommand; 348206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 349206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 350206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * {@link Animator} for showing the up/down arrows. 351206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 352206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private final AnimatorSet mShowInputControlsAnimator; 353206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 354206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 355b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov * {@link Animator} for dimming the selector wheel. 356b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov */ 357b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov private final Animator mDimSelectorWheelAnimator; 358b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov 359b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov /** 360206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * The Y position of the last down event. 361206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 362206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private float mLastDownEventY; 363206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 364206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 365206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * The Y position of the last motion event. 366206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 367206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private float mLastMotionEventY; 368206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 369206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 370206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Flag if to begin edit on next up event. 371206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 372206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private boolean mBeginEditOnUpEvent; 373206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 374206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 375206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Flag if to adjust the selector wheel on next up event. 376206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 377206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private boolean mAdjustScrollerOnUpEvent; 378206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 379206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 380b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov * The state of the selector wheel. 381206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 382b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov private int mSelectorWheelState; 383206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 384206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 385206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Determines speed during touch scrolling. 386206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 387206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private VelocityTracker mVelocityTracker; 388206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 389206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 390206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * @see ViewConfiguration#getScaledTouchSlop() 391206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 392206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private int mTouchSlop; 393206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 394206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 395206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * @see ViewConfiguration#getScaledMinimumFlingVelocity() 396206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 397206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private int mMinimumFlingVelocity; 398206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 399206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 400206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * @see ViewConfiguration#getScaledMaximumFlingVelocity() 401206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 402206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private int mMaximumFlingVelocity; 403206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 404206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 405206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Flag whether the selector should wrap around. 406206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 407e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov private boolean mWrapSelectorWheel; 408206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 409206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 410206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * The back ground color used to optimize scroller fading. 41168f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook */ 412206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private final int mSolidColor; 413206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 414206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 4154243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov * Flag indicating if this widget supports flinging. 4164243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov */ 4174243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov private final boolean mFlingable; 4184243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov 4194243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov /** 4209cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov * Divider for showing item to be selected while scrolling 4219cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov */ 4229cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov private final Drawable mSelectionDivider; 4239cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov 4249cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov /** 4259cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov * The height of the selection divider. 4269cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov */ 4279cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov private final int mSelectionDividerHeight; 4289cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov 4299cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov /** 430206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Reusable {@link Rect} instance. 431206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 432206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private final Rect mTempRect = new Rect(); 433206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 434206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 43550f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * The current scroll state of the number picker. 43650f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov */ 43750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov private int mScrollState = OnScrollListener.SCROLL_STATE_IDLE; 43850f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 43950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov /** 4409cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov * The duration of the animation for showing the input controls. 4419cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov */ 4429cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov private final long mShowInputControlsAnimimationDuration; 4439cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov 4449cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov /** 445b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov * Flag whether the scoll wheel and the fading edges have been initialized. 446b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov */ 447b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov private boolean mScrollWheelAndFadingEdgesInitialized; 448b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov 449b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov /** 450e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * Interface to listen for changes of the current value. 451206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 452cedc446684e94c9971c38c3206f1f224314bda2aSvetoslav Ganov public interface OnValueChangeListener { 453e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov 454206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 4554bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * Called upon a change of the current value. 4564bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * 457206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * @param picker The NumberPicker associated with this listener. 458206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * @param oldVal The previous value. 459206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * @param newVal The new value. 460206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 461e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov void onValueChange(NumberPicker picker, int oldVal, int newVal); 462206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 463206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 464206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 465e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * Interface to listen for the picker scroll state. 46650f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov */ 46750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov public interface OnScrollListener { 46850f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 46950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov /** 47050f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * The view is not scrolling. 47150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov */ 47250f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov public static int SCROLL_STATE_IDLE = 0; 47350f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 47450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov /** 47550f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * The user is scrolling using touch, and their finger is still on the screen. 47650f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov */ 47750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov public static int SCROLL_STATE_TOUCH_SCROLL = 1; 47850f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 47950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov /** 48050f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * The user had previously been scrolling using touch and performed a fling. 48150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov */ 48250f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov public static int SCROLL_STATE_FLING = 2; 48350f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 48450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov /** 485e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * Callback invoked while the number picker scroll state has changed. 48650f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * 487e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @param view The view whose scroll state is being reported. 488e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @param scrollState The current scroll state. One of 489e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * {@link #SCROLL_STATE_IDLE}, 490e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * {@link #SCROLL_STATE_TOUCH_SCROLL} or 491e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * {@link #SCROLL_STATE_IDLE}. 49250f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov */ 4934bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov public void onScrollStateChange(NumberPicker view, int scrollState); 49450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov } 49550f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 49650f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov /** 497e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * Interface used to format current value into a string for presentation. 498206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 499206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov public interface Formatter { 5004bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov 5014bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov /** 502e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * Formats a string representation of the current value. 5034bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * 5044bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * @param value The currently selected value. 5054bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * @return A formatted string representation. 5064bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov */ 507e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov public String format(int value); 5089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 509fdf6db6748b32f620a7f68b13a67c38b4e59e5edTom Taylor 51068f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook /** 5114bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * Create a new number picker. 5124bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * 5134bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * @param context The application environment. 5144bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov */ 5154bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov public NumberPicker(Context context) { 5164bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov this(context, null); 5174bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov } 5184bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov 5194bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov /** 5204bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * Create a new number picker. 521206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * 522206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * @param context The application environment. 523206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * @param attrs A collection of attributes. 52468f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook */ 5259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public NumberPicker(Context context, AttributeSet attrs) { 526206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov this(context, attrs, R.attr.numberPickerStyle); 527206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 528206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 529206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 530206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Create a new number picker 531206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * 532206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * @param context the application environment. 533206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * @param attrs a collection of attributes. 534206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * @param defStyle The default style to apply to this view. 535206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 536206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov public NumberPicker(Context context, AttributeSet attrs, int defStyle) { 537206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov super(context, attrs, defStyle); 538206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 539206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // process style attributes 540206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov TypedArray attributesArray = context.obtainStyledAttributes(attrs, 541206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov R.styleable.NumberPicker, defStyle, 0); 542206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mSolidColor = attributesArray.getColor(R.styleable.NumberPicker_solidColor, 0); 5434243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov mFlingable = attributesArray.getBoolean(R.styleable.NumberPicker_flingable, true); 5449cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov mSelectionDivider = attributesArray.getDrawable(R.styleable.NumberPicker_selectionDivider); 5459cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov int defSelectionDividerHeight = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 5469cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov UNSCALED_DEFAULT_SELECTION_DIVIDER_HEIGHT, 5479cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov getResources().getDisplayMetrics()); 5489cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov mSelectionDividerHeight = attributesArray.getDimensionPixelSize( 5499cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov R.styleable.NumberPicker_selectionDividerHeight, defSelectionDividerHeight); 5509f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov mMinHeight = attributesArray.getDimensionPixelSize(R.styleable.NumberPicker_minHeight, 5519f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov SIZE_UNSPECIFIED); 552ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov mMaxHeight = attributesArray.getDimensionPixelSize(R.styleable.NumberPicker_maxHeight, 5539f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov SIZE_UNSPECIFIED); 5549f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov if (mMinHeight != SIZE_UNSPECIFIED && mMaxHeight != SIZE_UNSPECIFIED 5559f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov && mMinHeight > mMaxHeight) { 556ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov throw new IllegalArgumentException("minHeight > maxHeight"); 557ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov } 5589f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov mMinWidth = attributesArray.getDimensionPixelSize(R.styleable.NumberPicker_minWidth, 5599f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov SIZE_UNSPECIFIED); 560ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov mMaxWidth = attributesArray.getDimensionPixelSize(R.styleable.NumberPicker_maxWidth, 5619f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov SIZE_UNSPECIFIED); 5629f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov if (mMinWidth != SIZE_UNSPECIFIED && mMaxWidth != SIZE_UNSPECIFIED 5639f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov && mMinWidth > mMaxWidth) { 564ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov throw new IllegalArgumentException("minWidth > maxWidth"); 565ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov } 566ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov mComputeMaxWidth = (mMaxWidth == Integer.MAX_VALUE); 567206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov attributesArray.recycle(); 568206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 5699cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov mShowInputControlsAnimimationDuration = getResources().getInteger( 5709cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov R.integer.config_longAnimTime); 5719cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov 572206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // By default Linearlayout that we extend is not drawn. This is 573206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // its draw() method is not called but dispatchDraw() is called 574206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // directly (see ViewGroup.drawChild()). However, this class uses 575206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // the fading edge effect implemented by View and we need our 576206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // draw() method to be called. Therefore, we declare we will draw. 577206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov setWillNotDraw(false); 578b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov setSelectorWheelState(SELECTOR_WHEEL_STATE_NONE); 579206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 580206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov LayoutInflater inflater = (LayoutInflater) getContext().getSystemService( 581206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov Context.LAYOUT_INFLATER_SERVICE); 5829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project inflater.inflate(R.layout.number_picker, this, true); 58368f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook 584206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov OnClickListener onClickListener = new OnClickListener() { 58568f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook public void onClick(View v) { 5866304b0d58e74509a9f21b67b5227b2fee2f1b60fSvetoslav Ganov InputMethodManager inputMethodManager = InputMethodManager.peekInstance(); 5876304b0d58e74509a9f21b67b5227b2fee2f1b60fSvetoslav Ganov if (inputMethodManager != null && inputMethodManager.isActive(mInputText)) { 5886304b0d58e74509a9f21b67b5227b2fee2f1b60fSvetoslav Ganov inputMethodManager.hideSoftInputFromWindow(getWindowToken(), 0); 5896304b0d58e74509a9f21b67b5227b2fee2f1b60fSvetoslav Ganov } 590206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mInputText.clearFocus(); 591206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (v.getId() == R.id.increment) { 592b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov changeCurrentByOne(true); 593206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } else { 594b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov changeCurrentByOne(false); 59568f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook } 59668f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook } 59768f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook }; 59868f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook 599206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov OnLongClickListener onLongClickListener = new OnLongClickListener() { 600206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov public boolean onLongClick(View v) { 601206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mInputText.clearFocus(); 602206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (v.getId() == R.id.increment) { 603b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov postChangeCurrentByOneFromLongPress(true); 604206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } else { 605b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov postChangeCurrentByOneFromLongPress(false); 606206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 607206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return true; 608206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 609206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov }; 61068f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook 611206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // increment button 612206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mIncrementButton = (ImageButton) findViewById(R.id.increment); 613206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mIncrementButton.setOnClickListener(onClickListener); 614206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mIncrementButton.setOnLongClickListener(onLongClickListener); 615206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 616206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // decrement button 617206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mDecrementButton = (ImageButton) findViewById(R.id.decrement); 618206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mDecrementButton.setOnClickListener(onClickListener); 619206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mDecrementButton.setOnLongClickListener(onLongClickListener); 620206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 621206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // input text 622012dd5a461f18a2e5dad38c60282fac1c21ff7feSvetoslav Ganov mInputText = (EditText) findViewById(R.id.numberpicker_input); 623206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mInputText.setOnFocusChangeListener(new OnFocusChangeListener() { 624206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov public void onFocusChange(View v, boolean hasFocus) { 625a53efe9923bedab4fe5d578f32eaff308e5b9e76Svetoslav Ganov if (hasFocus) { 626a53efe9923bedab4fe5d578f32eaff308e5b9e76Svetoslav Ganov mInputText.selectAll(); 6276304b0d58e74509a9f21b67b5227b2fee2f1b60fSvetoslav Ganov InputMethodManager inputMethodManager = InputMethodManager.peekInstance(); 628b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov if (inputMethodManager != null) { 629b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov inputMethodManager.showSoftInput(mInputText, 0); 630b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov } 631a53efe9923bedab4fe5d578f32eaff308e5b9e76Svetoslav Ganov } else { 632a53efe9923bedab4fe5d578f32eaff308e5b9e76Svetoslav Ganov mInputText.setSelection(0, 0); 633206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov validateInputTextView(v); 63468f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook } 63568f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook } 636206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov }); 637206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mInputText.setFilters(new InputFilter[] { 638206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov new InputTextFilter() 639206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov }); 64068f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook 641206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mInputText.setRawInputType(InputType.TYPE_CLASS_NUMBER); 642206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 643206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // initialize constants 644206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mTouchSlop = ViewConfiguration.getTapTimeout(); 645206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov ViewConfiguration configuration = ViewConfiguration.get(context); 646206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mTouchSlop = configuration.getScaledTouchSlop(); 647206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mMinimumFlingVelocity = configuration.getScaledMinimumFlingVelocity(); 648206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mMaximumFlingVelocity = configuration.getScaledMaximumFlingVelocity() 649206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov / SELECTOR_MAX_FLING_VELOCITY_ADJUSTMENT; 650206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mTextSize = (int) mInputText.getTextSize(); 651206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 652206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // create the selector wheel paint 653206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov Paint paint = new Paint(); 654206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov paint.setAntiAlias(true); 655206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov paint.setTextAlign(Align.CENTER); 656206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov paint.setTextSize(mTextSize); 657206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov paint.setTypeface(mInputText.getTypeface()); 658206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov ColorStateList colors = mInputText.getTextColors(); 659206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov int color = colors.getColorForState(ENABLED_STATE_SET, Color.WHITE); 660206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov paint.setColor(color); 661b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov mSelectorWheelPaint = paint; 662206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 663206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // create the animator for showing the input controls 664b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov mDimSelectorWheelAnimator = ObjectAnimator.ofInt(this, PROPERTY_SELECTOR_PAINT_ALPHA, 665b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov SELECTOR_WHEEL_BRIGHT_ALPHA, SELECTOR_WHEEL_DIM_ALPHA); 666206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov final ObjectAnimator showIncrementButton = ObjectAnimator.ofFloat(mIncrementButton, 667b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov PROPERTY_BUTTON_ALPHA, BUTTON_ALPHA_TRANSPARENT, BUTTON_ALPHA_OPAQUE); 668206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov final ObjectAnimator showDecrementButton = ObjectAnimator.ofFloat(mDecrementButton, 669b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov PROPERTY_BUTTON_ALPHA, BUTTON_ALPHA_TRANSPARENT, BUTTON_ALPHA_OPAQUE); 670206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mShowInputControlsAnimator = new AnimatorSet(); 671b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov mShowInputControlsAnimator.playTogether(mDimSelectorWheelAnimator, showIncrementButton, 6725203194fdff0c0aaefc405d65871ef0e06e7c682Svetoslav Ganov showDecrementButton); 673206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mShowInputControlsAnimator.addListener(new AnimatorListenerAdapter() { 674206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private boolean mCanceled = false; 675206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 676206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov @Override 677206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov public void onAnimationEnd(Animator animation) { 678206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (!mCanceled) { 679206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // if canceled => we still want the wheel drawn 680b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov setSelectorWheelState(SELECTOR_WHEEL_STATE_SMALL); 68168f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook } 682206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mCanceled = false; 68368f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook } 68468f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook 685206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov @Override 686206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov public void onAnimationCancel(Animator animation) { 687206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (mShowInputControlsAnimator.isRunning()) { 688206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mCanceled = true; 689206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 690206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 691206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov }); 69268f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook 693206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // create the fling and adjust scrollers 694bf80562d22b2bbe7944d80d0524c69d0238010cbSvetoslav Ganov mFlingScroller = new Scroller(getContext(), null, true); 6959cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov mAdjustScroller = new Scroller(getContext(), new DecelerateInterpolator(2.5f)); 696fdf6db6748b32f620a7f68b13a67c38b4e59e5edTom Taylor 697206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov updateInputTextView(); 698206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov updateIncrementAndDecrementButtonsVisibilityState(); 6999cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov 700b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov if (mFlingable) { 701b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov if (isInEditMode()) { 702b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov setSelectorWheelState(SELECTOR_WHEEL_STATE_SMALL); 703b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov } else { 704b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov // Start with shown selector wheel and hidden controls. When made 705b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov // visible hide the selector and fade-in the controls to suggest 706b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov // fling interaction. 707b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov setSelectorWheelState(SELECTOR_WHEEL_STATE_LARGE); 708b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov hideInputControls(); 709b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov } 7109cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov } 711206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 712206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 713206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov @Override 7149cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov protected void onLayout(boolean changed, int left, int top, int right, int bottom) { 715ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov final int msrdWdth = getMeasuredWidth(); 716ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov final int msrdHght = getMeasuredHeight(); 717ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov 718ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov // Increment button at the top. 719ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov final int inctBtnMsrdWdth = mIncrementButton.getMeasuredWidth(); 720ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov final int incrBtnLeft = (msrdWdth - inctBtnMsrdWdth) / 2; 721ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov final int incrBtnTop = 0; 722ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov final int incrBtnRight = incrBtnLeft + inctBtnMsrdWdth; 723ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov final int incrBtnBottom = incrBtnTop + mIncrementButton.getMeasuredHeight(); 724ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov mIncrementButton.layout(incrBtnLeft, incrBtnTop, incrBtnRight, incrBtnBottom); 725ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov 726ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov // Input text centered horizontally. 727ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov final int inptTxtMsrdWdth = mInputText.getMeasuredWidth(); 728ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov final int inptTxtMsrdHght = mInputText.getMeasuredHeight(); 729ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov final int inptTxtLeft = (msrdWdth - inptTxtMsrdWdth) / 2; 730ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov final int inptTxtTop = (msrdHght - inptTxtMsrdHght) / 2; 731ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov final int inptTxtRight = inptTxtLeft + inptTxtMsrdWdth; 732ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov final int inptTxtBottom = inptTxtTop + inptTxtMsrdHght; 733ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov mInputText.layout(inptTxtLeft, inptTxtTop, inptTxtRight, inptTxtBottom); 734ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov 735ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov // Decrement button at the top. 736ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov final int decrBtnMsrdWdth = mIncrementButton.getMeasuredWidth(); 737ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov final int decrBtnLeft = (msrdWdth - decrBtnMsrdWdth) / 2; 738ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov final int decrBtnTop = msrdHght - mDecrementButton.getMeasuredHeight(); 739ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov final int decrBtnRight = decrBtnLeft + decrBtnMsrdWdth; 740ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov final int decrBtnBottom = msrdHght; 741ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov mDecrementButton.layout(decrBtnLeft, decrBtnTop, decrBtnRight, decrBtnBottom); 742e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov 743b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov if (!mScrollWheelAndFadingEdgesInitialized) { 744b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov mScrollWheelAndFadingEdgesInitialized = true; 745b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov // need to do all this when we know our size 746b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov initializeSelectorWheel(); 747b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov initializeFadingEdges(); 748b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov } 749206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 750206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 751206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov @Override 752e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 753698e1d5d867a7ac653fa1d6f29cef4cfb73fad38Svetoslav Ganov // Try greedily to fit the max width and height. 754698e1d5d867a7ac653fa1d6f29cef4cfb73fad38Svetoslav Ganov final int newWidthMeasureSpec = makeMeasureSpec(widthMeasureSpec, mMaxWidth); 755698e1d5d867a7ac653fa1d6f29cef4cfb73fad38Svetoslav Ganov final int newHeightMeasureSpec = makeMeasureSpec(heightMeasureSpec, mMaxHeight); 756ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov super.onMeasure(newWidthMeasureSpec, newHeightMeasureSpec); 757698e1d5d867a7ac653fa1d6f29cef4cfb73fad38Svetoslav Ganov // Flag if we are measured with width or height less than the respective min. 7589f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov final int widthSize = resolveSizeAndStateRespectingMinSize(mMinWidth, getMeasuredWidth(), 7599f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov widthMeasureSpec); 7609f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov final int heightSize = resolveSizeAndStateRespectingMinSize(mMinHeight, getMeasuredHeight(), 7619f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov heightMeasureSpec); 762698e1d5d867a7ac653fa1d6f29cef4cfb73fad38Svetoslav Ganov setMeasuredDimension(widthSize, heightSize); 763e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov } 764e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov 765e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov @Override 766206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov public boolean onInterceptTouchEvent(MotionEvent event) { 7674243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov if (!isEnabled() || !mFlingable) { 76851c52edad7d40697d7fb2a091f850506fa897643Svetoslav Ganov return false; 76951c52edad7d40697d7fb2a091f850506fa897643Svetoslav Ganov } 770206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov switch (event.getActionMasked()) { 771206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov case MotionEvent.ACTION_DOWN: 772206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mLastMotionEventY = mLastDownEventY = event.getY(); 773206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov removeAllCallbacks(); 774092bda57c4b8caad378400b2bc97b9ac66fd2179Svetoslav Ganov mShowInputControlsAnimator.cancel(); 775b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov mDimSelectorWheelAnimator.cancel(); 776206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mBeginEditOnUpEvent = false; 777206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mAdjustScrollerOnUpEvent = true; 778b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov if (mSelectorWheelState == SELECTOR_WHEEL_STATE_LARGE) { 779234484a9fb53786aa8b7ed2a3df7e24d41817689Svetoslav Ganov mSelectorWheelPaint.setAlpha(SELECTOR_WHEEL_BRIGHT_ALPHA); 78050f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov boolean scrollersFinished = mFlingScroller.isFinished() 781206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov && mAdjustScroller.isFinished(); 78250f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov if (!scrollersFinished) { 78350f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov mFlingScroller.forceFinished(true); 78450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov mAdjustScroller.forceFinished(true); 7859cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov onScrollStateChange(OnScrollListener.SCROLL_STATE_IDLE); 78650f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov } 78750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov mBeginEditOnUpEvent = scrollersFinished; 788206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mAdjustScrollerOnUpEvent = true; 789092bda57c4b8caad378400b2bc97b9ac66fd2179Svetoslav Ganov hideInputControls(); 790206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return true; 791206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 792e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov if (isEventInVisibleViewHitRect(event, mIncrementButton) 793e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov || isEventInVisibleViewHitRect(event, mDecrementButton)) { 794e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov return false; 795206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 796e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov mAdjustScrollerOnUpEvent = false; 797e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov setSelectorWheelState(SELECTOR_WHEEL_STATE_LARGE); 798e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov hideInputControls(); 799e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov return true; 800206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov case MotionEvent.ACTION_MOVE: 801206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov float currentMoveY = event.getY(); 802206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov int deltaDownY = (int) Math.abs(currentMoveY - mLastDownEventY); 803206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (deltaDownY > mTouchSlop) { 804206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mBeginEditOnUpEvent = false; 8059cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov onScrollStateChange(OnScrollListener.SCROLL_STATE_TOUCH_SCROLL); 806b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov setSelectorWheelState(SELECTOR_WHEEL_STATE_LARGE); 807092bda57c4b8caad378400b2bc97b9ac66fd2179Svetoslav Ganov hideInputControls(); 808206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return true; 809206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 810206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov break; 811206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 812206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return false; 813206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 814206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 815206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov @Override 816206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov public boolean onTouchEvent(MotionEvent ev) { 81751c52edad7d40697d7fb2a091f850506fa897643Svetoslav Ganov if (!isEnabled()) { 81851c52edad7d40697d7fb2a091f850506fa897643Svetoslav Ganov return false; 81951c52edad7d40697d7fb2a091f850506fa897643Svetoslav Ganov } 820206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (mVelocityTracker == null) { 821206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mVelocityTracker = VelocityTracker.obtain(); 822206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 823206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mVelocityTracker.addMovement(ev); 824206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov int action = ev.getActionMasked(); 825206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov switch (action) { 826206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov case MotionEvent.ACTION_MOVE: 827206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov float currentMoveY = ev.getY(); 82850f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov if (mBeginEditOnUpEvent 82950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov || mScrollState != OnScrollListener.SCROLL_STATE_TOUCH_SCROLL) { 830206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov int deltaDownY = (int) Math.abs(currentMoveY - mLastDownEventY); 831206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (deltaDownY > mTouchSlop) { 832206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mBeginEditOnUpEvent = false; 8339cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov onScrollStateChange(OnScrollListener.SCROLL_STATE_TOUCH_SCROLL); 834206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 835206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 836206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov int deltaMoveY = (int) (currentMoveY - mLastMotionEventY); 837206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov scrollBy(0, deltaMoveY); 838206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov invalidate(); 839206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mLastMotionEventY = currentMoveY; 840206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov break; 841206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov case MotionEvent.ACTION_UP: 842206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (mBeginEditOnUpEvent) { 843b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov setSelectorWheelState(SELECTOR_WHEEL_STATE_SMALL); 8449cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov showInputControls(mShowInputControlsAnimimationDuration); 845206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mInputText.requestFocus(); 846206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return true; 847206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 848206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov VelocityTracker velocityTracker = mVelocityTracker; 849206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov velocityTracker.computeCurrentVelocity(1000, mMaximumFlingVelocity); 850206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov int initialVelocity = (int) velocityTracker.getYVelocity(); 851206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (Math.abs(initialVelocity) > mMinimumFlingVelocity) { 852206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov fling(initialVelocity); 8539cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov onScrollStateChange(OnScrollListener.SCROLL_STATE_FLING); 854206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } else { 855206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (mAdjustScrollerOnUpEvent) { 856206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (mFlingScroller.isFinished() && mAdjustScroller.isFinished()) { 857206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov postAdjustScrollerCommand(0); 858206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 859206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } else { 860206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov postAdjustScrollerCommand(SHOW_INPUT_CONTROLS_DELAY_MILLIS); 861206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 862206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 863206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mVelocityTracker.recycle(); 864206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mVelocityTracker = null; 865206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov break; 866206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 867206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return true; 868206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 869206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 870206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov @Override 871206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov public boolean dispatchTouchEvent(MotionEvent event) { 872b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov final int action = event.getActionMasked(); 873b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov switch (action) { 874b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov case MotionEvent.ACTION_MOVE: 875b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov if (mSelectorWheelState == SELECTOR_WHEEL_STATE_LARGE) { 876b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov removeAllCallbacks(); 877b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov forceCompleteChangeCurrentByOneViaScroll(); 878b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov } 879b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov break; 880b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov case MotionEvent.ACTION_CANCEL: 881b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov case MotionEvent.ACTION_UP: 882b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov removeAllCallbacks(); 883b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov break; 884206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 885206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return super.dispatchTouchEvent(event); 886206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 887206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 888206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov @Override 889206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov public boolean dispatchKeyEvent(KeyEvent event) { 890206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov int keyCode = event.getKeyCode(); 891206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER || keyCode == KeyEvent.KEYCODE_ENTER) { 892206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov removeAllCallbacks(); 893206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 894206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return super.dispatchKeyEvent(event); 895206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 896206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 897206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov @Override 898206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov public boolean dispatchTrackballEvent(MotionEvent event) { 899206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov int action = event.getActionMasked(); 900206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) { 901206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov removeAllCallbacks(); 902206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 903206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return super.dispatchTrackballEvent(event); 904206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 9059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 906206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov @Override 907206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov public void computeScroll() { 908b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov if (mSelectorWheelState == SELECTOR_WHEEL_STATE_NONE) { 909206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return; 910206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 911206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov Scroller scroller = mFlingScroller; 912206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (scroller.isFinished()) { 913206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov scroller = mAdjustScroller; 914206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (scroller.isFinished()) { 915206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return; 916206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 917206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 918206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov scroller.computeScrollOffset(); 919206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov int currentScrollerY = scroller.getCurrY(); 920206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (mPreviousScrollerY == 0) { 921206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mPreviousScrollerY = scroller.getStartY(); 922206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 923206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov scrollBy(0, currentScrollerY - mPreviousScrollerY); 924206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mPreviousScrollerY = currentScrollerY; 925206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (scroller.isFinished()) { 926206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov onScrollerFinished(scroller); 927206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } else { 928206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov invalidate(); 9299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 931fdf6db6748b32f620a7f68b13a67c38b4e59e5edTom Taylor 9329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 9339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void setEnabled(boolean enabled) { 9349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project super.setEnabled(enabled); 9359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mIncrementButton.setEnabled(enabled); 9369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mDecrementButton.setEnabled(enabled); 937206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mInputText.setEnabled(enabled); 938206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 939206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 940206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov @Override 941206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov public void scrollBy(int x, int y) { 942b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov if (mSelectorWheelState == SELECTOR_WHEEL_STATE_NONE) { 943b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov return; 944b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov } 945b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov int[] selectorIndices = mSelectorIndices; 94634c0688ceafbeef2648bd2287b3b3c3801679448Svetoslav Ganov if (!mWrapSelectorWheel && y > 0 94734c0688ceafbeef2648bd2287b3b3c3801679448Svetoslav Ganov && selectorIndices[SELECTOR_MIDDLE_ITEM_INDEX] <= mMinValue) { 948206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mCurrentScrollOffset = mInitialScrollOffset; 949206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return; 950206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 95134c0688ceafbeef2648bd2287b3b3c3801679448Svetoslav Ganov if (!mWrapSelectorWheel && y < 0 95234c0688ceafbeef2648bd2287b3b3c3801679448Svetoslav Ganov && selectorIndices[SELECTOR_MIDDLE_ITEM_INDEX] >= mMaxValue) { 953206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mCurrentScrollOffset = mInitialScrollOffset; 954206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return; 955206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 956206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mCurrentScrollOffset += y; 957b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov while (mCurrentScrollOffset - mInitialScrollOffset > mSelectorTextGapHeight) { 958206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mCurrentScrollOffset -= mSelectorElementHeight; 959206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov decrementSelectorIndices(selectorIndices); 960206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov changeCurrent(selectorIndices[SELECTOR_MIDDLE_ITEM_INDEX]); 961b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov if (!mWrapSelectorWheel && selectorIndices[SELECTOR_MIDDLE_ITEM_INDEX] <= mMinValue) { 962206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mCurrentScrollOffset = mInitialScrollOffset; 963206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 964206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 965b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov while (mCurrentScrollOffset - mInitialScrollOffset < -mSelectorTextGapHeight) { 966206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mCurrentScrollOffset += mSelectorElementHeight; 967b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov incrementSelectorIndices(selectorIndices); 968206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov changeCurrent(selectorIndices[SELECTOR_MIDDLE_ITEM_INDEX]); 969b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov if (!mWrapSelectorWheel && selectorIndices[SELECTOR_MIDDLE_ITEM_INDEX] >= mMaxValue) { 970206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mCurrentScrollOffset = mInitialScrollOffset; 971206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 972206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 9739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 974fdf6db6748b32f620a7f68b13a67c38b4e59e5edTom Taylor 9754bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov @Override 9764bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov public int getSolidColor() { 9774bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov return mSolidColor; 9784bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov } 9794bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov 98068f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook /** 9814bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * Sets the listener to be notified on change of the current value. 982206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * 983e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @param onValueChangedListener The listener. 98468f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook */ 985cedc446684e94c9971c38c3206f1f224314bda2aSvetoslav Ganov public void setOnValueChangedListener(OnValueChangeListener onValueChangedListener) { 986cedc446684e94c9971c38c3206f1f224314bda2aSvetoslav Ganov mOnValueChangeListener = onValueChangedListener; 98750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov } 98850f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 98950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov /** 9904bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * Set listener to be notified for scroll state changes. 99150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * 992e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @param onScrollListener The listener. 99350f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov */ 99450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov public void setOnScrollListener(OnScrollListener onScrollListener) { 99550f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov mOnScrollListener = onScrollListener; 9969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 997fdf6db6748b32f620a7f68b13a67c38b4e59e5edTom Taylor 99868f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook /** 9994bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * Set the formatter to be used for formatting the current value. 10004bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * <p> 1001e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * Note: If you have provided alternative values for the values this 1002e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * formatter is never invoked. 10034bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * </p> 1004206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * 1005e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @param formatter The formatter object. If formatter is <code>null</code>, 1006e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * {@link String#valueOf(int)} will be used. 10074bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * 1008e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @see #setDisplayedValues(String[]) 100968f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook */ 10109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void setFormatter(Formatter formatter) { 1011e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov if (formatter == mFormatter) { 1012e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov return; 1013e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov } 10149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mFormatter = formatter; 1015b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov initializeSelectorWheelIndices(); 10169cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov updateInputTextView(); 1017206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1018206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 1019206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 1020e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * Set the current value for the number picker. 10214bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * <p> 1022e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * If the argument is less than the {@link NumberPicker#getMinValue()} and 1023e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * {@link NumberPicker#getWrapSelectorWheel()} is <code>false</code> the 1024e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * current value is set to the {@link NumberPicker#getMinValue()} value. 1025e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * </p> 1026e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * <p> 1027e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * If the argument is less than the {@link NumberPicker#getMinValue()} and 1028e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * {@link NumberPicker#getWrapSelectorWheel()} is <code>true</code> the 1029e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * current value is set to the {@link NumberPicker#getMaxValue()} value. 1030e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * </p> 1031e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * <p> 1032e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * If the argument is less than the {@link NumberPicker#getMaxValue()} and 1033e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * {@link NumberPicker#getWrapSelectorWheel()} is <code>false</code> the 1034e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * current value is set to the {@link NumberPicker#getMaxValue()} value. 1035e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * </p> 1036e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * <p> 1037e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * If the argument is less than the {@link NumberPicker#getMaxValue()} and 1038e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * {@link NumberPicker#getWrapSelectorWheel()} is <code>true</code> the 1039e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * current value is set to the {@link NumberPicker#getMinValue()} value. 10404bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * </p> 1041206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * 1042e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @param value The current value. 10434bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * @see #setWrapSelectorWheel(boolean) 1044e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @see #setMinValue(int) 1045e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @see #setMaxValue(int) 1046206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 1047e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov public void setValue(int value) { 1048e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov if (mValue == value) { 1049a911d4a2b1be7e9ea909a579167826e4a5bac1a3Svetoslav Ganov return; 1050a911d4a2b1be7e9ea909a579167826e4a5bac1a3Svetoslav Ganov } 1051e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov if (value < mMinValue) { 1052e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov value = mWrapSelectorWheel ? mMaxValue : mMinValue; 1053206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1054e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov if (value > mMaxValue) { 1055e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov value = mWrapSelectorWheel ? mMinValue : mMaxValue; 10568bcbebd4178b2e9aca9ee3bd9e1e12c42e74c8dbAdam Powell } 1057e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov mValue = value; 1058b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov initializeSelectorWheelIndices(); 1059e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov updateInputTextView(); 1060e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov updateIncrementAndDecrementButtonsVisibilityState(); 1061b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov invalidate(); 10629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1063fdf6db6748b32f620a7f68b13a67c38b4e59e5edTom Taylor 106468f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook /** 1065ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov * Computes the max width if no such specified as an attribute. 1066ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov */ 1067ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov private void tryComputeMaxWidth() { 1068ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov if (!mComputeMaxWidth) { 1069ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov return; 1070ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov } 1071ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov int maxTextWidth = 0; 1072ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov if (mDisplayedValues == null) { 1073ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov float maxDigitWidth = 0; 1074ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov for (int i = 0; i <= 9; i++) { 1075ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov final float digitWidth = mSelectorWheelPaint.measureText(String.valueOf(i)); 1076ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov if (digitWidth > maxDigitWidth) { 1077ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov maxDigitWidth = digitWidth; 1078ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov } 1079ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov } 1080ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov int numberOfDigits = 0; 1081ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov int current = mMaxValue; 1082ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov while (current > 0) { 1083ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov numberOfDigits++; 1084ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov current = current / 10; 1085ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov } 1086ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov maxTextWidth = (int) (numberOfDigits * maxDigitWidth); 1087ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov } else { 1088ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov final int valueCount = mDisplayedValues.length; 1089ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov for (int i = 0; i < valueCount; i++) { 1090ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov final float textWidth = mSelectorWheelPaint.measureText(mDisplayedValues[i]); 1091ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov if (textWidth > maxTextWidth) { 1092ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov maxTextWidth = (int) textWidth; 1093ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov } 1094ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov } 1095ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov } 1096ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov maxTextWidth += mInputText.getPaddingLeft() + mInputText.getPaddingRight(); 1097ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov if (mMaxWidth != maxTextWidth) { 1098ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov if (maxTextWidth > mMinWidth) { 1099ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov mMaxWidth = maxTextWidth; 1100ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov } else { 1101ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov mMaxWidth = mMinWidth; 1102ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov } 1103ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov invalidate(); 1104ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov } 1105ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov } 1106ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov 1107ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov /** 1108e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * Gets whether the selector wheel wraps when reaching the min/max value. 110968f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook * 1110e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @return True if the selector wheel wraps. 11114bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * 1112e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @see #getMinValue() 1113e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @see #getMaxValue() 111468f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook */ 1115e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov public boolean getWrapSelectorWheel() { 1116e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov return mWrapSelectorWheel; 1117206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1118206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 1119206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 1120e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * Sets whether the selector wheel shown during flinging/scrolling should 1121e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * wrap around the {@link NumberPicker#getMinValue()} and 1122e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * {@link NumberPicker#getMaxValue()} values. 1123e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * <p> 1124e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * By default if the range (max - min) is more than five (the number of 1125e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * items shown on the selector wheel) the selector wheel wrapping is 1126e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * enabled. 1127e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * </p> 1128206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * 11296304b0d58e74509a9f21b67b5227b2fee2f1b60fSvetoslav Ganov * @param wrapSelectorWheel Whether to wrap. 1130206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 11316304b0d58e74509a9f21b67b5227b2fee2f1b60fSvetoslav Ganov public void setWrapSelectorWheel(boolean wrapSelectorWheel) { 11326304b0d58e74509a9f21b67b5227b2fee2f1b60fSvetoslav Ganov if (wrapSelectorWheel && (mMaxValue - mMinValue) < mSelectorIndices.length) { 1133206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov throw new IllegalStateException("Range less than selector items count."); 1134206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 11356304b0d58e74509a9f21b67b5227b2fee2f1b60fSvetoslav Ganov if (wrapSelectorWheel != mWrapSelectorWheel) { 11366304b0d58e74509a9f21b67b5227b2fee2f1b60fSvetoslav Ganov mWrapSelectorWheel = wrapSelectorWheel; 1137156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov updateIncrementAndDecrementButtonsVisibilityState(); 1138206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 11399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 11424bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * Sets the speed at which the numbers be incremented and decremented when 11434bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * the up and down buttons are long pressed respectively. 1144e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * <p> 1145e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * The default value is 300 ms. 1146e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * </p> 114768f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook * 11484bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * @param intervalMillis The speed (in milliseconds) at which the numbers 1149e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * will be incremented and decremented. 11509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 11514bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov public void setOnLongPressUpdateInterval(long intervalMillis) { 11524bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov mLongPressUpdateInterval = intervalMillis; 11539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1154fdf6db6748b32f620a7f68b13a67c38b4e59e5edTom Taylor 1155206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 1156e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * Returns the value of the picker. 1157e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * 1158e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @return The value. 1159e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov */ 1160e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov public int getValue() { 1161e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov return mValue; 1162e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov } 1163e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov 1164e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov /** 1165e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * Returns the min value of the picker. 1166e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * 1167e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @return The min value 1168e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov */ 1169e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov public int getMinValue() { 1170e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov return mMinValue; 1171e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov } 1172e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov 1173e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov /** 1174e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * Sets the min value of the picker. 1175206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * 1176e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @param minValue The min value. 1177206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 1178e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov public void setMinValue(int minValue) { 1179e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov if (mMinValue == minValue) { 1180e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov return; 1181e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov } 1182e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov if (minValue < 0) { 1183e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov throw new IllegalArgumentException("minValue must be >= 0"); 1184e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov } 1185e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov mMinValue = minValue; 1186e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov if (mMinValue > mValue) { 1187e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov mValue = mMinValue; 1188e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov } 1189e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov boolean wrapSelectorWheel = mMaxValue - mMinValue > mSelectorIndices.length; 1190e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov setWrapSelectorWheel(wrapSelectorWheel); 1191b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov initializeSelectorWheelIndices(); 1192e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov updateInputTextView(); 1193ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov tryComputeMaxWidth(); 1194206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1195206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 11964bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov /** 1197e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * Returns the max value of the picker. 11984bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * 1199e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @return The max value. 12004bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov */ 1201e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov public int getMaxValue() { 1202e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov return mMaxValue; 12034bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov } 12044bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov 12054bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov /** 1206e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * Sets the max value of the picker. 12074bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * 1208e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @param maxValue The max value. 12094bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov */ 1210e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov public void setMaxValue(int maxValue) { 1211e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov if (mMaxValue == maxValue) { 1212e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov return; 1213e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov } 1214e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov if (maxValue < 0) { 1215e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov throw new IllegalArgumentException("maxValue must be >= 0"); 1216e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov } 1217e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov mMaxValue = maxValue; 1218e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov if (mMaxValue < mValue) { 1219e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov mValue = mMaxValue; 1220e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov } 1221e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov boolean wrapSelectorWheel = mMaxValue - mMinValue > mSelectorIndices.length; 1222e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov setWrapSelectorWheel(wrapSelectorWheel); 1223b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov initializeSelectorWheelIndices(); 1224e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov updateInputTextView(); 1225ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov tryComputeMaxWidth(); 1226e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov } 1227e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov 1228e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov /** 1229e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * Gets the values to be displayed instead of string values. 1230e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * 1231e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @return The displayed values. 1232e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov */ 1233e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov public String[] getDisplayedValues() { 1234e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov return mDisplayedValues; 1235e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov } 1236e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov 1237e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov /** 1238e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * Sets the values to be displayed. 1239e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * 1240e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @param displayedValues The displayed values. 1241e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov */ 1242e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov public void setDisplayedValues(String[] displayedValues) { 1243e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov if (mDisplayedValues == displayedValues) { 1244e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov return; 1245e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov } 1246e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov mDisplayedValues = displayedValues; 1247e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov if (mDisplayedValues != null) { 1248e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov // Allow text entry rather than strictly numeric entry. 1249e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov mInputText.setRawInputType(InputType.TYPE_CLASS_TEXT 1250e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov | InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS); 1251e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov } else { 1252e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov mInputText.setRawInputType(InputType.TYPE_CLASS_NUMBER); 1253e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov } 1254e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov updateInputTextView(); 1255b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov initializeSelectorWheelIndices(); 12569f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov tryComputeMaxWidth(); 1257206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1258206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 1259206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov @Override 1260206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov protected float getTopFadingEdgeStrength() { 1261206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return TOP_AND_BOTTOM_FADING_EDGE_STRENGTH; 1262206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1263206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 1264206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov @Override 1265206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov protected float getBottomFadingEdgeStrength() { 1266206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return TOP_AND_BOTTOM_FADING_EDGE_STRENGTH; 1267206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1268206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 1269206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov @Override 12709cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov protected void onAttachedToWindow() { 12719cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov super.onAttachedToWindow(); 12729cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov // make sure we show the controls only the very 12739cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov // first time the user sees this widget 12744fd9dae6a23a22142f73749c291c9fd18459e381Svetoslav Ganov if (mFlingable && !isInEditMode()) { 12759cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov // animate a bit slower the very first time 12769cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov showInputControls(mShowInputControlsAnimimationDuration * 2); 12779cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov } 12789cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov } 12799cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov 12809cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov @Override 1281206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov protected void onDetachedFromWindow() { 1282206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov removeAllCallbacks(); 1283206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1284206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 1285206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov @Override 1286206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov protected void dispatchDraw(Canvas canvas) { 1287206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // There is a good reason for doing this. See comments in draw(). 1288206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1289206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 1290206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov @Override 1291206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov public void draw(Canvas canvas) { 1292206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // Dispatch draw to our children only if we are not currently running 1293b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov // the animation for simultaneously dimming the scroll wheel and 1294206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // showing in the buttons. This class takes advantage of the View 1295206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // implementation of fading edges effect to draw the selector wheel. 1296206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // However, in View.draw(), the fading is applied after all the children 1297206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // have been drawn and we do not want this fading to be applied to the 1298b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov // buttons. Therefore, we draw our children after we have completed 1299b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov // drawing ourselves. 1300c75ec3324e9e3e6500148cc2978caab90ea962e4Chet Haase super.draw(canvas); 1301206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 1302206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // Draw our children if we are not showing the selector wheel of fading 1303206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // it out 1304b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov if (mShowInputControlsAnimator.isRunning() 1305b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov || mSelectorWheelState != SELECTOR_WHEEL_STATE_LARGE) { 1306206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov long drawTime = getDrawingTime(); 1307206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov for (int i = 0, count = getChildCount(); i < count; i++) { 1308206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov View child = getChildAt(i); 1309206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (!child.isShown()) { 1310206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov continue; 1311206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1312206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov drawChild(canvas, getChildAt(i), drawTime); 1313206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1314206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1315206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1316206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 1317206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov @Override 1318206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov protected void onDraw(Canvas canvas) { 1319b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov if (mSelectorWheelState == SELECTOR_WHEEL_STATE_NONE) { 1320206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return; 1321206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1322b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov 1323206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov float x = (mRight - mLeft) / 2; 1324206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov float y = mCurrentScrollOffset; 1325206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 1326b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov final int restoreCount = canvas.save(); 1327b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov 1328b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov if (mSelectorWheelState == SELECTOR_WHEEL_STATE_SMALL) { 1329b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov Rect clipBounds = canvas.getClipBounds(); 1330b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov clipBounds.inset(0, mSelectorElementHeight); 1331b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov canvas.clipRect(clipBounds); 1332b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov } 1333b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov 13349cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov // draw the selector wheel 1335b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov int[] selectorIndices = mSelectorIndices; 1336206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov for (int i = 0; i < selectorIndices.length; i++) { 1337206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov int selectorIndex = selectorIndices[i]; 1338206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov String scrollSelectorValue = mSelectorIndexToStringCache.get(selectorIndex); 13396304b0d58e74509a9f21b67b5227b2fee2f1b60fSvetoslav Ganov // Do not draw the middle item if input is visible since the input is shown only 13406304b0d58e74509a9f21b67b5227b2fee2f1b60fSvetoslav Ganov // if the wheel is static and it covers the middle item. Otherwise, if the user 13416304b0d58e74509a9f21b67b5227b2fee2f1b60fSvetoslav Ganov // starts editing the text via the IME he may see a dimmed version of the old 13426304b0d58e74509a9f21b67b5227b2fee2f1b60fSvetoslav Ganov // value intermixed with the new one. 13436304b0d58e74509a9f21b67b5227b2fee2f1b60fSvetoslav Ganov if (i != SELECTOR_MIDDLE_ITEM_INDEX || mInputText.getVisibility() != VISIBLE) { 13446304b0d58e74509a9f21b67b5227b2fee2f1b60fSvetoslav Ganov canvas.drawText(scrollSelectorValue, x, y, mSelectorWheelPaint); 13456304b0d58e74509a9f21b67b5227b2fee2f1b60fSvetoslav Ganov } 1346206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov y += mSelectorElementHeight; 1347206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 13489cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov 13499cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov // draw the selection dividers (only if scrolling and drawable specified) 13509cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov if (mSelectionDivider != null) { 13519cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov // draw the top divider 13529cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov int topOfTopDivider = 13539cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov (getHeight() - mSelectorElementHeight - mSelectionDividerHeight) / 2; 13549cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov int bottomOfTopDivider = topOfTopDivider + mSelectionDividerHeight; 13559cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov mSelectionDivider.setBounds(0, topOfTopDivider, mRight, bottomOfTopDivider); 13569cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov mSelectionDivider.draw(canvas); 13579cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov 13589cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov // draw the bottom divider 13599cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov int topOfBottomDivider = topOfTopDivider + mSelectorElementHeight; 13609cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov int bottomOfBottomDivider = bottomOfTopDivider + mSelectorElementHeight; 13619cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov mSelectionDivider.setBounds(0, topOfBottomDivider, mRight, bottomOfBottomDivider); 13629cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov mSelectionDivider.draw(canvas); 13639cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov } 1364b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov 1365b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov canvas.restoreToCount(restoreCount); 13669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1367fdf6db6748b32f620a7f68b13a67c38b4e59e5edTom Taylor 13683fec3fe0e3a83c5e0d1264f34bcc55b158537bc6Svetoslav Ganov @Override 13693fec3fe0e3a83c5e0d1264f34bcc55b158537bc6Svetoslav Ganov public void sendAccessibilityEvent(int eventType) { 13703fec3fe0e3a83c5e0d1264f34bcc55b158537bc6Svetoslav Ganov // Do not send accessibility events - we want the user to 13713fec3fe0e3a83c5e0d1264f34bcc55b158537bc6Svetoslav Ganov // perceive this widget as several controls rather as a whole. 13723fec3fe0e3a83c5e0d1264f34bcc55b158537bc6Svetoslav Ganov } 13733fec3fe0e3a83c5e0d1264f34bcc55b158537bc6Svetoslav Ganov 137468f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook /** 1375ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov * Makes a measure spec that tries greedily to use the max value. 1376e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov * 1377e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov * @param measureSpec The measure spec. 1378698e1d5d867a7ac653fa1d6f29cef4cfb73fad38Svetoslav Ganov * @param maxSize The max value for the size. 1379ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov * @return A measure spec greedily imposing the max size. 1380e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov */ 1381698e1d5d867a7ac653fa1d6f29cef4cfb73fad38Svetoslav Ganov private int makeMeasureSpec(int measureSpec, int maxSize) { 13829f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov if (maxSize == SIZE_UNSPECIFIED) { 13839f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov return measureSpec; 13849f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov } 1385ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov final int size = MeasureSpec.getSize(measureSpec); 1386e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov final int mode = MeasureSpec.getMode(measureSpec); 1387e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov switch (mode) { 1388e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov case MeasureSpec.EXACTLY: 1389ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov return measureSpec; 1390e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov case MeasureSpec.AT_MOST: 1391698e1d5d867a7ac653fa1d6f29cef4cfb73fad38Svetoslav Ganov return MeasureSpec.makeMeasureSpec(Math.min(size, maxSize), MeasureSpec.EXACTLY); 1392e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov case MeasureSpec.UNSPECIFIED: 1393698e1d5d867a7ac653fa1d6f29cef4cfb73fad38Svetoslav Ganov return MeasureSpec.makeMeasureSpec(maxSize, MeasureSpec.EXACTLY); 1394e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov default: 1395ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov throw new IllegalArgumentException("Unknown measure mode: " + mode); 1396e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov } 1397e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov } 1398e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov 1399e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov /** 14009f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov * Utility to reconcile a desired size and state, with constraints imposed by 14019f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov * a MeasureSpec. Tries to respect the min size, unless a different size is 14029f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov * imposed by the constraints. 14039f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov * 14049f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov * @param minSize The minimal desired size. 14059f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov * @param measuredSize The currently measured size. 14069f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov * @param measureSpec The current measure spec. 14079f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov * @return The resolved size and state. 14089f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov */ 14099f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov private int resolveSizeAndStateRespectingMinSize(int minSize, int measuredSize, 14109f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov int measureSpec) { 14119f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov if (minSize != SIZE_UNSPECIFIED) { 14129f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov final int desiredWidth = Math.max(minSize, measuredSize); 14139f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov return resolveSizeAndState(desiredWidth, measureSpec, 0); 14149f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov } else { 14159f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov return measuredSize; 14169f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov } 14179f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov } 14189f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov 14199f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov /** 1420a911d4a2b1be7e9ea909a579167826e4a5bac1a3Svetoslav Ganov * Resets the selector indices and clear the cached 1421a911d4a2b1be7e9ea909a579167826e4a5bac1a3Svetoslav Ganov * string representation of these indices. 1422a911d4a2b1be7e9ea909a579167826e4a5bac1a3Svetoslav Ganov */ 1423b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov private void initializeSelectorWheelIndices() { 1424a911d4a2b1be7e9ea909a579167826e4a5bac1a3Svetoslav Ganov mSelectorIndexToStringCache.clear(); 1425b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov int[] selectorIdices = mSelectorIndices; 1426b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov int current = getValue(); 1427b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov for (int i = 0; i < mSelectorIndices.length; i++) { 1428b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov int selectorIndex = current + (i - SELECTOR_MIDDLE_ITEM_INDEX); 1429b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov if (mWrapSelectorWheel) { 1430b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov selectorIndex = getWrappedSelectorIndex(selectorIndex); 1431b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov } 1432b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov mSelectorIndices[i] = selectorIndex; 1433b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov ensureCachedScrollSelectorValue(mSelectorIndices[i]); 1434a911d4a2b1be7e9ea909a579167826e4a5bac1a3Svetoslav Ganov } 1435a911d4a2b1be7e9ea909a579167826e4a5bac1a3Svetoslav Ganov } 1436a911d4a2b1be7e9ea909a579167826e4a5bac1a3Svetoslav Ganov 1437a911d4a2b1be7e9ea909a579167826e4a5bac1a3Svetoslav Ganov /** 1438206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Sets the current value of this NumberPicker, and sets mPrevious to the 1439206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * previous value. If current is greater than mEnd less than mStart, the 1440206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * value of mCurrent is wrapped around. Subclasses can override this to 1441206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * change the wrapping behavior 144268f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook * 144368f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook * @param current the new value of the NumberPicker 144468f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook */ 1445206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private void changeCurrent(int current) { 1446e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov if (mValue == current) { 1447206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return; 1448206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 14499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Wrap around the values if we go past the start or end 1450e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov if (mWrapSelectorWheel) { 1451206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov current = getWrappedSelectorIndex(current); 14529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1453e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov int previous = mValue; 1454e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov setValue(current); 1455206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov notifyChange(previous, current); 14569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1457fdf6db6748b32f620a7f68b13a67c38b4e59e5edTom Taylor 145868f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook /** 1459b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov * Changes the current value by one which is increment or 1460b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov * decrement based on the passes argument. 1461b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov * 1462b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov * @param increment True to increment, false to decrement. 1463b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov */ 1464b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov private void changeCurrentByOne(boolean increment) { 1465b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov if (mFlingable) { 1466b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov mDimSelectorWheelAnimator.cancel(); 1467b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov mInputText.setVisibility(View.INVISIBLE); 1468b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov mSelectorWheelPaint.setAlpha(SELECTOR_WHEEL_BRIGHT_ALPHA); 1469b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov mPreviousScrollerY = 0; 1470b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov forceCompleteChangeCurrentByOneViaScroll(); 1471b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov if (increment) { 1472b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov mFlingScroller.startScroll(0, 0, 0, -mSelectorElementHeight, 1473b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov CHANGE_CURRENT_BY_ONE_SCROLL_DURATION); 1474b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov } else { 1475b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov mFlingScroller.startScroll(0, 0, 0, mSelectorElementHeight, 1476b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov CHANGE_CURRENT_BY_ONE_SCROLL_DURATION); 1477b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov } 1478b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov invalidate(); 1479b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov } else { 1480b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov if (increment) { 1481b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov changeCurrent(mValue + 1); 1482b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov } else { 1483b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov changeCurrent(mValue - 1); 1484b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov } 1485b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov } 1486b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov } 1487b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov 1488b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov /** 1489b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov * Ensures that if we are in the process of changing the current value 1490b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov * by one via scrolling the scroller gets to its final state and the 1491b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov * value is updated. 1492b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov */ 1493b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov private void forceCompleteChangeCurrentByOneViaScroll() { 1494b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov Scroller scroller = mFlingScroller; 1495b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov if (!scroller.isFinished()) { 1496b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov final int yBeforeAbort = scroller.getCurrY(); 1497b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov scroller.abortAnimation(); 1498b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov final int yDelta = scroller.getCurrY() - yBeforeAbort; 1499b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov scrollBy(0, yDelta); 1500b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov } 1501b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov } 1502b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov 1503b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov /** 1504206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Sets the <code>alpha</code> of the {@link Paint} for drawing the selector 1505206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * wheel. 150668f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook */ 1507206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov @SuppressWarnings("unused") 1508b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov // Called via reflection 1509206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private void setSelectorPaintAlpha(int alpha) { 1510b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov mSelectorWheelPaint.setAlpha(alpha); 1511b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov invalidate(); 15129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 151468f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook /** 1515e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov * @return If the <code>event</code> is in the visible <code>view</code>. 151668f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook */ 1517e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov private boolean isEventInVisibleViewHitRect(MotionEvent event, View view) { 1518e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov if (view.getVisibility() == VISIBLE) { 1519e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov view.getHitRect(mTempRect); 1520e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov return mTempRect.contains((int) event.getX(), (int) event.getY()); 1521e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov } 1522e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov return false; 1523206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1524206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 1525206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 1526b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov * Sets the <code>selectorWheelState</code>. 1527206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 1528b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov private void setSelectorWheelState(int selectorWheelState) { 1529b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov mSelectorWheelState = selectorWheelState; 1530b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov if (selectorWheelState == SELECTOR_WHEEL_STATE_LARGE) { 1531b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov mSelectorWheelPaint.setAlpha(SELECTOR_WHEEL_BRIGHT_ALPHA); 1532b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov } 15333fec3fe0e3a83c5e0d1264f34bcc55b158537bc6Svetoslav Ganov 1534b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov if (mFlingable && selectorWheelState == SELECTOR_WHEEL_STATE_LARGE 15353fec3fe0e3a83c5e0d1264f34bcc55b158537bc6Svetoslav Ganov && AccessibilityManager.getInstance(mContext).isEnabled()) { 15363fec3fe0e3a83c5e0d1264f34bcc55b158537bc6Svetoslav Ganov AccessibilityManager.getInstance(mContext).interrupt(); 15373fec3fe0e3a83c5e0d1264f34bcc55b158537bc6Svetoslav Ganov String text = mContext.getString(R.string.number_picker_increment_scroll_action); 15383fec3fe0e3a83c5e0d1264f34bcc55b158537bc6Svetoslav Ganov mInputText.setContentDescription(text); 15393fec3fe0e3a83c5e0d1264f34bcc55b158537bc6Svetoslav Ganov mInputText.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED); 15403fec3fe0e3a83c5e0d1264f34bcc55b158537bc6Svetoslav Ganov mInputText.setContentDescription(null); 15413fec3fe0e3a83c5e0d1264f34bcc55b158537bc6Svetoslav Ganov } 1542206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1543206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 1544b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov private void initializeSelectorWheel() { 1545b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov initializeSelectorWheelIndices(); 1546b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov int[] selectorIndices = mSelectorIndices; 15479cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov int totalTextHeight = selectorIndices.length * mTextSize; 154801fa0d7aae1a551e1e7cfb90d2aeaf2fcb3978afSvetoslav Ganov float totalTextGapHeight = (mBottom - mTop) - totalTextHeight; 154901fa0d7aae1a551e1e7cfb90d2aeaf2fcb3978afSvetoslav Ganov float textGapCount = selectorIndices.length - 1; 1550b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov mSelectorTextGapHeight = (int) (totalTextGapHeight / textGapCount + 0.5f); 1551b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov mSelectorElementHeight = mTextSize + mSelectorTextGapHeight; 1552eeafd4296b7cf4c2ad9c985562f6d70e2a3ffc03Chet Haase // Ensure that the middle item is positioned the same as the text in mInputText 1553eeafd4296b7cf4c2ad9c985562f6d70e2a3ffc03Chet Haase int editTextTextPosition = mInputText.getBaseline() + mInputText.getTop(); 1554eeafd4296b7cf4c2ad9c985562f6d70e2a3ffc03Chet Haase mInitialScrollOffset = editTextTextPosition - 1555eeafd4296b7cf4c2ad9c985562f6d70e2a3ffc03Chet Haase (mSelectorElementHeight * SELECTOR_MIDDLE_ITEM_INDEX); 15566a19fcde07527706c2a9175e0b9f2a71549b7ffeSvetoslav Ganov mCurrentScrollOffset = mInitialScrollOffset; 15579cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov updateInputTextView(); 15589cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov } 15599cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov 1560b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov private void initializeFadingEdges() { 1561b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov setVerticalFadingEdgeEnabled(true); 1562b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov setFadingEdgeLength((mBottom - mTop - mTextSize) / 2); 1563b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov } 1564b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov 1565206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 1566206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Callback invoked upon completion of a given <code>scroller</code>. 1567206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 1568206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private void onScrollerFinished(Scroller scroller) { 1569206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (scroller == mFlingScroller) { 1570b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov if (mSelectorWheelState == SELECTOR_WHEEL_STATE_LARGE) { 1571b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov postAdjustScrollerCommand(0); 1572b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov onScrollStateChange(OnScrollListener.SCROLL_STATE_IDLE); 1573b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov } else { 1574b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov updateInputTextView(); 1575b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov fadeSelectorWheel(mShowInputControlsAnimimationDuration); 1576b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov } 15779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 1578206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov updateInputTextView(); 15799cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov showInputControls(mShowInputControlsAnimimationDuration); 15809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1582fdf6db6748b32f620a7f68b13a67c38b4e59e5edTom Taylor 1583206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 15849cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov * Handles transition to a given <code>scrollState</code> 158550f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov */ 15869cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov private void onScrollStateChange(int scrollState) { 15879cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov if (mScrollState == scrollState) { 15889cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov return; 15899cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov } 15909cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov mScrollState = scrollState; 15919cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov if (mOnScrollListener != null) { 15924bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov mOnScrollListener.onScrollStateChange(this, scrollState); 159350f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov } 159450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov } 159550f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 159650f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov /** 1597206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Flings the selector with the given <code>velocityY</code>. 1598206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 1599206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private void fling(int velocityY) { 1600206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mPreviousScrollerY = 0; 1601206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 1602234484a9fb53786aa8b7ed2a3df7e24d41817689Svetoslav Ganov if (velocityY > 0) { 1603234484a9fb53786aa8b7ed2a3df7e24d41817689Svetoslav Ganov mFlingScroller.fling(0, 0, 0, velocityY, 0, 0, 0, Integer.MAX_VALUE); 1604206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } else { 1605234484a9fb53786aa8b7ed2a3df7e24d41817689Svetoslav Ganov mFlingScroller.fling(0, Integer.MAX_VALUE, 0, velocityY, 0, 0, 0, Integer.MAX_VALUE); 16069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1607206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 1608206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov invalidate(); 16099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1611206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 1612206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Hides the input controls which is the up/down arrows and the text field. 1613206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 1614206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private void hideInputControls() { 1615206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mShowInputControlsAnimator.cancel(); 1616206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mIncrementButton.setVisibility(INVISIBLE); 1617206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mDecrementButton.setVisibility(INVISIBLE); 1618206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mInputText.setVisibility(INVISIBLE); 1619206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1620c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 1621206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 1622206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Show the input controls by making them visible and animating the alpha 1623206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * property up/down arrows. 16249cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov * 16259cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov * @param animationDuration The duration of the animation. 1626206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 16279cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov private void showInputControls(long animationDuration) { 1628206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov updateIncrementAndDecrementButtonsVisibilityState(); 1629206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mInputText.setVisibility(VISIBLE); 16309cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov mShowInputControlsAnimator.setDuration(animationDuration); 1631206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mShowInputControlsAnimator.start(); 1632206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1633c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 1634206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 1635b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov * Fade the selector wheel via an animation. 1636b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov * 1637b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov * @param animationDuration The duration of the animation. 1638b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov */ 1639b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov private void fadeSelectorWheel(long animationDuration) { 1640b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov mInputText.setVisibility(VISIBLE); 1641b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov mDimSelectorWheelAnimator.setDuration(animationDuration); 1642b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov mDimSelectorWheelAnimator.start(); 1643b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov } 1644b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov 1645b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov /** 1646206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Updates the visibility state of the increment and decrement buttons. 1647206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 1648206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private void updateIncrementAndDecrementButtonsVisibilityState() { 1649e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov if (mWrapSelectorWheel || mValue < mMaxValue) { 1650206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mIncrementButton.setVisibility(VISIBLE); 1651206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } else { 1652206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mIncrementButton.setVisibility(INVISIBLE); 1653206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1654e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov if (mWrapSelectorWheel || mValue > mMinValue) { 1655206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mDecrementButton.setVisibility(VISIBLE); 1656206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } else { 1657206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mDecrementButton.setVisibility(INVISIBLE); 16589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 16619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1662206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * @return The wrapped index <code>selectorIndex</code> value. 166368f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook */ 1664206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private int getWrappedSelectorIndex(int selectorIndex) { 1665e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov if (selectorIndex > mMaxValue) { 1666e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov return mMinValue + (selectorIndex - mMaxValue) % (mMaxValue - mMinValue) - 1; 1667e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov } else if (selectorIndex < mMinValue) { 1668e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov return mMaxValue - (mMinValue - selectorIndex) % (mMaxValue - mMinValue) + 1; 1669206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1670206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return selectorIndex; 16719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1672fdf6db6748b32f620a7f68b13a67c38b4e59e5edTom Taylor 1673206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 1674206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Increments the <code>selectorIndices</code> whose string representations 1675206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * will be displayed in the selector. 1676206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 1677b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov private void incrementSelectorIndices(int[] selectorIndices) { 1678206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov for (int i = 0; i < selectorIndices.length - 1; i++) { 1679206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov selectorIndices[i] = selectorIndices[i + 1]; 1680206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1681206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov int nextScrollSelectorIndex = selectorIndices[selectorIndices.length - 2] + 1; 1682e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov if (mWrapSelectorWheel && nextScrollSelectorIndex > mMaxValue) { 1683e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov nextScrollSelectorIndex = mMinValue; 1684206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1685206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov selectorIndices[selectorIndices.length - 1] = nextScrollSelectorIndex; 1686206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov ensureCachedScrollSelectorValue(nextScrollSelectorIndex); 1687206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1688fdf6db6748b32f620a7f68b13a67c38b4e59e5edTom Taylor 1689206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 1690206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Decrements the <code>selectorIndices</code> whose string representations 1691206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * will be displayed in the selector. 1692206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 1693206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private void decrementSelectorIndices(int[] selectorIndices) { 1694206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov for (int i = selectorIndices.length - 1; i > 0; i--) { 1695206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov selectorIndices[i] = selectorIndices[i - 1]; 1696206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1697206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov int nextScrollSelectorIndex = selectorIndices[1] - 1; 1698e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov if (mWrapSelectorWheel && nextScrollSelectorIndex < mMinValue) { 1699e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov nextScrollSelectorIndex = mMaxValue; 1700206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1701206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov selectorIndices[0] = nextScrollSelectorIndex; 1702206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov ensureCachedScrollSelectorValue(nextScrollSelectorIndex); 1703206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1704fdf6db6748b32f620a7f68b13a67c38b4e59e5edTom Taylor 1705206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 1706206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Ensures we have a cached string representation of the given <code> 1707206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * selectorIndex</code> 1708206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * to avoid multiple instantiations of the same string. 1709206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 1710206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private void ensureCachedScrollSelectorValue(int selectorIndex) { 1711206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov SparseArray<String> cache = mSelectorIndexToStringCache; 1712206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov String scrollSelectorValue = cache.get(selectorIndex); 1713206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (scrollSelectorValue != null) { 1714206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return; 1715206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1716e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov if (selectorIndex < mMinValue || selectorIndex > mMaxValue) { 1717206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov scrollSelectorValue = ""; 1718206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } else { 1719206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (mDisplayedValues != null) { 1720e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov int displayedValueIndex = selectorIndex - mMinValue; 172150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov scrollSelectorValue = mDisplayedValues[displayedValueIndex]; 1722206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } else { 1723206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov scrollSelectorValue = formatNumber(selectorIndex); 17249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 17259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1726206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov cache.put(selectorIndex, scrollSelectorValue); 17279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1728fdf6db6748b32f620a7f68b13a67c38b4e59e5edTom Taylor 1729206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private String formatNumber(int value) { 1730e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov return (mFormatter != null) ? mFormatter.format(value) : String.valueOf(value); 1731206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 17329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1733206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private void validateInputTextView(View v) { 1734206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov String str = String.valueOf(((TextView) v).getText()); 1735206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (TextUtils.isEmpty(str)) { 1736206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // Restore to the old value as we don't allow empty values 1737206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov updateInputTextView(); 1738206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } else { 1739206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // Check the new value and ensure it's in range 1740206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov int current = getSelectedPos(str.toString()); 1741206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov changeCurrent(current); 17429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1743206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1744fdf6db6748b32f620a7f68b13a67c38b4e59e5edTom Taylor 1745206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 1746206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Updates the view of this NumberPicker. If displayValues were specified in 17479cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov * the string corresponding to the index specified by the current value will 17489cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov * be returned. Otherwise, the formatter specified in {@link #setFormatter} 17499cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov * will be used to format the number. 1750206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 1751206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private void updateInputTextView() { 1752206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /* 1753206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * If we don't have displayed values then use the current number else 1754206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * find the correct value in the displayed values for the current 1755206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * number. 1756206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 1757206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (mDisplayedValues == null) { 1758e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov mInputText.setText(formatNumber(mValue)); 1759206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } else { 1760e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov mInputText.setText(mDisplayedValues[mValue - mMinValue]); 17619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1762206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mInputText.setSelection(mInputText.getText().length()); 17633fec3fe0e3a83c5e0d1264f34bcc55b158537bc6Svetoslav Ganov 17643fec3fe0e3a83c5e0d1264f34bcc55b158537bc6Svetoslav Ganov if (mFlingable && AccessibilityManager.getInstance(mContext).isEnabled()) { 17653fec3fe0e3a83c5e0d1264f34bcc55b158537bc6Svetoslav Ganov String text = mContext.getString(R.string.number_picker_increment_scroll_mode, 17663fec3fe0e3a83c5e0d1264f34bcc55b158537bc6Svetoslav Ganov mInputText.getText()); 17673fec3fe0e3a83c5e0d1264f34bcc55b158537bc6Svetoslav Ganov mInputText.setContentDescription(text); 17683fec3fe0e3a83c5e0d1264f34bcc55b158537bc6Svetoslav Ganov } 1769206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1770fdf6db6748b32f620a7f68b13a67c38b4e59e5edTom Taylor 1771206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 1772206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Notifies the listener, if registered, of a change of the value of this 1773206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * NumberPicker. 1774206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 1775206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private void notifyChange(int previous, int current) { 1776cedc446684e94c9971c38c3206f1f224314bda2aSvetoslav Ganov if (mOnValueChangeListener != null) { 1777cedc446684e94c9971c38c3206f1f224314bda2aSvetoslav Ganov mOnValueChangeListener.onValueChange(this, previous, mValue); 1778206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1779206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 17809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1781206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 1782b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov * Posts a command for changing the current value by one. 1783b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov * 1784b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov * @param increment Whether to increment or decrement the value. 1785206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 1786b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov private void postChangeCurrentByOneFromLongPress(boolean increment) { 1787206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mInputText.clearFocus(); 1788206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov removeAllCallbacks(); 1789b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov if (mChangeCurrentByOneFromLongPressCommand == null) { 1790b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov mChangeCurrentByOneFromLongPressCommand = new ChangeCurrentByOneFromLongPressCommand(); 1791206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1792b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov mChangeCurrentByOneFromLongPressCommand.setIncrement(increment); 1793b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov post(mChangeCurrentByOneFromLongPressCommand); 1794206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 17959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1796206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 1797206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Removes all pending callback from the message queue. 1798206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 1799206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private void removeAllCallbacks() { 1800b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov if (mChangeCurrentByOneFromLongPressCommand != null) { 1801b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov removeCallbacks(mChangeCurrentByOneFromLongPressCommand); 1802206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1803206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (mAdjustScrollerCommand != null) { 1804206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov removeCallbacks(mAdjustScrollerCommand); 1805206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1806206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (mSetSelectionCommand != null) { 1807206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov removeCallbacks(mSetSelectionCommand); 18089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 18099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 18109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1811206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 1812206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * @return The selected index given its displayed <code>value</code>. 1813206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 1814206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private int getSelectedPos(String value) { 18159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mDisplayedValues == null) { 1816aa516beb79693ceffbd81a7c9d14c940e412cccbRomain Guy try { 1817206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return Integer.parseInt(value); 1818aa516beb79693ceffbd81a7c9d14c940e412cccbRomain Guy } catch (NumberFormatException e) { 1819206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // Ignore as if it's not a number we don't care 1820aa516beb79693ceffbd81a7c9d14c940e412cccbRomain Guy } 18219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 18229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < mDisplayedValues.length; i++) { 1823206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // Don't force the user to type in jan when ja will do 1824206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov value = value.toLowerCase(); 1825206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (mDisplayedValues[i].toLowerCase().startsWith(value)) { 1826e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov return mMinValue + i; 18279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 18289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1829fdf6db6748b32f620a7f68b13a67c38b4e59e5edTom Taylor 1830206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /* 1831206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * The user might have typed in a number into the month field i.e. 18329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 10 instead of OCT so support that too. 18339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 18349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 1835206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return Integer.parseInt(value); 18369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (NumberFormatException e) { 1837fdf6db6748b32f620a7f68b13a67c38b4e59e5edTom Taylor 1838206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // Ignore as if it's not a number we don't care 18399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 18409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1841e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov return mMinValue; 18429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 18439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 18449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1845206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Posts an {@link SetSelectionCommand} from the given <code>selectionStart 1846206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * </code> to 1847206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * <code>selectionEnd</code>. 18489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1849206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private void postSetSelectionCommand(int selectionStart, int selectionEnd) { 1850206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (mSetSelectionCommand == null) { 1851206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mSetSelectionCommand = new SetSelectionCommand(); 1852206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } else { 1853206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov removeCallbacks(mSetSelectionCommand); 1854206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1855206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mSetSelectionCommand.mSelectionStart = selectionStart; 1856206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mSetSelectionCommand.mSelectionEnd = selectionEnd; 1857206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov post(mSetSelectionCommand); 18589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 185968f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook 186068f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook /** 1861206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Posts an {@link AdjustScrollerCommand} within the given <code> 1862206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * delayMillis</code> 1863206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * . 186468f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook */ 1865206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private void postAdjustScrollerCommand(int delayMillis) { 1866206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (mAdjustScrollerCommand == null) { 1867206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mAdjustScrollerCommand = new AdjustScrollerCommand(); 1868206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } else { 1869206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov removeCallbacks(mAdjustScrollerCommand); 1870206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1871206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov postDelayed(mAdjustScrollerCommand, delayMillis); 187268f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook } 187368f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook 187468f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook /** 1875206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Filter for accepting only valid indices or prefixes of the string 1876206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * representation of valid indices. 187768f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook */ 1878206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov class InputTextFilter extends NumberKeyListener { 1879206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 1880206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // XXX This doesn't allow for range limits when controlled by a 1881206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // soft input method! 1882206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov public int getInputType() { 1883206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return InputType.TYPE_CLASS_TEXT; 1884206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1885206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 1886206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov @Override 1887206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov protected char[] getAcceptedChars() { 1888206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return DIGIT_CHARACTERS; 1889206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1890206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 1891206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov @Override 1892206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov public CharSequence filter(CharSequence source, int start, int end, Spanned dest, 1893206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov int dstart, int dend) { 1894206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (mDisplayedValues == null) { 1895206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov CharSequence filtered = super.filter(source, start, end, dest, dstart, dend); 1896206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (filtered == null) { 1897206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov filtered = source.subSequence(start, end); 1898206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1899206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 1900206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov String result = String.valueOf(dest.subSequence(0, dstart)) + filtered 1901206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov + dest.subSequence(dend, dest.length()); 1902206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 1903206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if ("".equals(result)) { 1904206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return result; 1905206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1906206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov int val = getSelectedPos(result); 1907206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 1908206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /* 1909206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Ensure the user can't type in a value greater than the max 1910206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * allowed. We have to allow less than min as the user might 1911206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * want to delete some numbers and then type a new number. 1912206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 1913e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov if (val > mMaxValue) { 1914206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return ""; 1915206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } else { 1916206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return filtered; 1917206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1918206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } else { 1919206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov CharSequence filtered = String.valueOf(source.subSequence(start, end)); 1920206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (TextUtils.isEmpty(filtered)) { 1921206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return ""; 1922206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1923206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov String result = String.valueOf(dest.subSequence(0, dstart)) + filtered 1924206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov + dest.subSequence(dend, dest.length()); 1925206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov String str = String.valueOf(result).toLowerCase(); 1926206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov for (String val : mDisplayedValues) { 1927206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov String valLowerCase = val.toLowerCase(); 1928206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (valLowerCase.startsWith(str)) { 1929206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov postSetSelectionCommand(result.length(), val.length()); 1930206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return val.subSequence(dstart, val.length()); 1931206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1932206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1933206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return ""; 1934206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1935206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1936206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1937206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 1938206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 1939206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Command for setting the input text selection. 1940206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 1941206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov class SetSelectionCommand implements Runnable { 1942206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private int mSelectionStart; 1943206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 1944206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private int mSelectionEnd; 1945206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 1946206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov public void run() { 1947206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mInputText.setSelection(mSelectionStart, mSelectionEnd); 1948206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1949206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1950206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 1951206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 1952206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Command for adjusting the scroller to show in its center the closest of 1953206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * the displayed items. 1954206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 1955206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov class AdjustScrollerCommand implements Runnable { 1956206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov public void run() { 1957206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mPreviousScrollerY = 0; 195834c0688ceafbeef2648bd2287b3b3c3801679448Svetoslav Ganov if (mInitialScrollOffset == mCurrentScrollOffset) { 195934c0688ceafbeef2648bd2287b3b3c3801679448Svetoslav Ganov updateInputTextView(); 19609cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov showInputControls(mShowInputControlsAnimimationDuration); 196134c0688ceafbeef2648bd2287b3b3c3801679448Svetoslav Ganov return; 196234c0688ceafbeef2648bd2287b3b3c3801679448Svetoslav Ganov } 196334c0688ceafbeef2648bd2287b3b3c3801679448Svetoslav Ganov // adjust to the closest value 1964206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov int deltaY = mInitialScrollOffset - mCurrentScrollOffset; 196534c0688ceafbeef2648bd2287b3b3c3801679448Svetoslav Ganov if (Math.abs(deltaY) > mSelectorElementHeight / 2) { 196634c0688ceafbeef2648bd2287b3b3c3801679448Svetoslav Ganov deltaY += (deltaY > 0) ? -mSelectorElementHeight : mSelectorElementHeight; 196734c0688ceafbeef2648bd2287b3b3c3801679448Svetoslav Ganov } 19689cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov mAdjustScroller.startScroll(0, 0, 0, deltaY, SELECTOR_ADJUSTMENT_DURATION_MILLIS); 1969206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov invalidate(); 1970206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1971206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1972206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 1973206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 1974b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov * Command for changing the current value from a long press by one. 1975206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 1976b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov class ChangeCurrentByOneFromLongPressCommand implements Runnable { 1977b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov private boolean mIncrement; 1978206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 1979b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov private void setIncrement(boolean increment) { 1980b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov mIncrement = increment; 1981206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1982206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 1983206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov public void run() { 1984b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov changeCurrentByOne(mIncrement); 19854bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov postDelayed(this, mLongPressUpdateInterval); 1986206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 198768f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook } 19887762d93621f508f4410fd37b5bbdfec0071b0420Paul Westbrook} 1989