NumberPicker.java revision fac14f9731ce7fc765de582c983af751aab697de
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 1968f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrookimport android.annotation.Widget; 209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Context; 21206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganovimport android.content.res.ColorStateList; 22206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganovimport android.content.res.TypedArray; 23206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganovimport android.graphics.Canvas; 24206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganovimport android.graphics.Color; 25206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganovimport android.graphics.Paint; 26e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganovimport android.graphics.Paint.Align; 27b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganovimport android.graphics.Rect; 289cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganovimport android.graphics.drawable.Drawable; 299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.text.InputFilter; 309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.text.InputType; 319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.text.Spanned; 32206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganovimport android.text.TextUtils; 339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.text.method.NumberKeyListener; 349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.AttributeSet; 35206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganovimport android.util.SparseArray; 369cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganovimport android.util.TypedValue; 37206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganovimport android.view.KeyEvent; 389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.LayoutInflater; 39b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganovimport android.view.LayoutInflater.Filter; 40206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganovimport android.view.MotionEvent; 41206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganovimport android.view.VelocityTracker; 429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.View; 43206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganovimport android.view.ViewConfiguration; 443fec3fe0e3a83c5e0d1264f34bcc55b158537bc6Svetoslav Ganovimport android.view.accessibility.AccessibilityEvent; 453fec3fe0e3a83c5e0d1264f34bcc55b158537bc6Svetoslav Ganovimport android.view.accessibility.AccessibilityManager; 468a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganovimport android.view.accessibility.AccessibilityNodeInfo; 47d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganovimport android.view.accessibility.AccessibilityNodeProvider; 489cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganovimport android.view.animation.DecelerateInterpolator; 49a2b41b438d45570867e4682c0caaf93ace5e712eSvetoslav Ganovimport android.view.inputmethod.EditorInfo; 50206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganovimport android.view.inputmethod.InputMethodManager; 519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 52b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganovimport com.android.internal.R; 53b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov 54d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganovimport java.util.ArrayList; 55d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganovimport java.util.Collections; 56d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganovimport java.util.List; 57d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 5868f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook/** 594bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * A widget that enables the user to select a number form a predefined range. 60d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * There are two flavors of this widget and which one is presented to the user 61d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * depends on the current theme. 62d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * <ul> 63d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * <li> 64d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * If the current theme is derived from {@link android.R.style#Theme} the widget 65d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * presents the current value as an editable input field with an increment button 66d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * above and a decrement button below. Long pressing the buttons allows for a quick 67d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * change of the current value. Tapping on the input field allows to type in 68d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * a desired value. 69d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * </li> 70d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * <li> 71d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * If the current theme is derived from {@link android.R.style#Theme_Holo} or 72d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * {@link android.R.style#Theme_Holo_Light} the widget presents the current 73d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * value as an editable input field with a lesser value above and a greater 74d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * value below. Tapping on the lesser or greater value selects it by animating 75d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * the number axis up or down to make the chosen value current. Flinging up 76d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * or down allows for multiple increments or decrements of the current value. 77d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * Long pressing on the lesser and greater values also allows for a quick change 78d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * of the current value. Tapping on the current value allows to type in a 79d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * desired value. 80d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * </li> 81d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * </ul> 824bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * <p> 834bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * For an example of using this widget, see {@link android.widget.TimePicker}. 844bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * </p> 8568f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook */ 8668f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook@Widget 8768f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrookpublic class NumberPicker extends LinearLayout { 88fdf6db6748b32f620a7f68b13a67c38b4e59e5edTom Taylor 8968f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook /** 903f9c9eab7b41c409c3c7b503b89ad340e408b6a0Svetoslav Ganov * The number of items show in the selector wheel. 913f9c9eab7b41c409c3c7b503b89ad340e408b6a0Svetoslav Ganov */ 92d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private static final int SELECTOR_WHEEL_ITEM_COUNT = 3; 933f9c9eab7b41c409c3c7b503b89ad340e408b6a0Svetoslav Ganov 943f9c9eab7b41c409c3c7b503b89ad340e408b6a0Svetoslav Ganov /** 95e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * The default update interval during long press. 96e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov */ 97e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov private static final long DEFAULT_LONG_PRESS_UPDATE_INTERVAL = 300; 98e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov 99e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov /** 100206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * The index of the middle selector item. 10168f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook */ 102d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private static final int SELECTOR_MIDDLE_ITEM_INDEX = SELECTOR_WHEEL_ITEM_COUNT / 2; 1039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10468f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook /** 105206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * The coefficient by which to adjust (divide) the max fling velocity. 10668f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook */ 107206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private static final int SELECTOR_MAX_FLING_VELOCITY_ADJUSTMENT = 8; 1089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 109206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 110206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * The the duration for adjusting the selector wheel. 111206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 112206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private static final int SELECTOR_ADJUSTMENT_DURATION_MILLIS = 800; 113fdf6db6748b32f620a7f68b13a67c38b4e59e5edTom Taylor 114206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 115fe41ce4ef97e7da585fdbf06988da8047e72b9f6Svetoslav Ganov * The duration of scrolling to the next/previous value while snapping to 116fe41ce4ef97e7da585fdbf06988da8047e72b9f6Svetoslav Ganov * a given position. 117b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov */ 118fe41ce4ef97e7da585fdbf06988da8047e72b9f6Svetoslav Ganov private static final int SNAP_SCROLL_DURATION = 300; 119b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov 120b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov /** 121b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov * The strength of fading in the top and bottom while drawing the selector. 122206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 123b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov private static final float TOP_AND_BOTTOM_FADING_EDGE_STRENGTH = 0.9f; 124206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 125206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 126b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov * The default unscaled height of the selection divider. 127206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 128b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov private static final int UNSCALED_DEFAULT_SELECTION_DIVIDER_HEIGHT = 2; 129206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 130206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 131d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * The default unscaled distance between the selection dividers. 132b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov */ 133d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private static final int UNSCALED_DEFAULT_SELECTION_DIVIDERS_DISTANCE = 48; 134b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov 135b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov /** 136d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * The default unscaled minimal distance for a swipe to be considered a fling. 137b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov */ 138d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private static final int UNSCALED_DEFAULT_MIN_FLING_DISTANCE = 150; 139b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov 140b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov /** 141d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * Coefficient for adjusting touch scroll distance. 142b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov */ 143fe41ce4ef97e7da585fdbf06988da8047e72b9f6Svetoslav Ganov private static final float TOUCH_SCROLL_DECELERATION_COEFFICIENT = 2.0f; 144b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov 145b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov /** 146d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * The resource id for the default layout. 147b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov */ 148d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private static final int DEFAULT_LAYOUT_RESOURCE_ID = R.layout.number_picker; 1499cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov 1509cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov /** 151206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * The numbers accepted by the input text's {@link Filter} 152206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 153206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private static final char[] DIGIT_CHARACTERS = new char[] { 154206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' 155fe41ce4ef97e7da585fdbf06988da8047e72b9f6Svetoslav Ganov }; 156206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 157206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 1589f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov * Constant for unspecified size. 1599f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov */ 1609f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov private static final int SIZE_UNSPECIFIED = -1; 1619f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov 1629f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov /** 163206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Use a custom NumberPicker formatting callback to use two-digit minutes 164206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * strings like "01". Keeping a static formatter etc. is the most efficient 165206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * way to do this; it avoids creating temporary objects on every call to 166206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * format(). 167e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * 168e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @hide 169206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 170206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov public static final NumberPicker.Formatter TWO_DIGIT_FORMATTER = new NumberPicker.Formatter() { 171206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov final StringBuilder mBuilder = new StringBuilder(); 172206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 173f0ef665299d795df7905897e1c337e37891dafefJean-Baptiste Queru final java.util.Formatter mFmt = new java.util.Formatter(mBuilder, java.util.Locale.US); 174206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 175206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov final Object[] mArgs = new Object[1]; 176206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 177e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov public String format(int value) { 178206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mArgs[0] = value; 179206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mBuilder.delete(0, mBuilder.length()); 180206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mFmt.format("%02d", mArgs); 181206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return mFmt.toString(); 1829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project }; 1849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 185206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 186206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * The increment button. 187206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 188206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private final ImageButton mIncrementButton; 189206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 190206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 191206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * The decrement button. 192206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 193206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private final ImageButton mDecrementButton; 194206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 195206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 196206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * The text for showing the current value. 197206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 198206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private final EditText mInputText; 199206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 200206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 201d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * The distance between the two selection dividers. 202d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov */ 203d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private final int mSelectionDividersDistance; 204d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 205d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov /** 206ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov * The min height of this widget. 207ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov */ 208ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov private final int mMinHeight; 209ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov 210ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov /** 211e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov * The max height of this widget. 212e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov */ 213e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov private final int mMaxHeight; 214e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov 215e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov /** 216e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov * The max width of this widget. 217e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov */ 218ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov private final int mMinWidth; 219ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov 220ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov /** 221ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov * The max width of this widget. 222ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov */ 223ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov private int mMaxWidth; 224ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov 225ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov /** 226ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov * Flag whether to compute the max width. 227ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov */ 228ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov private final boolean mComputeMaxWidth; 229e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov 230e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov /** 231206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * The height of the text. 232206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 233206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private final int mTextSize; 2349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 235206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 236d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * The minimal distance for a swipe to be considered a fling. 237d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov */ 238d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private final int mMinFlingDistance; 239d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 240d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav 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 */ 293d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private final int[] mSelectorIndices = new int[SELECTOR_WHEEL_ITEM_COUNT]; 294206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 295206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 296206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * The {@link Paint} for drawing the selector. 297206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 298b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov private final Paint mSelectorWheelPaint; 299206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 300206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 301206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * The height of a selector element (text + gap). 302206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 303206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private int mSelectorElementHeight; 304206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 305206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 306206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * The initial offset of the scroll selector. 307206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 308206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private int mInitialScrollOffset = Integer.MIN_VALUE; 309206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 310206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 311206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * The current offset of the scroll selector. 312206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 313206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private int mCurrentScrollOffset; 314206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 315206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 316206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * The {@link Scroller} responsible for flinging the selector. 317206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 318206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private final Scroller mFlingScroller; 319206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 320206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 321206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * The {@link Scroller} responsible for adjusting the selector. 322206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 323206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private final Scroller mAdjustScroller; 324206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 325206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 326206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * The previous Y coordinate while scrolling the selector. 327206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 328206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private int mPreviousScrollerY; 329206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 330206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 331206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Handle to the reusable command for setting the input text selection. 332206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 333206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private SetSelectionCommand mSetSelectionCommand; 334206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 335206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 336b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov * Handle to the reusable command for changing the current value from long 337b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov * press by one. 338206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 339b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov private ChangeCurrentByOneFromLongPressCommand mChangeCurrentByOneFromLongPressCommand; 340206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 341206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 342d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * Command for beginning an edit of the current value via IME on long press. 343b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov */ 344d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private BeginSoftInputOnLongPressCommand mBeginSoftInputOnLongPressCommand; 345b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov 346b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov /** 347206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * The Y position of the last down event. 348206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 349206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private float mLastDownEventY; 350206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 351206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 352d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * The time of the last down event. 353206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 354d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private long mLastDownEventTime; 355206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 356206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 357d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * The Y position of the last down or move event. 358206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 359d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private float mLastDownOrMoveEventY; 360206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 361206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 362206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Determines speed during touch scrolling. 363206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 364206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private VelocityTracker mVelocityTracker; 365206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 366206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 367206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * @see ViewConfiguration#getScaledTouchSlop() 368206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 369206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private int mTouchSlop; 370206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 371206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 372206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * @see ViewConfiguration#getScaledMinimumFlingVelocity() 373206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 374206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private int mMinimumFlingVelocity; 375206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 376206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 377206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * @see ViewConfiguration#getScaledMaximumFlingVelocity() 378206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 379206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private int mMaximumFlingVelocity; 380206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 381206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 382206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Flag whether the selector should wrap around. 383206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 384e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov private boolean mWrapSelectorWheel; 385206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 386206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 387206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * The back ground color used to optimize scroller fading. 38868f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook */ 389206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private final int mSolidColor; 390206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 391206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 392d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * Flag whether this widget has a selector wheel. 3934243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov */ 394d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private final boolean mHasSelectorWheel; 3954243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov 3964243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov /** 3979cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov * Divider for showing item to be selected while scrolling 3989cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov */ 3999cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov private final Drawable mSelectionDivider; 4009cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov 4019cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov /** 4029cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov * The height of the selection divider. 4039cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov */ 4049cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov private final int mSelectionDividerHeight; 4059cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov 4069cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov /** 407d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * The current scroll state of the number picker. 408206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 409d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private int mScrollState = OnScrollListener.SCROLL_STATE_IDLE; 410206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 411206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 412d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * Flag whether to ignore move events - we ignore such when we show in IME 413d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * to prevent the content from scrolling. 41450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov */ 415d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private boolean mIngonreMoveEvents; 41650f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 41750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov /** 418d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * Flag whether to show soft input on tap. 4199cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov */ 420d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private boolean mShowSoftInputOnTap; 4219cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov 4229cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov /** 423d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * The top of the top selection divider. 424b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov */ 425d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private int mTopSelectionDividerTop; 426b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov 427b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov /** 428d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * The bottom of the bottom selection divider. 429a2b41b438d45570867e4682c0caaf93ace5e712eSvetoslav Ganov */ 430d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private int mBottomSelectionDividerBottom; 431d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 432d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov /** 433d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * The virtual id of the last hovered child. 434d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov */ 435d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private int mLastHoveredChildVirtualViewId; 436d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 437d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov /** 438d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * Provider to report to clients the semantic structure of this widget. 439d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov */ 440d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private AccessibilityNodeProviderImpl mAccessibilityNodeProvider; 441a2b41b438d45570867e4682c0caaf93ace5e712eSvetoslav Ganov 442a2b41b438d45570867e4682c0caaf93ace5e712eSvetoslav Ganov /** 443e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * Interface to listen for changes of the current value. 444206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 445cedc446684e94c9971c38c3206f1f224314bda2aSvetoslav Ganov public interface OnValueChangeListener { 446e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov 447206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 4484bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * Called upon a change of the current value. 4494bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * 450206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * @param picker The NumberPicker associated with this listener. 451206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * @param oldVal The previous value. 452206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * @param newVal The new value. 453206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 454e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov void onValueChange(NumberPicker picker, int oldVal, int newVal); 455206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 456206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 457206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 458e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * Interface to listen for the picker scroll state. 45950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov */ 46050f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov public interface OnScrollListener { 46150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 46250f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov /** 46350f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * The view is not scrolling. 46450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov */ 46550f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov public static int SCROLL_STATE_IDLE = 0; 46650f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 46750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov /** 468d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * The user is scrolling using touch, and his finger is still on the screen. 46950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov */ 47050f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov public static int SCROLL_STATE_TOUCH_SCROLL = 1; 47150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 47250f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov /** 47350f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * The user had previously been scrolling using touch and performed a fling. 47450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov */ 47550f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov public static int SCROLL_STATE_FLING = 2; 47650f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 47750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov /** 478e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * Callback invoked while the number picker scroll state has changed. 47950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * 480e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @param view The view whose scroll state is being reported. 481e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @param scrollState The current scroll state. One of 482e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * {@link #SCROLL_STATE_IDLE}, 483e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * {@link #SCROLL_STATE_TOUCH_SCROLL} or 484e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * {@link #SCROLL_STATE_IDLE}. 48550f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov */ 4864bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov public void onScrollStateChange(NumberPicker view, int scrollState); 48750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov } 48850f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 48950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov /** 490e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * Interface used to format current value into a string for presentation. 491206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 492206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov public interface Formatter { 4934bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov 4944bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov /** 495e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * Formats a string representation of the current value. 4964bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * 4974bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * @param value The currently selected value. 4984bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * @return A formatted string representation. 4994bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov */ 500e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov public String format(int value); 5019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 502fdf6db6748b32f620a7f68b13a67c38b4e59e5edTom Taylor 50368f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook /** 5044bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * Create a new number picker. 5054bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * 5064bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * @param context The application environment. 5074bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov */ 5084bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov public NumberPicker(Context context) { 5094bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov this(context, null); 5104bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov } 5114bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov 5124bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov /** 5134bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * Create a new number picker. 514206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * 515206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * @param context The application environment. 516206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * @param attrs A collection of attributes. 51768f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook */ 5189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public NumberPicker(Context context, AttributeSet attrs) { 519206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov this(context, attrs, R.attr.numberPickerStyle); 520206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 521206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 522206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 523206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Create a new number picker 524206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * 525206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * @param context the application environment. 526206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * @param attrs a collection of attributes. 527206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * @param defStyle The default style to apply to this view. 528206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 529206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov public NumberPicker(Context context, AttributeSet attrs, int defStyle) { 530206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov super(context, attrs, defStyle); 531206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 532206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // process style attributes 533d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov TypedArray attributesArray = context.obtainStyledAttributes( 534d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov attrs, R.styleable.NumberPicker, defStyle, 0); 535d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov final int layoutResId = attributesArray.getResourceId( 536d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov R.styleable.NumberPicker_internalLayout, DEFAULT_LAYOUT_RESOURCE_ID); 537d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 538d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mHasSelectorWheel = (layoutResId != DEFAULT_LAYOUT_RESOURCE_ID); 539d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 540206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mSolidColor = attributesArray.getColor(R.styleable.NumberPicker_solidColor, 0); 541d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 5429cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov mSelectionDivider = attributesArray.getDrawable(R.styleable.NumberPicker_selectionDivider); 543d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 544d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov final int defSelectionDividerHeight = (int) TypedValue.applyDimension( 545d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov TypedValue.COMPLEX_UNIT_DIP, UNSCALED_DEFAULT_SELECTION_DIVIDER_HEIGHT, 5469cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov getResources().getDisplayMetrics()); 5479cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov mSelectionDividerHeight = attributesArray.getDimensionPixelSize( 5489cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov R.styleable.NumberPicker_selectionDividerHeight, defSelectionDividerHeight); 549d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 550d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov final int defSelectionDividerDistance = (int) TypedValue.applyDimension( 551d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov TypedValue.COMPLEX_UNIT_DIP, UNSCALED_DEFAULT_SELECTION_DIVIDERS_DISTANCE, 552d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov getResources().getDisplayMetrics()); 553d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mSelectionDividersDistance = attributesArray.getDimensionPixelSize( 554d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov R.styleable.NumberPicker_selectionDividersDistance, defSelectionDividerDistance); 555d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 556d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov final int defMinFlingDistance = (int) TypedValue.applyDimension( 557d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov TypedValue.COMPLEX_UNIT_DIP, UNSCALED_DEFAULT_MIN_FLING_DISTANCE, 558d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov getResources().getDisplayMetrics()); 559d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mMinFlingDistance = attributesArray.getDimensionPixelSize( 560d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov R.styleable.NumberPicker_minFlingDistance, defMinFlingDistance); 561d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 562e8331bd2e7ad3d62140143cafba3ff69be028557Svetoslav Ganov mMinHeight = attributesArray.getDimensionPixelSize( 563e8331bd2e7ad3d62140143cafba3ff69be028557Svetoslav Ganov R.styleable.NumberPicker_internalMinHeight, SIZE_UNSPECIFIED); 564d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 565e8331bd2e7ad3d62140143cafba3ff69be028557Svetoslav Ganov mMaxHeight = attributesArray.getDimensionPixelSize( 566e8331bd2e7ad3d62140143cafba3ff69be028557Svetoslav Ganov R.styleable.NumberPicker_internalMaxHeight, SIZE_UNSPECIFIED); 5679f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov if (mMinHeight != SIZE_UNSPECIFIED && mMaxHeight != SIZE_UNSPECIFIED 5689f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov && mMinHeight > mMaxHeight) { 569ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov throw new IllegalArgumentException("minHeight > maxHeight"); 570ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov } 571d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 572d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mMinWidth = attributesArray.getDimensionPixelSize( 573d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov R.styleable.NumberPicker_internalMinWidth, SIZE_UNSPECIFIED); 574d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 575d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mMaxWidth = attributesArray.getDimensionPixelSize( 576d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov R.styleable.NumberPicker_internalMaxWidth, SIZE_UNSPECIFIED); 5779f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov if (mMinWidth != SIZE_UNSPECIFIED && mMaxWidth != SIZE_UNSPECIFIED 5789f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov && mMinWidth > mMaxWidth) { 579ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov throw new IllegalArgumentException("minWidth > maxWidth"); 580ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov } 581d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 582ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov mComputeMaxWidth = (mMaxWidth == Integer.MAX_VALUE); 583206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 584d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov attributesArray.recycle(); 5859cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov 586206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // By default Linearlayout that we extend is not drawn. This is 587206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // its draw() method is not called but dispatchDraw() is called 588206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // directly (see ViewGroup.drawChild()). However, this class uses 589206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // the fading edge effect implemented by View and we need our 590206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // draw() method to be called. Therefore, we declare we will draw. 591d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov setWillNotDraw(!mHasSelectorWheel); 592206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 593206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov LayoutInflater inflater = (LayoutInflater) getContext().getSystemService( 594206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov Context.LAYOUT_INFLATER_SERVICE); 595d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov inflater.inflate(layoutResId, this, true); 59668f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook 597206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov OnClickListener onClickListener = new OnClickListener() { 59868f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook public void onClick(View v) { 599b52d9729bfb2ef7ad50d9a5125ebf3a8322429a9Svetoslav Ganov hideSoftInput(); 600206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mInputText.clearFocus(); 601206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (v.getId() == R.id.increment) { 602d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov changeValueByOne(true); 603206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } else { 604d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov changeValueByOne(false); 60568f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook } 60668f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook } 60768f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook }; 60868f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook 609206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov OnLongClickListener onLongClickListener = new OnLongClickListener() { 610206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov public boolean onLongClick(View v) { 611b52d9729bfb2ef7ad50d9a5125ebf3a8322429a9Svetoslav Ganov hideSoftInput(); 612206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mInputText.clearFocus(); 613206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (v.getId() == R.id.increment) { 614d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov postChangeCurrentByOneFromLongPress(true, 0); 615206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } else { 616d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov postChangeCurrentByOneFromLongPress(false, 0); 617206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 618206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return true; 619206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 620206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov }; 62168f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook 622206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // increment button 623d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (!mHasSelectorWheel) { 624d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mIncrementButton = (ImageButton) findViewById(R.id.increment); 625d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mIncrementButton.setOnClickListener(onClickListener); 626d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mIncrementButton.setOnLongClickListener(onLongClickListener); 627d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } else { 628d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mIncrementButton = null; 629d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 630206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 631206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // decrement button 632d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (!mHasSelectorWheel) { 633d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mDecrementButton = (ImageButton) findViewById(R.id.decrement); 634d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mDecrementButton.setOnClickListener(onClickListener); 635d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mDecrementButton.setOnLongClickListener(onLongClickListener); 636d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } else { 637d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mDecrementButton = null; 638d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 639206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 640206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // input text 641012dd5a461f18a2e5dad38c60282fac1c21ff7feSvetoslav Ganov mInputText = (EditText) findViewById(R.id.numberpicker_input); 642206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mInputText.setOnFocusChangeListener(new OnFocusChangeListener() { 643206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov public void onFocusChange(View v, boolean hasFocus) { 644a53efe9923bedab4fe5d578f32eaff308e5b9e76Svetoslav Ganov if (hasFocus) { 645a53efe9923bedab4fe5d578f32eaff308e5b9e76Svetoslav Ganov mInputText.selectAll(); 646a53efe9923bedab4fe5d578f32eaff308e5b9e76Svetoslav Ganov } else { 647a53efe9923bedab4fe5d578f32eaff308e5b9e76Svetoslav Ganov mInputText.setSelection(0, 0); 648206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov validateInputTextView(v); 64968f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook } 65068f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook } 651206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov }); 652206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mInputText.setFilters(new InputFilter[] { 653206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov new InputTextFilter() 654206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov }); 65568f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook 656206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mInputText.setRawInputType(InputType.TYPE_CLASS_NUMBER); 657a2b41b438d45570867e4682c0caaf93ace5e712eSvetoslav Ganov mInputText.setImeOptions(EditorInfo.IME_ACTION_DONE); 658206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 659206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // initialize constants 660206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov ViewConfiguration configuration = ViewConfiguration.get(context); 661206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mTouchSlop = configuration.getScaledTouchSlop(); 662206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mMinimumFlingVelocity = configuration.getScaledMinimumFlingVelocity(); 663206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mMaximumFlingVelocity = configuration.getScaledMaximumFlingVelocity() 664206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov / SELECTOR_MAX_FLING_VELOCITY_ADJUSTMENT; 665206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mTextSize = (int) mInputText.getTextSize(); 666206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 667206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // create the selector wheel paint 668206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov Paint paint = new Paint(); 669206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov paint.setAntiAlias(true); 670206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov paint.setTextAlign(Align.CENTER); 671206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov paint.setTextSize(mTextSize); 672206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov paint.setTypeface(mInputText.getTypeface()); 673206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov ColorStateList colors = mInputText.getTextColors(); 674206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov int color = colors.getColorForState(ENABLED_STATE_SET, Color.WHITE); 675206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov paint.setColor(color); 676b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov mSelectorWheelPaint = paint; 677206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 678206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // create the fling and adjust scrollers 679bf80562d22b2bbe7944d80d0524c69d0238010cbSvetoslav Ganov mFlingScroller = new Scroller(getContext(), null, true); 6809cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov mAdjustScroller = new Scroller(getContext(), new DecelerateInterpolator(2.5f)); 681fdf6db6748b32f620a7f68b13a67c38b4e59e5edTom Taylor 682206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov updateInputTextView(); 683206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 684206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 685206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov @Override 6869cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov protected void onLayout(boolean changed, int left, int top, int right, int bottom) { 687d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (!mHasSelectorWheel) { 688d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov super.onLayout(changed, left, top, right, bottom); 689d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return; 690d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 691ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov final int msrdWdth = getMeasuredWidth(); 692ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov final int msrdHght = getMeasuredHeight(); 693ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov 694ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov // Input text centered horizontally. 695ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov final int inptTxtMsrdWdth = mInputText.getMeasuredWidth(); 696ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov final int inptTxtMsrdHght = mInputText.getMeasuredHeight(); 697ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov final int inptTxtLeft = (msrdWdth - inptTxtMsrdWdth) / 2; 698ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov final int inptTxtTop = (msrdHght - inptTxtMsrdHght) / 2; 699ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov final int inptTxtRight = inptTxtLeft + inptTxtMsrdWdth; 700ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov final int inptTxtBottom = inptTxtTop + inptTxtMsrdHght; 701ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov mInputText.layout(inptTxtLeft, inptTxtTop, inptTxtRight, inptTxtBottom); 702ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov 703d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (changed) { 704b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov // need to do all this when we know our size 705b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov initializeSelectorWheel(); 706b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov initializeFadingEdges(); 707d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mTopSelectionDividerTop = (getHeight() - mSelectionDividersDistance) / 2 708d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov - mSelectionDividerHeight; 709d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mBottomSelectionDividerBottom = mTopSelectionDividerTop + 2 * mSelectionDividerHeight 710d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov + mSelectionDividersDistance; 711b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov } 712206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 713206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 714206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov @Override 715e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 716d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (!mHasSelectorWheel) { 717d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov super.onMeasure(widthMeasureSpec, heightMeasureSpec); 718d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return; 719d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 720698e1d5d867a7ac653fa1d6f29cef4cfb73fad38Svetoslav Ganov // Try greedily to fit the max width and height. 721698e1d5d867a7ac653fa1d6f29cef4cfb73fad38Svetoslav Ganov final int newWidthMeasureSpec = makeMeasureSpec(widthMeasureSpec, mMaxWidth); 722698e1d5d867a7ac653fa1d6f29cef4cfb73fad38Svetoslav Ganov final int newHeightMeasureSpec = makeMeasureSpec(heightMeasureSpec, mMaxHeight); 723ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov super.onMeasure(newWidthMeasureSpec, newHeightMeasureSpec); 724698e1d5d867a7ac653fa1d6f29cef4cfb73fad38Svetoslav Ganov // Flag if we are measured with width or height less than the respective min. 7259f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov final int widthSize = resolveSizeAndStateRespectingMinSize(mMinWidth, getMeasuredWidth(), 7269f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov widthMeasureSpec); 7279f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov final int heightSize = resolveSizeAndStateRespectingMinSize(mMinHeight, getMeasuredHeight(), 7289f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov heightMeasureSpec); 729698e1d5d867a7ac653fa1d6f29cef4cfb73fad38Svetoslav Ganov setMeasuredDimension(widthSize, heightSize); 730e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov } 731e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov 732d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov /** 733d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * Move to the final position of a scroller. Ensures to force finish the scroller 734d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * and if it is not at its final position a scroll of the selector wheel is 735d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * performed to fast forward to the final position. 736d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * 737d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * @param scroller The scroller to whose final position to get. 738d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * @return True of the a move was performed, i.e. the scroller was not in final position. 739d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov */ 740d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private boolean moveToFinalScrollerPosition(Scroller scroller) { 741d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov scroller.forceFinished(true); 742d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov int amountToScroll = scroller.getFinalY() - scroller.getCurrY(); 743d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov int futureScrollOffset = (mCurrentScrollOffset + amountToScroll) % mSelectorElementHeight; 744d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov int overshootAdjustment = mInitialScrollOffset - futureScrollOffset; 745d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (overshootAdjustment != 0) { 746d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (Math.abs(overshootAdjustment) > mSelectorElementHeight / 2) { 747d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (overshootAdjustment > 0) { 748d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov overshootAdjustment -= mSelectorElementHeight; 749d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } else { 750d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov overshootAdjustment += mSelectorElementHeight; 751d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 752d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 753d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov amountToScroll += overshootAdjustment; 754d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov scrollBy(0, amountToScroll); 755d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return true; 756d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 757d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return false; 758d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 759d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 760e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov @Override 761206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov public boolean onInterceptTouchEvent(MotionEvent event) { 762d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (!mHasSelectorWheel || !isEnabled()) { 76351c52edad7d40697d7fb2a091f850506fa897643Svetoslav Ganov return false; 76451c52edad7d40697d7fb2a091f850506fa897643Svetoslav Ganov } 765d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov final int action = event.getActionMasked(); 766d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov switch (action) { 767d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov case MotionEvent.ACTION_DOWN: { 768206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov removeAllCallbacks(); 769d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mInputText.setVisibility(View.INVISIBLE); 770d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mLastDownOrMoveEventY = mLastDownEventY = event.getY(); 771d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mLastDownEventTime = event.getEventTime(); 772d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mIngonreMoveEvents = false; 773d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mShowSoftInputOnTap = false; 774d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (!mFlingScroller.isFinished()) { 775d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mFlingScroller.forceFinished(true); 776d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mAdjustScroller.forceFinished(true); 777d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov onScrollStateChange(OnScrollListener.SCROLL_STATE_IDLE); 778d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } else if (!mAdjustScroller.isFinished()) { 779d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mFlingScroller.forceFinished(true); 780d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mAdjustScroller.forceFinished(true); 781d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } else if (mLastDownEventY < mTopSelectionDividerTop) { 782b52d9729bfb2ef7ad50d9a5125ebf3a8322429a9Svetoslav Ganov hideSoftInput(); 783d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov postChangeCurrentByOneFromLongPress( 784d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov false, ViewConfiguration.getLongPressTimeout()); 785d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } else if (mLastDownEventY > mBottomSelectionDividerBottom) { 786b52d9729bfb2ef7ad50d9a5125ebf3a8322429a9Svetoslav Ganov hideSoftInput(); 787d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov postChangeCurrentByOneFromLongPress( 788d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov true, ViewConfiguration.getLongPressTimeout()); 789d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } else { 790d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mShowSoftInputOnTap = true; 791d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov postBeginSoftInputOnLongPressCommand(); 792206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 793d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return true; 794d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 795206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 796206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return false; 797206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 798206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 799206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov @Override 800d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov public boolean onTouchEvent(MotionEvent event) { 801d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (!isEnabled() || !mHasSelectorWheel) { 80251c52edad7d40697d7fb2a091f850506fa897643Svetoslav Ganov return false; 80351c52edad7d40697d7fb2a091f850506fa897643Svetoslav Ganov } 804206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (mVelocityTracker == null) { 805206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mVelocityTracker = VelocityTracker.obtain(); 806206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 807d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mVelocityTracker.addMovement(event); 808d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov int action = event.getActionMasked(); 809206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov switch (action) { 810d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov case MotionEvent.ACTION_MOVE: { 811d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (mIngonreMoveEvents) { 812d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov break; 813d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 814d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov float currentMoveY = event.getY(); 815d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (mScrollState != OnScrollListener.SCROLL_STATE_TOUCH_SCROLL) { 816206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov int deltaDownY = (int) Math.abs(currentMoveY - mLastDownEventY); 817206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (deltaDownY > mTouchSlop) { 818d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov removeAllCallbacks(); 8199cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov onScrollStateChange(OnScrollListener.SCROLL_STATE_TOUCH_SCROLL); 820206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 821d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } else { 822d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov int deltaMoveY = (int) ((currentMoveY - mLastDownOrMoveEventY) 823d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov / TOUCH_SCROLL_DECELERATION_COEFFICIENT); 824d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov scrollBy(0, deltaMoveY); 825d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov invalidate(); 826206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 827d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mLastDownOrMoveEventY = currentMoveY; 828d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } break; 829d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov case MotionEvent.ACTION_UP: { 830d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov removeBeginSoftInputCommand(); 831d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov removeChangeCurrentByOneFromLongPress(); 832206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov VelocityTracker velocityTracker = mVelocityTracker; 833206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov velocityTracker.computeCurrentVelocity(1000, mMaximumFlingVelocity); 834206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov int initialVelocity = (int) velocityTracker.getYVelocity(); 835206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (Math.abs(initialVelocity) > mMinimumFlingVelocity) { 836d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov int deltaMove = (int) (event.getY() - mLastDownEventY); 837d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov int absDeltaMoveY = Math.abs(deltaMove); 838d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (absDeltaMoveY > mMinFlingDistance) { 839d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov fling(initialVelocity); 840d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } else { 841fe41ce4ef97e7da585fdbf06988da8047e72b9f6Svetoslav Ganov final int normalizedDeltaMove = 842fe41ce4ef97e7da585fdbf06988da8047e72b9f6Svetoslav Ganov (int) (absDeltaMoveY / TOUCH_SCROLL_DECELERATION_COEFFICIENT); 843fe41ce4ef97e7da585fdbf06988da8047e72b9f6Svetoslav Ganov if (normalizedDeltaMove < mSelectorElementHeight) { 844fe41ce4ef97e7da585fdbf06988da8047e72b9f6Svetoslav Ganov snapToNextValue(deltaMove < 0); 845fe41ce4ef97e7da585fdbf06988da8047e72b9f6Svetoslav Ganov } else { 846fe41ce4ef97e7da585fdbf06988da8047e72b9f6Svetoslav Ganov snapToClosestValue(); 847fe41ce4ef97e7da585fdbf06988da8047e72b9f6Svetoslav Ganov } 848d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 8499cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov onScrollStateChange(OnScrollListener.SCROLL_STATE_FLING); 850206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } else { 851d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov int eventY = (int) event.getY(); 852d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov int deltaMoveY = (int) Math.abs(eventY - mLastDownEventY); 853d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov long deltaTime = event.getEventTime() - mLastDownEventTime; 854d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (deltaMoveY <= mTouchSlop && deltaTime < ViewConfiguration.getTapTimeout()) { 855d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (mShowSoftInputOnTap) { 856d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mShowSoftInputOnTap = false; 857d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov showSoftInput(); 858d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } else { 859d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov int selectorIndexOffset = (eventY / mSelectorElementHeight) 860d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov - SELECTOR_MIDDLE_ITEM_INDEX; 861d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (selectorIndexOffset > 0) { 862d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov changeValueByOne(true); 863d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } else if (selectorIndexOffset < 0) { 864d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov changeValueByOne(false); 865d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 866206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 867206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } else { 868d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov ensureScrollWheelAdjusted(); 869206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 870d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov onScrollStateChange(OnScrollListener.SCROLL_STATE_IDLE); 871206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 872206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mVelocityTracker.recycle(); 873206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mVelocityTracker = null; 874d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } break; 875206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 876206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return true; 877206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 878206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 879206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov @Override 880206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov public boolean dispatchTouchEvent(MotionEvent event) { 881b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov final int action = event.getActionMasked(); 882b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov switch (action) { 883b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov case MotionEvent.ACTION_CANCEL: 884b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov case MotionEvent.ACTION_UP: 885b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov removeAllCallbacks(); 886b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov break; 887206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 888206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return super.dispatchTouchEvent(event); 889206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 890206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 891206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov @Override 892206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov public boolean dispatchKeyEvent(KeyEvent event) { 893d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov final int keyCode = event.getKeyCode(); 894d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov switch (keyCode) { 895d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov case KeyEvent.KEYCODE_DPAD_CENTER: 896d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov case KeyEvent.KEYCODE_ENTER: 897d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov removeAllCallbacks(); 898d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov break; 899206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 900206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return super.dispatchKeyEvent(event); 901206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 902206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 903206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov @Override 904206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov public boolean dispatchTrackballEvent(MotionEvent event) { 905d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov final int action = event.getActionMasked(); 906d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov switch (action) { 907d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov case MotionEvent.ACTION_CANCEL: 908d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov case MotionEvent.ACTION_UP: 909d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov removeAllCallbacks(); 910d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov break; 911206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 912206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return super.dispatchTrackballEvent(event); 913206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 9149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 915206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov @Override 916d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov protected boolean dispatchHoverEvent(MotionEvent event) { 917d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (!mHasSelectorWheel) { 918d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return super.dispatchHoverEvent(event); 919d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 920d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (AccessibilityManager.getInstance(mContext).isEnabled()) { 921d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov final int eventY = (int) event.getY(); 922d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov final int hoveredVirtualViewId; 923d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (eventY < mTopSelectionDividerTop) { 924d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov hoveredVirtualViewId = AccessibilityNodeProviderImpl.VIRTUAL_VIEW_ID_DECREMENT; 925d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } else if (eventY > mBottomSelectionDividerBottom) { 926d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov hoveredVirtualViewId = AccessibilityNodeProviderImpl.VIRTUAL_VIEW_ID_INCREMENT; 927d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } else { 928d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov hoveredVirtualViewId = AccessibilityNodeProviderImpl.VIRTUAL_VIEW_ID_INPUT; 929d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 930d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov final int action = event.getActionMasked(); 931d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov AccessibilityNodeProviderImpl provider = 932d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov (AccessibilityNodeProviderImpl) getAccessibilityNodeProvider(); 933d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov switch (action) { 934d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov case MotionEvent.ACTION_HOVER_ENTER: { 935d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov provider.sendAccessibilityEventForVirtualView(hoveredVirtualViewId, 936d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov AccessibilityEvent.TYPE_VIEW_HOVER_ENTER); 937d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mLastHoveredChildVirtualViewId = hoveredVirtualViewId; 938d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } break; 939d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov case MotionEvent.ACTION_HOVER_MOVE: { 940d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (mLastHoveredChildVirtualViewId != hoveredVirtualViewId 941d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov && mLastHoveredChildVirtualViewId != View.NO_ID) { 942d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov provider.sendAccessibilityEventForVirtualView( 943d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mLastHoveredChildVirtualViewId, 944d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov AccessibilityEvent.TYPE_VIEW_HOVER_EXIT); 945d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov provider.sendAccessibilityEventForVirtualView(hoveredVirtualViewId, 946d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov AccessibilityEvent.TYPE_VIEW_HOVER_ENTER); 947d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mLastHoveredChildVirtualViewId = hoveredVirtualViewId; 948d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 949d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } break; 950d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov case MotionEvent.ACTION_HOVER_EXIT: { 951d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov provider.sendAccessibilityEventForVirtualView(hoveredVirtualViewId, 952d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov AccessibilityEvent.TYPE_VIEW_HOVER_EXIT); 953d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mLastHoveredChildVirtualViewId = View.NO_ID; 954d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } break; 955d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 956206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 957d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return false; 958d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 959d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 960d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov @Override 961d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov public void computeScroll() { 962206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov Scroller scroller = mFlingScroller; 963206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (scroller.isFinished()) { 964206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov scroller = mAdjustScroller; 965206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (scroller.isFinished()) { 966206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return; 967206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 968206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 969206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov scroller.computeScrollOffset(); 970206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov int currentScrollerY = scroller.getCurrY(); 971206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (mPreviousScrollerY == 0) { 972206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mPreviousScrollerY = scroller.getStartY(); 973206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 974206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov scrollBy(0, currentScrollerY - mPreviousScrollerY); 975206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mPreviousScrollerY = currentScrollerY; 976206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (scroller.isFinished()) { 977206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov onScrollerFinished(scroller); 978206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } else { 979206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov invalidate(); 9809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 982fdf6db6748b32f620a7f68b13a67c38b4e59e5edTom Taylor 9839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 9849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void setEnabled(boolean enabled) { 9859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project super.setEnabled(enabled); 986d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (!mHasSelectorWheel) { 987d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mIncrementButton.setEnabled(enabled); 988d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 989d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (!mHasSelectorWheel) { 990d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mDecrementButton.setEnabled(enabled); 991d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 992206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mInputText.setEnabled(enabled); 993206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 994206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 995206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov @Override 996206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov public void scrollBy(int x, int y) { 997b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov int[] selectorIndices = mSelectorIndices; 99834c0688ceafbeef2648bd2287b3b3c3801679448Svetoslav Ganov if (!mWrapSelectorWheel && y > 0 99934c0688ceafbeef2648bd2287b3b3c3801679448Svetoslav Ganov && selectorIndices[SELECTOR_MIDDLE_ITEM_INDEX] <= mMinValue) { 1000206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mCurrentScrollOffset = mInitialScrollOffset; 1001206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return; 1002206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 100334c0688ceafbeef2648bd2287b3b3c3801679448Svetoslav Ganov if (!mWrapSelectorWheel && y < 0 100434c0688ceafbeef2648bd2287b3b3c3801679448Svetoslav Ganov && selectorIndices[SELECTOR_MIDDLE_ITEM_INDEX] >= mMaxValue) { 1005206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mCurrentScrollOffset = mInitialScrollOffset; 1006206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return; 1007206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1008206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mCurrentScrollOffset += y; 1009b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov while (mCurrentScrollOffset - mInitialScrollOffset > mSelectorTextGapHeight) { 1010206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mCurrentScrollOffset -= mSelectorElementHeight; 1011206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov decrementSelectorIndices(selectorIndices); 1012d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov setValueInternal(selectorIndices[SELECTOR_MIDDLE_ITEM_INDEX], true); 1013b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov if (!mWrapSelectorWheel && selectorIndices[SELECTOR_MIDDLE_ITEM_INDEX] <= mMinValue) { 1014206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mCurrentScrollOffset = mInitialScrollOffset; 1015206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1016206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1017b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov while (mCurrentScrollOffset - mInitialScrollOffset < -mSelectorTextGapHeight) { 1018206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mCurrentScrollOffset += mSelectorElementHeight; 1019b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov incrementSelectorIndices(selectorIndices); 1020d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov setValueInternal(selectorIndices[SELECTOR_MIDDLE_ITEM_INDEX], true); 1021b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov if (!mWrapSelectorWheel && selectorIndices[SELECTOR_MIDDLE_ITEM_INDEX] >= mMaxValue) { 1022206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mCurrentScrollOffset = mInitialScrollOffset; 1023206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1024206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 10259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1026fdf6db6748b32f620a7f68b13a67c38b4e59e5edTom Taylor 10274bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov @Override 10284bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov public int getSolidColor() { 10294bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov return mSolidColor; 10304bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov } 10314bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov 103268f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook /** 10334bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * Sets the listener to be notified on change of the current value. 1034206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * 1035e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @param onValueChangedListener The listener. 103668f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook */ 1037cedc446684e94c9971c38c3206f1f224314bda2aSvetoslav Ganov public void setOnValueChangedListener(OnValueChangeListener onValueChangedListener) { 1038cedc446684e94c9971c38c3206f1f224314bda2aSvetoslav Ganov mOnValueChangeListener = onValueChangedListener; 103950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov } 104050f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 104150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov /** 10424bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * Set listener to be notified for scroll state changes. 104350f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * 1044e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @param onScrollListener The listener. 104550f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov */ 104650f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov public void setOnScrollListener(OnScrollListener onScrollListener) { 104750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov mOnScrollListener = onScrollListener; 10489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1049fdf6db6748b32f620a7f68b13a67c38b4e59e5edTom Taylor 105068f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook /** 10514bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * Set the formatter to be used for formatting the current value. 10524bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * <p> 1053e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * Note: If you have provided alternative values for the values this 1054e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * formatter is never invoked. 10554bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * </p> 1056206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * 1057e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @param formatter The formatter object. If formatter is <code>null</code>, 1058e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * {@link String#valueOf(int)} will be used. 1059d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov *@see #setDisplayedValues(String[]) 106068f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook */ 10619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void setFormatter(Formatter formatter) { 1062e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov if (formatter == mFormatter) { 1063e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov return; 1064e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov } 10659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mFormatter = formatter; 1066b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov initializeSelectorWheelIndices(); 10679cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov updateInputTextView(); 1068206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1069206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 1070206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 1071e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * Set the current value for the number picker. 10724bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * <p> 1073e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * If the argument is less than the {@link NumberPicker#getMinValue()} and 1074e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * {@link NumberPicker#getWrapSelectorWheel()} is <code>false</code> the 1075e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * current value is set to the {@link NumberPicker#getMinValue()} value. 1076e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * </p> 1077e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * <p> 1078e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * If the argument is less than the {@link NumberPicker#getMinValue()} and 1079e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * {@link NumberPicker#getWrapSelectorWheel()} is <code>true</code> the 1080e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * current value is set to the {@link NumberPicker#getMaxValue()} value. 1081e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * </p> 1082e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * <p> 1083e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * If the argument is less than the {@link NumberPicker#getMaxValue()} and 1084e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * {@link NumberPicker#getWrapSelectorWheel()} is <code>false</code> the 1085e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * current value is set to the {@link NumberPicker#getMaxValue()} value. 1086e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * </p> 1087e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * <p> 1088e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * If the argument is less than the {@link NumberPicker#getMaxValue()} and 1089e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * {@link NumberPicker#getWrapSelectorWheel()} is <code>true</code> the 1090e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * current value is set to the {@link NumberPicker#getMinValue()} value. 10914bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * </p> 1092206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * 1093e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @param value The current value. 10944bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * @see #setWrapSelectorWheel(boolean) 1095e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @see #setMinValue(int) 1096e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @see #setMaxValue(int) 1097206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 1098e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov public void setValue(int value) { 1099d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov setValueInternal(value, false); 11009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1101fdf6db6748b32f620a7f68b13a67c38b4e59e5edTom Taylor 110268f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook /** 1103d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * Shows the soft input for its input text. 1104d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov */ 1105d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private void showSoftInput() { 1106d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov InputMethodManager inputMethodManager = InputMethodManager.peekInstance(); 1107d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (inputMethodManager != null) { 1108d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (mHasSelectorWheel) { 1109d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mInputText.setVisibility(View.VISIBLE); 1110d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 1111d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mInputText.requestFocus(); 1112d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov inputMethodManager.showSoftInput(mInputText, 0); 1113d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 1114d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 1115d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 1116d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov /** 1117d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * Hides the soft input if it is active for the input text. 1118b52d9729bfb2ef7ad50d9a5125ebf3a8322429a9Svetoslav Ganov */ 1119b52d9729bfb2ef7ad50d9a5125ebf3a8322429a9Svetoslav Ganov private void hideSoftInput() { 1120b52d9729bfb2ef7ad50d9a5125ebf3a8322429a9Svetoslav Ganov InputMethodManager inputMethodManager = InputMethodManager.peekInstance(); 1121b52d9729bfb2ef7ad50d9a5125ebf3a8322429a9Svetoslav Ganov if (inputMethodManager != null && inputMethodManager.isActive(mInputText)) { 1122b52d9729bfb2ef7ad50d9a5125ebf3a8322429a9Svetoslav Ganov inputMethodManager.hideSoftInputFromWindow(getWindowToken(), 0); 1123d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (mHasSelectorWheel) { 1124d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mInputText.setVisibility(View.INVISIBLE); 1125d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 1126b52d9729bfb2ef7ad50d9a5125ebf3a8322429a9Svetoslav Ganov } 1127b52d9729bfb2ef7ad50d9a5125ebf3a8322429a9Svetoslav Ganov } 1128b52d9729bfb2ef7ad50d9a5125ebf3a8322429a9Svetoslav Ganov 1129b52d9729bfb2ef7ad50d9a5125ebf3a8322429a9Svetoslav Ganov /** 1130ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov * Computes the max width if no such specified as an attribute. 1131ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov */ 1132ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov private void tryComputeMaxWidth() { 1133ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov if (!mComputeMaxWidth) { 1134ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov return; 1135ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov } 1136ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov int maxTextWidth = 0; 1137ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov if (mDisplayedValues == null) { 1138ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov float maxDigitWidth = 0; 1139ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov for (int i = 0; i <= 9; i++) { 1140ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov final float digitWidth = mSelectorWheelPaint.measureText(String.valueOf(i)); 1141ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov if (digitWidth > maxDigitWidth) { 1142ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov maxDigitWidth = digitWidth; 1143ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov } 1144ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov } 1145ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov int numberOfDigits = 0; 1146ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov int current = mMaxValue; 1147ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov while (current > 0) { 1148ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov numberOfDigits++; 1149ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov current = current / 10; 1150ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov } 1151ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov maxTextWidth = (int) (numberOfDigits * maxDigitWidth); 1152ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov } else { 1153ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov final int valueCount = mDisplayedValues.length; 1154ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov for (int i = 0; i < valueCount; i++) { 1155ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov final float textWidth = mSelectorWheelPaint.measureText(mDisplayedValues[i]); 1156ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov if (textWidth > maxTextWidth) { 1157ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov maxTextWidth = (int) textWidth; 1158ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov } 1159ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov } 1160ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov } 1161ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov maxTextWidth += mInputText.getPaddingLeft() + mInputText.getPaddingRight(); 1162ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov if (mMaxWidth != maxTextWidth) { 1163ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov if (maxTextWidth > mMinWidth) { 1164ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov mMaxWidth = maxTextWidth; 1165ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov } else { 1166ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov mMaxWidth = mMinWidth; 1167ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov } 1168ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov invalidate(); 1169ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov } 1170ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov } 1171ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov 1172ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov /** 1173e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * Gets whether the selector wheel wraps when reaching the min/max value. 117468f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook * 1175e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @return True if the selector wheel wraps. 11764bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * 1177e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @see #getMinValue() 1178e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @see #getMaxValue() 117968f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook */ 1180e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov public boolean getWrapSelectorWheel() { 1181e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov return mWrapSelectorWheel; 1182206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1183206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 1184206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 1185e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * Sets whether the selector wheel shown during flinging/scrolling should 1186e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * wrap around the {@link NumberPicker#getMinValue()} and 1187e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * {@link NumberPicker#getMaxValue()} values. 1188e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * <p> 1189d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * By default if the range (max - min) is more than the number of items shown 1190d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * on the selector wheel the selector wheel wrapping is enabled. 1191e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * </p> 11923f9c9eab7b41c409c3c7b503b89ad340e408b6a0Svetoslav Ganov * <p> 1193d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * <strong>Note:</strong> If the number of items, i.e. the range ( 1194d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * {@link #getMaxValue()} - {@link #getMinValue()}) is less than 1195d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * the number of items shown on the selector wheel, the selector wheel will 1196d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * not wrap. Hence, in such a case calling this method is a NOP. 11973f9c9eab7b41c409c3c7b503b89ad340e408b6a0Svetoslav Ganov * </p> 1198d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * 11996304b0d58e74509a9f21b67b5227b2fee2f1b60fSvetoslav Ganov * @param wrapSelectorWheel Whether to wrap. 1200206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 12016304b0d58e74509a9f21b67b5227b2fee2f1b60fSvetoslav Ganov public void setWrapSelectorWheel(boolean wrapSelectorWheel) { 12023f9c9eab7b41c409c3c7b503b89ad340e408b6a0Svetoslav Ganov final boolean wrappingAllowed = (mMaxValue - mMinValue) >= mSelectorIndices.length; 12033f9c9eab7b41c409c3c7b503b89ad340e408b6a0Svetoslav Ganov if ((!wrapSelectorWheel || wrappingAllowed) && wrapSelectorWheel != mWrapSelectorWheel) { 12046304b0d58e74509a9f21b67b5227b2fee2f1b60fSvetoslav Ganov mWrapSelectorWheel = wrapSelectorWheel; 1205206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 12069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 12094bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * Sets the speed at which the numbers be incremented and decremented when 12104bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * the up and down buttons are long pressed respectively. 1211e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * <p> 1212e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * The default value is 300 ms. 1213e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * </p> 121468f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook * 12154bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * @param intervalMillis The speed (in milliseconds) at which the numbers 1216e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * will be incremented and decremented. 12179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 12184bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov public void setOnLongPressUpdateInterval(long intervalMillis) { 12194bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov mLongPressUpdateInterval = intervalMillis; 12209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1221fdf6db6748b32f620a7f68b13a67c38b4e59e5edTom Taylor 1222206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 1223e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * Returns the value of the picker. 1224e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * 1225e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @return The value. 1226e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov */ 1227e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov public int getValue() { 1228e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov return mValue; 1229e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov } 1230e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov 1231e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov /** 1232e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * Returns the min value of the picker. 1233e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * 1234e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @return The min value 1235e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov */ 1236e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov public int getMinValue() { 1237e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov return mMinValue; 1238e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov } 1239e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov 1240e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov /** 1241e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * Sets the min value of the picker. 1242206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * 1243e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @param minValue The min value. 1244206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 1245e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov public void setMinValue(int minValue) { 1246e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov if (mMinValue == minValue) { 1247e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov return; 1248e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov } 1249e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov if (minValue < 0) { 1250e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov throw new IllegalArgumentException("minValue must be >= 0"); 1251e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov } 1252e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov mMinValue = minValue; 1253e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov if (mMinValue > mValue) { 1254e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov mValue = mMinValue; 1255e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov } 1256e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov boolean wrapSelectorWheel = mMaxValue - mMinValue > mSelectorIndices.length; 1257e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov setWrapSelectorWheel(wrapSelectorWheel); 1258b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov initializeSelectorWheelIndices(); 1259e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov updateInputTextView(); 1260ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov tryComputeMaxWidth(); 1261d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov invalidate(); 1262206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1263206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 12644bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov /** 1265e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * Returns the max value of the picker. 12664bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * 1267e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @return The max value. 12684bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov */ 1269e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov public int getMaxValue() { 1270e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov return mMaxValue; 12714bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov } 12724bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov 12734bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov /** 1274e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * Sets the max value of the picker. 12754bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * 1276e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @param maxValue The max value. 12774bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov */ 1278e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov public void setMaxValue(int maxValue) { 1279e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov if (mMaxValue == maxValue) { 1280e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov return; 1281e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov } 1282e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov if (maxValue < 0) { 1283e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov throw new IllegalArgumentException("maxValue must be >= 0"); 1284e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov } 1285e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov mMaxValue = maxValue; 1286e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov if (mMaxValue < mValue) { 1287e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov mValue = mMaxValue; 1288e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov } 1289e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov boolean wrapSelectorWheel = mMaxValue - mMinValue > mSelectorIndices.length; 1290e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov setWrapSelectorWheel(wrapSelectorWheel); 1291b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov initializeSelectorWheelIndices(); 1292e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov updateInputTextView(); 1293ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov tryComputeMaxWidth(); 1294d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov invalidate(); 1295e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov } 1296e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov 1297e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov /** 1298e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * Gets the values to be displayed instead of string values. 1299e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * 1300e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @return The displayed values. 1301e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov */ 1302e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov public String[] getDisplayedValues() { 1303e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov return mDisplayedValues; 1304e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov } 1305e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov 1306e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov /** 1307e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * Sets the values to be displayed. 1308e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * 1309e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @param displayedValues The displayed values. 1310e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov */ 1311e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov public void setDisplayedValues(String[] displayedValues) { 1312e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov if (mDisplayedValues == displayedValues) { 1313e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov return; 1314e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov } 1315e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov mDisplayedValues = displayedValues; 1316e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov if (mDisplayedValues != null) { 1317e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov // Allow text entry rather than strictly numeric entry. 1318e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov mInputText.setRawInputType(InputType.TYPE_CLASS_TEXT 1319e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov | InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS); 1320e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov } else { 1321e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov mInputText.setRawInputType(InputType.TYPE_CLASS_NUMBER); 1322e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov } 1323e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov updateInputTextView(); 1324b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov initializeSelectorWheelIndices(); 13259f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov tryComputeMaxWidth(); 1326206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1327206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 1328206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov @Override 1329206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov protected float getTopFadingEdgeStrength() { 1330206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return TOP_AND_BOTTOM_FADING_EDGE_STRENGTH; 1331206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1332206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 1333206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov @Override 1334206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov protected float getBottomFadingEdgeStrength() { 1335206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return TOP_AND_BOTTOM_FADING_EDGE_STRENGTH; 1336206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1337206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 1338206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov @Override 1339206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov protected void onDetachedFromWindow() { 1340206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov removeAllCallbacks(); 1341206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1342206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 1343206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov @Override 1344206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov protected void onDraw(Canvas canvas) { 1345d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (!mHasSelectorWheel) { 1346d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov super.onDraw(canvas); 1347206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return; 1348206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1349206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov float x = (mRight - mLeft) / 2; 1350206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov float y = mCurrentScrollOffset; 1351206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 13529cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov // draw the selector wheel 1353b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov int[] selectorIndices = mSelectorIndices; 1354206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov for (int i = 0; i < selectorIndices.length; i++) { 1355206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov int selectorIndex = selectorIndices[i]; 1356206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov String scrollSelectorValue = mSelectorIndexToStringCache.get(selectorIndex); 1357d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov // Do not draw the middle item if input is visible since the input 1358d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov // is shown only if the wheel is static and it covers the middle 1359d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov // item. Otherwise, if the user starts editing the text via the 1360d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov // IME he may see a dimmed version of the old value intermixed 1361d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov // with the new one. 13626304b0d58e74509a9f21b67b5227b2fee2f1b60fSvetoslav Ganov if (i != SELECTOR_MIDDLE_ITEM_INDEX || mInputText.getVisibility() != VISIBLE) { 13636304b0d58e74509a9f21b67b5227b2fee2f1b60fSvetoslav Ganov canvas.drawText(scrollSelectorValue, x, y, mSelectorWheelPaint); 13646304b0d58e74509a9f21b67b5227b2fee2f1b60fSvetoslav Ganov } 1365206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov y += mSelectorElementHeight; 1366206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 13679cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov 1368d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov // draw the selection dividers 13699cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov if (mSelectionDivider != null) { 13709cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov // draw the top divider 1371d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov int topOfTopDivider = mTopSelectionDividerTop; 13729cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov int bottomOfTopDivider = topOfTopDivider + mSelectionDividerHeight; 13739cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov mSelectionDivider.setBounds(0, topOfTopDivider, mRight, bottomOfTopDivider); 13749cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov mSelectionDivider.draw(canvas); 13759cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov 13769cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov // draw the bottom divider 1377d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov int bottomOfBottomDivider = mBottomSelectionDividerBottom; 1378d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov int topOfBottomDivider = bottomOfBottomDivider - mSelectionDividerHeight; 13799cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov mSelectionDivider.setBounds(0, topOfBottomDivider, mRight, bottomOfBottomDivider); 13809cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov mSelectionDivider.draw(canvas); 13819cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov } 13829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1383fdf6db6748b32f620a7f68b13a67c38b4e59e5edTom Taylor 13843fec3fe0e3a83c5e0d1264f34bcc55b158537bc6Svetoslav Ganov @Override 13853fec3fe0e3a83c5e0d1264f34bcc55b158537bc6Svetoslav Ganov public void sendAccessibilityEvent(int eventType) { 13863fec3fe0e3a83c5e0d1264f34bcc55b158537bc6Svetoslav Ganov // Do not send accessibility events - we want the user to 13873fec3fe0e3a83c5e0d1264f34bcc55b158537bc6Svetoslav Ganov // perceive this widget as several controls rather as a whole. 13883fec3fe0e3a83c5e0d1264f34bcc55b158537bc6Svetoslav Ganov } 13893fec3fe0e3a83c5e0d1264f34bcc55b158537bc6Svetoslav Ganov 13908a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov @Override 13918a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov public void onInitializeAccessibilityEvent(AccessibilityEvent event) { 13928a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov super.onInitializeAccessibilityEvent(event); 13938a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov event.setClassName(NumberPicker.class.getName()); 1394d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov event.setScrollable(true); 1395d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov event.setScrollY((mMinValue + mValue) * mSelectorElementHeight); 1396d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov event.setMaxScrollY((mMaxValue - mMinValue) * mSelectorElementHeight); 13978a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov } 13988a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov 13998a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov @Override 1400d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov public AccessibilityNodeProvider getAccessibilityNodeProvider() { 1401d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (!mHasSelectorWheel) { 1402d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return super.getAccessibilityNodeProvider(); 1403d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 1404d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (mAccessibilityNodeProvider == null) { 1405d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mAccessibilityNodeProvider = new AccessibilityNodeProviderImpl(); 1406d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 1407d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return mAccessibilityNodeProvider; 14088a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov } 14098a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov 141068f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook /** 1411ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov * Makes a measure spec that tries greedily to use the max value. 1412e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov * 1413e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov * @param measureSpec The measure spec. 1414698e1d5d867a7ac653fa1d6f29cef4cfb73fad38Svetoslav Ganov * @param maxSize The max value for the size. 1415ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov * @return A measure spec greedily imposing the max size. 1416e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov */ 1417698e1d5d867a7ac653fa1d6f29cef4cfb73fad38Svetoslav Ganov private int makeMeasureSpec(int measureSpec, int maxSize) { 14189f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov if (maxSize == SIZE_UNSPECIFIED) { 14199f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov return measureSpec; 14209f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov } 1421ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov final int size = MeasureSpec.getSize(measureSpec); 1422e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov final int mode = MeasureSpec.getMode(measureSpec); 1423e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov switch (mode) { 1424e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov case MeasureSpec.EXACTLY: 1425ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov return measureSpec; 1426e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov case MeasureSpec.AT_MOST: 1427698e1d5d867a7ac653fa1d6f29cef4cfb73fad38Svetoslav Ganov return MeasureSpec.makeMeasureSpec(Math.min(size, maxSize), MeasureSpec.EXACTLY); 1428e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov case MeasureSpec.UNSPECIFIED: 1429698e1d5d867a7ac653fa1d6f29cef4cfb73fad38Svetoslav Ganov return MeasureSpec.makeMeasureSpec(maxSize, MeasureSpec.EXACTLY); 1430e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov default: 1431ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov throw new IllegalArgumentException("Unknown measure mode: " + mode); 1432e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov } 1433e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov } 1434e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov 1435e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov /** 1436d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * Utility to reconcile a desired size and state, with constraints imposed 1437d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * by a MeasureSpec. Tries to respect the min size, unless a different size 1438d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * is imposed by the constraints. 14399f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov * 14409f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov * @param minSize The minimal desired size. 14419f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov * @param measuredSize The currently measured size. 14429f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov * @param measureSpec The current measure spec. 14439f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov * @return The resolved size and state. 14449f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov */ 1445d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private int resolveSizeAndStateRespectingMinSize( 1446d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov int minSize, int measuredSize, int measureSpec) { 14479f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov if (minSize != SIZE_UNSPECIFIED) { 14489f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov final int desiredWidth = Math.max(minSize, measuredSize); 14499f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov return resolveSizeAndState(desiredWidth, measureSpec, 0); 14509f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov } else { 14519f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov return measuredSize; 14529f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov } 14539f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov } 14549f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov 14559f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov /** 1456d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * Resets the selector indices and clear the cached string representation of 1457d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * these indices. 1458a911d4a2b1be7e9ea909a579167826e4a5bac1a3Svetoslav Ganov */ 1459b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov private void initializeSelectorWheelIndices() { 1460a911d4a2b1be7e9ea909a579167826e4a5bac1a3Svetoslav Ganov mSelectorIndexToStringCache.clear(); 1461b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov int[] selectorIdices = mSelectorIndices; 1462b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov int current = getValue(); 1463b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov for (int i = 0; i < mSelectorIndices.length; i++) { 1464b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov int selectorIndex = current + (i - SELECTOR_MIDDLE_ITEM_INDEX); 1465b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov if (mWrapSelectorWheel) { 1466b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov selectorIndex = getWrappedSelectorIndex(selectorIndex); 1467b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov } 1468b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov mSelectorIndices[i] = selectorIndex; 1469b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov ensureCachedScrollSelectorValue(mSelectorIndices[i]); 1470a911d4a2b1be7e9ea909a579167826e4a5bac1a3Svetoslav Ganov } 1471a911d4a2b1be7e9ea909a579167826e4a5bac1a3Svetoslav Ganov } 1472a911d4a2b1be7e9ea909a579167826e4a5bac1a3Svetoslav Ganov 1473a911d4a2b1be7e9ea909a579167826e4a5bac1a3Svetoslav Ganov /** 1474d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * Sets the current value of this NumberPicker. 147568f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook * 1476d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * @param current The new value of the NumberPicker. 1477d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * @param notifyChange Whether to notify if the current value changed. 147868f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook */ 1479d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private void setValueInternal(int current, boolean notifyChange) { 1480e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov if (mValue == current) { 1481206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return; 1482206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 14839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Wrap around the values if we go past the start or end 1484e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov if (mWrapSelectorWheel) { 1485206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov current = getWrappedSelectorIndex(current); 1486d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } else { 1487d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov current = Math.max(current, mMinValue); 1488d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov current = Math.min(current, mMaxValue); 14899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1490e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov int previous = mValue; 1491d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mValue = current; 1492d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov updateInputTextView(); 1493d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (notifyChange) { 1494d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov notifyChange(previous, current); 1495d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 1496fac14f9731ce7fc765de582c983af751aab697deSvetoslav Ganov initializeSelectorWheelIndices(); 1497fac14f9731ce7fc765de582c983af751aab697deSvetoslav Ganov invalidate(); 14989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1499fdf6db6748b32f620a7f68b13a67c38b4e59e5edTom Taylor 150068f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook /** 1501b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov * Changes the current value by one which is increment or 1502b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov * decrement based on the passes argument. 1503d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * decrement the current value. 1504b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov * 1505b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov * @param increment True to increment, false to decrement. 1506b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov */ 1507d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private void changeValueByOne(boolean increment) { 1508d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (mHasSelectorWheel) { 1509b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov mInputText.setVisibility(View.INVISIBLE); 1510d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (!moveToFinalScrollerPosition(mFlingScroller)) { 1511d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov moveToFinalScrollerPosition(mAdjustScroller); 1512d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 1513b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov mPreviousScrollerY = 0; 1514b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov if (increment) { 1515fe41ce4ef97e7da585fdbf06988da8047e72b9f6Svetoslav Ganov mFlingScroller.startScroll(0, 0, 0, -mSelectorElementHeight, SNAP_SCROLL_DURATION); 1516b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov } else { 1517fe41ce4ef97e7da585fdbf06988da8047e72b9f6Svetoslav Ganov mFlingScroller.startScroll(0, 0, 0, mSelectorElementHeight, SNAP_SCROLL_DURATION); 1518b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov } 1519b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov invalidate(); 1520b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov } else { 1521b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov if (increment) { 1522d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov setValueInternal(mValue + 1, true); 1523b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov } else { 1524d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov setValueInternal(mValue - 1, true); 1525b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov } 1526b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov } 1527b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov } 1528b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov 1529b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov private void initializeSelectorWheel() { 1530b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov initializeSelectorWheelIndices(); 1531b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov int[] selectorIndices = mSelectorIndices; 15329cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov int totalTextHeight = selectorIndices.length * mTextSize; 153301fa0d7aae1a551e1e7cfb90d2aeaf2fcb3978afSvetoslav Ganov float totalTextGapHeight = (mBottom - mTop) - totalTextHeight; 1534d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov float textGapCount = selectorIndices.length; 1535b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov mSelectorTextGapHeight = (int) (totalTextGapHeight / textGapCount + 0.5f); 1536b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov mSelectorElementHeight = mTextSize + mSelectorTextGapHeight; 1537d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov // Ensure that the middle item is positioned the same as the text in 1538d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov // mInputText 1539eeafd4296b7cf4c2ad9c985562f6d70e2a3ffc03Chet Haase int editTextTextPosition = mInputText.getBaseline() + mInputText.getTop(); 1540d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mInitialScrollOffset = editTextTextPosition 1541d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov - (mSelectorElementHeight * SELECTOR_MIDDLE_ITEM_INDEX); 15426a19fcde07527706c2a9175e0b9f2a71549b7ffeSvetoslav Ganov mCurrentScrollOffset = mInitialScrollOffset; 15439cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov updateInputTextView(); 15449cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov } 15459cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov 1546b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov private void initializeFadingEdges() { 1547b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov setVerticalFadingEdgeEnabled(true); 1548b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov setFadingEdgeLength((mBottom - mTop - mTextSize) / 2); 1549b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov } 1550b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov 1551206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 1552206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Callback invoked upon completion of a given <code>scroller</code>. 1553206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 1554206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private void onScrollerFinished(Scroller scroller) { 1555206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (scroller == mFlingScroller) { 1556d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (!ensureScrollWheelAdjusted()) { 1557b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov updateInputTextView(); 1558b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov } 1559d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov onScrollStateChange(OnScrollListener.SCROLL_STATE_IDLE); 15609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 1561d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (mScrollState != OnScrollListener.SCROLL_STATE_TOUCH_SCROLL) { 1562d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov updateInputTextView(); 1563d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 15649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1566fdf6db6748b32f620a7f68b13a67c38b4e59e5edTom Taylor 1567206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 15689cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov * Handles transition to a given <code>scrollState</code> 156950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov */ 15709cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov private void onScrollStateChange(int scrollState) { 15719cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov if (mScrollState == scrollState) { 15729cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov return; 15739cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov } 15749cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov mScrollState = scrollState; 15759cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov if (mOnScrollListener != null) { 15764bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov mOnScrollListener.onScrollStateChange(this, scrollState); 157750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov } 157850f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov } 157950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 158050f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov /** 1581206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Flings the selector with the given <code>velocityY</code>. 1582206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 1583206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private void fling(int velocityY) { 1584206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mPreviousScrollerY = 0; 1585206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 1586234484a9fb53786aa8b7ed2a3df7e24d41817689Svetoslav Ganov if (velocityY > 0) { 1587234484a9fb53786aa8b7ed2a3df7e24d41817689Svetoslav Ganov mFlingScroller.fling(0, 0, 0, velocityY, 0, 0, 0, Integer.MAX_VALUE); 1588206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } else { 1589234484a9fb53786aa8b7ed2a3df7e24d41817689Svetoslav Ganov mFlingScroller.fling(0, Integer.MAX_VALUE, 0, velocityY, 0, 0, 0, Integer.MAX_VALUE); 15909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1591206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 1592206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov invalidate(); 15939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1595206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 1596206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * @return The wrapped index <code>selectorIndex</code> value. 159768f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook */ 1598206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private int getWrappedSelectorIndex(int selectorIndex) { 1599e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov if (selectorIndex > mMaxValue) { 1600e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov return mMinValue + (selectorIndex - mMaxValue) % (mMaxValue - mMinValue) - 1; 1601e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov } else if (selectorIndex < mMinValue) { 1602e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov return mMaxValue - (mMinValue - selectorIndex) % (mMaxValue - mMinValue) + 1; 1603206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1604206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return selectorIndex; 16059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1606fdf6db6748b32f620a7f68b13a67c38b4e59e5edTom Taylor 1607206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 1608206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Increments the <code>selectorIndices</code> whose string representations 1609206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * will be displayed in the selector. 1610206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 1611b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov private void incrementSelectorIndices(int[] selectorIndices) { 1612206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov for (int i = 0; i < selectorIndices.length - 1; i++) { 1613206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov selectorIndices[i] = selectorIndices[i + 1]; 1614206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1615206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov int nextScrollSelectorIndex = selectorIndices[selectorIndices.length - 2] + 1; 1616e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov if (mWrapSelectorWheel && nextScrollSelectorIndex > mMaxValue) { 1617e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov nextScrollSelectorIndex = mMinValue; 1618206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1619206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov selectorIndices[selectorIndices.length - 1] = nextScrollSelectorIndex; 1620206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov ensureCachedScrollSelectorValue(nextScrollSelectorIndex); 1621206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1622fdf6db6748b32f620a7f68b13a67c38b4e59e5edTom Taylor 1623206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 1624206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Decrements the <code>selectorIndices</code> whose string representations 1625206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * will be displayed in the selector. 1626206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 1627206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private void decrementSelectorIndices(int[] selectorIndices) { 1628206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov for (int i = selectorIndices.length - 1; i > 0; i--) { 1629206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov selectorIndices[i] = selectorIndices[i - 1]; 1630206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1631206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov int nextScrollSelectorIndex = selectorIndices[1] - 1; 1632e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov if (mWrapSelectorWheel && nextScrollSelectorIndex < mMinValue) { 1633e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov nextScrollSelectorIndex = mMaxValue; 1634206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1635206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov selectorIndices[0] = nextScrollSelectorIndex; 1636206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov ensureCachedScrollSelectorValue(nextScrollSelectorIndex); 1637206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1638fdf6db6748b32f620a7f68b13a67c38b4e59e5edTom Taylor 1639206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 1640206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Ensures we have a cached string representation of the given <code> 1641d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * selectorIndex</code> to avoid multiple instantiations of the same string. 1642206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 1643206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private void ensureCachedScrollSelectorValue(int selectorIndex) { 1644206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov SparseArray<String> cache = mSelectorIndexToStringCache; 1645206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov String scrollSelectorValue = cache.get(selectorIndex); 1646206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (scrollSelectorValue != null) { 1647206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return; 1648206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1649e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov if (selectorIndex < mMinValue || selectorIndex > mMaxValue) { 1650206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov scrollSelectorValue = ""; 1651206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } else { 1652206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (mDisplayedValues != null) { 1653e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov int displayedValueIndex = selectorIndex - mMinValue; 165450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov scrollSelectorValue = mDisplayedValues[displayedValueIndex]; 1655206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } else { 1656206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov scrollSelectorValue = formatNumber(selectorIndex); 16579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1659206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov cache.put(selectorIndex, scrollSelectorValue); 16609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1661fdf6db6748b32f620a7f68b13a67c38b4e59e5edTom Taylor 1662206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private String formatNumber(int value) { 1663e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov return (mFormatter != null) ? mFormatter.format(value) : String.valueOf(value); 1664206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 16659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1666206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private void validateInputTextView(View v) { 1667206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov String str = String.valueOf(((TextView) v).getText()); 1668206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (TextUtils.isEmpty(str)) { 1669206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // Restore to the old value as we don't allow empty values 1670206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov updateInputTextView(); 1671206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } else { 1672206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // Check the new value and ensure it's in range 1673206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov int current = getSelectedPos(str.toString()); 1674d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov setValueInternal(current, true); 16759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1676206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1677fdf6db6748b32f620a7f68b13a67c38b4e59e5edTom Taylor 1678206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 1679206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Updates the view of this NumberPicker. If displayValues were specified in 16809cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov * the string corresponding to the index specified by the current value will 16819cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov * be returned. Otherwise, the formatter specified in {@link #setFormatter} 16829cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov * will be used to format the number. 1683d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * 1684d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * @return Whether the text was updated. 1685206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 1686d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private boolean updateInputTextView() { 1687206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /* 1688206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * If we don't have displayed values then use the current number else 1689206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * find the correct value in the displayed values for the current 1690206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * number. 1691206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 1692d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov String text = (mDisplayedValues == null) ? formatNumber(mValue) 1693d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov : mDisplayedValues[mValue - mMinValue]; 1694d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (!TextUtils.isEmpty(text) && !text.equals(mInputText.getText().toString())) { 1695d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mInputText.setText(text); 1696d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return true; 16979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16983fec3fe0e3a83c5e0d1264f34bcc55b158537bc6Svetoslav Ganov 1699d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return false; 1700206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1701fdf6db6748b32f620a7f68b13a67c38b4e59e5edTom Taylor 1702206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 1703206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Notifies the listener, if registered, of a change of the value of this 1704206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * NumberPicker. 1705206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 1706206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private void notifyChange(int previous, int current) { 1707cedc446684e94c9971c38c3206f1f224314bda2aSvetoslav Ganov if (mOnValueChangeListener != null) { 1708cedc446684e94c9971c38c3206f1f224314bda2aSvetoslav Ganov mOnValueChangeListener.onValueChange(this, previous, mValue); 1709206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1710206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 17119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1712206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 1713b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov * Posts a command for changing the current value by one. 1714b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov * 1715b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov * @param increment Whether to increment or decrement the value. 1716206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 1717d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private void postChangeCurrentByOneFromLongPress(boolean increment, long delayMillis) { 1718b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov if (mChangeCurrentByOneFromLongPressCommand == null) { 1719b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov mChangeCurrentByOneFromLongPressCommand = new ChangeCurrentByOneFromLongPressCommand(); 1720d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } else { 1721d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov removeCallbacks(mChangeCurrentByOneFromLongPressCommand); 1722d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 1723d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mChangeCurrentByOneFromLongPressCommand.setStep(increment); 1724d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov postDelayed(mChangeCurrentByOneFromLongPressCommand, delayMillis); 1725d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 1726d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 1727d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov /** 1728d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * Removes the command for changing the current value by one. 1729d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov */ 1730d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private void removeChangeCurrentByOneFromLongPress() { 1731d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (mChangeCurrentByOneFromLongPressCommand != null) { 1732d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov removeCallbacks(mChangeCurrentByOneFromLongPressCommand); 1733d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 1734d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 1735d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 1736d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov /** 1737d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * Posts a command for beginning an edit of the current value via IME on 1738d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * long press. 1739d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov */ 1740d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private void postBeginSoftInputOnLongPressCommand() { 1741d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (mBeginSoftInputOnLongPressCommand == null) { 1742d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mBeginSoftInputOnLongPressCommand = new BeginSoftInputOnLongPressCommand(); 1743d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } else { 1744d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov removeCallbacks(mBeginSoftInputOnLongPressCommand); 1745d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 1746d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov postDelayed(mBeginSoftInputOnLongPressCommand, ViewConfiguration.getLongPressTimeout()); 1747d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 1748d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 1749d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov /** 1750d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * Removes the command for beginning an edit of the current value via IME. 1751d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov */ 1752d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private void removeBeginSoftInputCommand() { 1753d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (mBeginSoftInputOnLongPressCommand != null) { 1754d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov removeCallbacks(mBeginSoftInputOnLongPressCommand); 1755206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1756206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 17579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1758206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 1759206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Removes all pending callback from the message queue. 1760206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 1761206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private void removeAllCallbacks() { 1762b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov if (mChangeCurrentByOneFromLongPressCommand != null) { 1763b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov removeCallbacks(mChangeCurrentByOneFromLongPressCommand); 1764206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1765206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (mSetSelectionCommand != null) { 1766206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov removeCallbacks(mSetSelectionCommand); 17679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1768d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (mBeginSoftInputOnLongPressCommand != null) { 1769d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov removeCallbacks(mBeginSoftInputOnLongPressCommand); 1770d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 17719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 17729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1773206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 1774206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * @return The selected index given its displayed <code>value</code>. 1775206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 1776206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private int getSelectedPos(String value) { 17779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mDisplayedValues == null) { 1778aa516beb79693ceffbd81a7c9d14c940e412cccbRomain Guy try { 1779206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return Integer.parseInt(value); 1780aa516beb79693ceffbd81a7c9d14c940e412cccbRomain Guy } catch (NumberFormatException e) { 1781206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // Ignore as if it's not a number we don't care 1782aa516beb79693ceffbd81a7c9d14c940e412cccbRomain Guy } 17839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 17849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < mDisplayedValues.length; i++) { 1785206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // Don't force the user to type in jan when ja will do 1786206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov value = value.toLowerCase(); 1787206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (mDisplayedValues[i].toLowerCase().startsWith(value)) { 1788e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov return mMinValue + i; 17899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 17909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1791fdf6db6748b32f620a7f68b13a67c38b4e59e5edTom Taylor 1792206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /* 1793206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * The user might have typed in a number into the month field i.e. 17949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 10 instead of OCT so support that too. 17959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 17969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 1797206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return Integer.parseInt(value); 17989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (NumberFormatException e) { 1799fdf6db6748b32f620a7f68b13a67c38b4e59e5edTom Taylor 1800206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // Ignore as if it's not a number we don't care 18019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 18029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1803e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov return mMinValue; 18049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 18059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 18069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1807206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Posts an {@link SetSelectionCommand} from the given <code>selectionStart 1808d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * </code> to <code>selectionEnd</code>. 18099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1810206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private void postSetSelectionCommand(int selectionStart, int selectionEnd) { 1811206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (mSetSelectionCommand == null) { 1812206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mSetSelectionCommand = new SetSelectionCommand(); 1813206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } else { 1814206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov removeCallbacks(mSetSelectionCommand); 1815206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1816206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mSetSelectionCommand.mSelectionStart = selectionStart; 1817206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mSetSelectionCommand.mSelectionEnd = selectionEnd; 1818206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov post(mSetSelectionCommand); 18199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 182068f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook 182168f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook /** 1822206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Filter for accepting only valid indices or prefixes of the string 1823206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * representation of valid indices. 182468f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook */ 1825206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov class InputTextFilter extends NumberKeyListener { 1826206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 1827206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // XXX This doesn't allow for range limits when controlled by a 1828206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // soft input method! 1829206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov public int getInputType() { 1830206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return InputType.TYPE_CLASS_TEXT; 1831206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1832206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 1833206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov @Override 1834206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov protected char[] getAcceptedChars() { 1835206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return DIGIT_CHARACTERS; 1836206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1837206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 1838206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov @Override 1839d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov public CharSequence filter( 1840d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov CharSequence source, int start, int end, Spanned dest, int dstart, int dend) { 1841206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (mDisplayedValues == null) { 1842206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov CharSequence filtered = super.filter(source, start, end, dest, dstart, dend); 1843206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (filtered == null) { 1844206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov filtered = source.subSequence(start, end); 1845206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1846206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 1847206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov String result = String.valueOf(dest.subSequence(0, dstart)) + filtered 1848206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov + dest.subSequence(dend, dest.length()); 1849206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 1850206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if ("".equals(result)) { 1851206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return result; 1852206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1853206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov int val = getSelectedPos(result); 1854206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 1855206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /* 1856206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Ensure the user can't type in a value greater than the max 1857206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * allowed. We have to allow less than min as the user might 1858206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * want to delete some numbers and then type a new number. 1859206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 1860e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov if (val > mMaxValue) { 1861206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return ""; 1862206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } else { 1863206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return filtered; 1864206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1865206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } else { 1866206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov CharSequence filtered = String.valueOf(source.subSequence(start, end)); 1867206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (TextUtils.isEmpty(filtered)) { 1868206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return ""; 1869206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1870206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov String result = String.valueOf(dest.subSequence(0, dstart)) + filtered 1871206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov + dest.subSequence(dend, dest.length()); 1872206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov String str = String.valueOf(result).toLowerCase(); 1873206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov for (String val : mDisplayedValues) { 1874206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov String valLowerCase = val.toLowerCase(); 1875206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (valLowerCase.startsWith(str)) { 1876206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov postSetSelectionCommand(result.length(), val.length()); 1877206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return val.subSequence(dstart, val.length()); 1878206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1879206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1880206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return ""; 1881206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1882206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1883206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1884206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 1885206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 1886d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * Ensures that the scroll wheel is adjusted i.e. there is no offset and the 1887d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * middle element is in the middle of the widget. 1888d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * 1889d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * @return Whether an adjustment has been made. 1890d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov */ 1891d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private boolean ensureScrollWheelAdjusted() { 1892d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov // adjust to the closest value 1893d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov int deltaY = mInitialScrollOffset - mCurrentScrollOffset; 1894d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (deltaY != 0) { 1895d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mPreviousScrollerY = 0; 1896d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (Math.abs(deltaY) > mSelectorElementHeight / 2) { 1897d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov deltaY += (deltaY > 0) ? -mSelectorElementHeight : mSelectorElementHeight; 1898d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 1899d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mAdjustScroller.startScroll(0, 0, 0, deltaY, SELECTOR_ADJUSTMENT_DURATION_MILLIS); 1900d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov invalidate(); 1901d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return true; 1902d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 1903d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return false; 1904d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 1905d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 1906fe41ce4ef97e7da585fdbf06988da8047e72b9f6Svetoslav Ganov private void snapToNextValue(boolean increment) { 1907fe41ce4ef97e7da585fdbf06988da8047e72b9f6Svetoslav Ganov int deltaY = mCurrentScrollOffset - mInitialScrollOffset; 1908fe41ce4ef97e7da585fdbf06988da8047e72b9f6Svetoslav Ganov int amountToScroll = 0; 1909fe41ce4ef97e7da585fdbf06988da8047e72b9f6Svetoslav Ganov if (deltaY != 0) { 1910fe41ce4ef97e7da585fdbf06988da8047e72b9f6Svetoslav Ganov mPreviousScrollerY = 0; 1911fe41ce4ef97e7da585fdbf06988da8047e72b9f6Svetoslav Ganov if (deltaY > 0) { 1912fe41ce4ef97e7da585fdbf06988da8047e72b9f6Svetoslav Ganov if (increment) { 1913fe41ce4ef97e7da585fdbf06988da8047e72b9f6Svetoslav Ganov amountToScroll = - deltaY; 1914fe41ce4ef97e7da585fdbf06988da8047e72b9f6Svetoslav Ganov } else { 1915fe41ce4ef97e7da585fdbf06988da8047e72b9f6Svetoslav Ganov amountToScroll = mSelectorElementHeight - deltaY; 1916fe41ce4ef97e7da585fdbf06988da8047e72b9f6Svetoslav Ganov } 1917fe41ce4ef97e7da585fdbf06988da8047e72b9f6Svetoslav Ganov } else { 1918fe41ce4ef97e7da585fdbf06988da8047e72b9f6Svetoslav Ganov if (increment) { 1919fe41ce4ef97e7da585fdbf06988da8047e72b9f6Svetoslav Ganov amountToScroll = - mSelectorElementHeight - deltaY; 1920fe41ce4ef97e7da585fdbf06988da8047e72b9f6Svetoslav Ganov } else { 1921fe41ce4ef97e7da585fdbf06988da8047e72b9f6Svetoslav Ganov amountToScroll = - deltaY; 1922fe41ce4ef97e7da585fdbf06988da8047e72b9f6Svetoslav Ganov } 1923fe41ce4ef97e7da585fdbf06988da8047e72b9f6Svetoslav Ganov } 1924fe41ce4ef97e7da585fdbf06988da8047e72b9f6Svetoslav Ganov mFlingScroller.startScroll(0, 0, 0, amountToScroll, SNAP_SCROLL_DURATION); 1925fe41ce4ef97e7da585fdbf06988da8047e72b9f6Svetoslav Ganov invalidate(); 1926fe41ce4ef97e7da585fdbf06988da8047e72b9f6Svetoslav Ganov } 1927fe41ce4ef97e7da585fdbf06988da8047e72b9f6Svetoslav Ganov } 1928fe41ce4ef97e7da585fdbf06988da8047e72b9f6Svetoslav Ganov 1929fe41ce4ef97e7da585fdbf06988da8047e72b9f6Svetoslav Ganov private void snapToClosestValue() { 1930fe41ce4ef97e7da585fdbf06988da8047e72b9f6Svetoslav Ganov // adjust to the closest value 1931fe41ce4ef97e7da585fdbf06988da8047e72b9f6Svetoslav Ganov int deltaY = mInitialScrollOffset - mCurrentScrollOffset; 1932fe41ce4ef97e7da585fdbf06988da8047e72b9f6Svetoslav Ganov if (deltaY != 0) { 1933fe41ce4ef97e7da585fdbf06988da8047e72b9f6Svetoslav Ganov mPreviousScrollerY = 0; 1934fe41ce4ef97e7da585fdbf06988da8047e72b9f6Svetoslav Ganov if (Math.abs(deltaY) > mSelectorElementHeight / 2) { 1935fe41ce4ef97e7da585fdbf06988da8047e72b9f6Svetoslav Ganov deltaY += (deltaY > 0) ? -mSelectorElementHeight : mSelectorElementHeight; 1936fe41ce4ef97e7da585fdbf06988da8047e72b9f6Svetoslav Ganov } 1937fe41ce4ef97e7da585fdbf06988da8047e72b9f6Svetoslav Ganov mFlingScroller.startScroll(0, 0, 0, deltaY, SNAP_SCROLL_DURATION); 1938fe41ce4ef97e7da585fdbf06988da8047e72b9f6Svetoslav Ganov invalidate(); 1939fe41ce4ef97e7da585fdbf06988da8047e72b9f6Svetoslav Ganov } 1940fe41ce4ef97e7da585fdbf06988da8047e72b9f6Svetoslav Ganov } 1941fe41ce4ef97e7da585fdbf06988da8047e72b9f6Svetoslav Ganov 1942d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov /** 1943206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Command for setting the input text selection. 1944206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 1945206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov class SetSelectionCommand implements Runnable { 1946206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private int mSelectionStart; 1947206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 1948206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private int mSelectionEnd; 1949206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 1950206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov public void run() { 1951206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mInputText.setSelection(mSelectionStart, mSelectionEnd); 1952206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1953206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1954206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 1955206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 1956b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov * Command for changing the current value from a long press by one. 1957206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 1958b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov class ChangeCurrentByOneFromLongPressCommand implements Runnable { 1959b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov private boolean mIncrement; 1960206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 1961d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private void setStep(boolean increment) { 1962b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov mIncrement = increment; 1963206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1964206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 1965d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov @Override 1966206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov public void run() { 1967d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov changeValueByOne(mIncrement); 19684bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov postDelayed(this, mLongPressUpdateInterval); 1969206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 197068f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook } 1971a2b41b438d45570867e4682c0caaf93ace5e712eSvetoslav Ganov 1972a2b41b438d45570867e4682c0caaf93ace5e712eSvetoslav Ganov /** 1973a2b41b438d45570867e4682c0caaf93ace5e712eSvetoslav Ganov * @hide 1974a2b41b438d45570867e4682c0caaf93ace5e712eSvetoslav Ganov */ 1975a2b41b438d45570867e4682c0caaf93ace5e712eSvetoslav Ganov public static class CustomEditText extends EditText { 1976a2b41b438d45570867e4682c0caaf93ace5e712eSvetoslav Ganov 1977a2b41b438d45570867e4682c0caaf93ace5e712eSvetoslav Ganov public CustomEditText(Context context, AttributeSet attrs) { 1978a2b41b438d45570867e4682c0caaf93ace5e712eSvetoslav Ganov super(context, attrs); 1979a2b41b438d45570867e4682c0caaf93ace5e712eSvetoslav Ganov } 1980a2b41b438d45570867e4682c0caaf93ace5e712eSvetoslav Ganov 1981a2b41b438d45570867e4682c0caaf93ace5e712eSvetoslav Ganov @Override 1982a2b41b438d45570867e4682c0caaf93ace5e712eSvetoslav Ganov public void onEditorAction(int actionCode) { 1983a2b41b438d45570867e4682c0caaf93ace5e712eSvetoslav Ganov super.onEditorAction(actionCode); 1984a2b41b438d45570867e4682c0caaf93ace5e712eSvetoslav Ganov if (actionCode == EditorInfo.IME_ACTION_DONE) { 1985a2b41b438d45570867e4682c0caaf93ace5e712eSvetoslav Ganov clearFocus(); 1986a2b41b438d45570867e4682c0caaf93ace5e712eSvetoslav Ganov } 1987a2b41b438d45570867e4682c0caaf93ace5e712eSvetoslav Ganov } 1988a2b41b438d45570867e4682c0caaf93ace5e712eSvetoslav Ganov } 1989d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 1990d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov /** 1991d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * Command for beginning soft input on long press. 1992d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov */ 1993d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov class BeginSoftInputOnLongPressCommand implements Runnable { 1994d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 1995d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov @Override 1996d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov public void run() { 1997d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov showSoftInput(); 1998d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mIngonreMoveEvents = true; 1999d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2000d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2001d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 2002d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov class AccessibilityNodeProviderImpl extends AccessibilityNodeProvider { 2003d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private static final int VIRTUAL_VIEW_ID_INCREMENT = 1; 2004d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 2005d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private static final int VIRTUAL_VIEW_ID_INPUT = 2; 2006d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 2007d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private static final int VIRTUAL_VIEW_ID_DECREMENT = 3; 2008d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 2009d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private final Rect mTempRect = new Rect(); 2010d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 2011d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private final int[] mTempArray = new int[2]; 2012d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 2013d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov @Override 2014d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov public AccessibilityNodeInfo createAccessibilityNodeInfo(int virtualViewId) { 2015d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov switch (virtualViewId) { 2016d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov case View.NO_ID: 2017d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return createAccessibilityNodeInfoForNumberPicker( mScrollX, mScrollY, 2018d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mScrollX + (mRight - mLeft), mScrollY + (mBottom - mTop)); 2019d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov case VIRTUAL_VIEW_ID_DECREMENT: 2020d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return createAccessibilityNodeInfoForVirtualButton(VIRTUAL_VIEW_ID_DECREMENT, 2021d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov getVirtualDecrementButtonText(), mScrollX, mScrollY, 2022d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mScrollX + (mRight - mLeft), 2023d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mTopSelectionDividerTop + mSelectionDividerHeight); 2024d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov case VIRTUAL_VIEW_ID_INPUT: 2025d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return createAccessibiltyNodeInfoForInputText(); 2026d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov case VIRTUAL_VIEW_ID_INCREMENT: 2027d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return createAccessibilityNodeInfoForVirtualButton(VIRTUAL_VIEW_ID_INCREMENT, 2028d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov getVirtualIncrementButtonText(), mScrollX, 2029d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mBottomSelectionDividerBottom - mSelectionDividerHeight, 2030d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mScrollX + (mRight - mLeft), mScrollY + (mBottom - mTop)); 2031d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2032d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return super.createAccessibilityNodeInfo(virtualViewId); 2033d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2034d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 2035d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov @Override 2036d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov public List<AccessibilityNodeInfo> findAccessibilityNodeInfosByText(String searched, 2037d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov int virtualViewId) { 2038d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (TextUtils.isEmpty(searched)) { 2039d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return Collections.emptyList(); 2040d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2041d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov String searchedLowerCase = searched.toLowerCase(); 2042d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov List<AccessibilityNodeInfo> result = new ArrayList<AccessibilityNodeInfo>(); 2043d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov switch (virtualViewId) { 2044d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov case View.NO_ID: { 2045d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov findAccessibilityNodeInfosByTextInChild(searchedLowerCase, 2046d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov VIRTUAL_VIEW_ID_DECREMENT, result); 2047d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov findAccessibilityNodeInfosByTextInChild(searchedLowerCase, 2048d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov VIRTUAL_VIEW_ID_INPUT, result); 2049d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov findAccessibilityNodeInfosByTextInChild(searchedLowerCase, 2050d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov VIRTUAL_VIEW_ID_INCREMENT, result); 2051d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return result; 2052d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2053d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov case VIRTUAL_VIEW_ID_DECREMENT: 2054d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov case VIRTUAL_VIEW_ID_INCREMENT: 2055d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov case VIRTUAL_VIEW_ID_INPUT: { 2056d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov findAccessibilityNodeInfosByTextInChild(searchedLowerCase, virtualViewId, 2057d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov result); 2058d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return result; 2059d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2060d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2061d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return super.findAccessibilityNodeInfosByText(searched, virtualViewId); 2062d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2063d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 2064d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov @Override 2065d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov public boolean performAccessibilityAction(int action, int virtualViewId) { 2066d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov switch (virtualViewId) { 2067d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov case VIRTUAL_VIEW_ID_INPUT: { 2068d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov switch (action) { 2069d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov case AccessibilityNodeInfo.ACTION_FOCUS: { 2070d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (!mInputText.isFocused()) { 2071d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return mInputText.requestFocus(); 2072d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2073d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } break; 2074d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov case AccessibilityNodeInfo.ACTION_CLEAR_FOCUS: { 2075d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (mInputText.isFocused()) { 2076d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mInputText.clearFocus(); 2077d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return true; 2078d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2079d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } break; 2080d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2081d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } break; 2082d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2083d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return super.performAccessibilityAction(action, virtualViewId); 2084d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2085d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 2086d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov public void sendAccessibilityEventForVirtualView(int virtualViewId, int eventType) { 2087d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov switch (virtualViewId) { 2088d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov case VIRTUAL_VIEW_ID_DECREMENT: { 2089d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov sendAccessibilityEventForVirtualButton(virtualViewId, eventType, 2090d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov getVirtualDecrementButtonText()); 2091d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } break; 2092d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov case VIRTUAL_VIEW_ID_INPUT: { 2093d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov sendAccessibilityEventForVirtualText(eventType); 2094d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } break; 2095d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov case VIRTUAL_VIEW_ID_INCREMENT: { 2096d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov sendAccessibilityEventForVirtualButton(virtualViewId, eventType, 2097d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov getVirtualIncrementButtonText()); 2098d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } break; 2099d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2100d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2101d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 2102d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private void sendAccessibilityEventForVirtualText(int eventType) { 2103d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov AccessibilityEvent event = AccessibilityEvent.obtain(eventType); 2104d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mInputText.onInitializeAccessibilityEvent(event); 2105d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mInputText.onPopulateAccessibilityEvent(event); 2106d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov event.setSource(NumberPicker.this, VIRTUAL_VIEW_ID_INPUT); 2107d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov requestSendAccessibilityEvent(NumberPicker.this, event); 2108d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2109d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 2110d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private void sendAccessibilityEventForVirtualButton(int virtualViewId, int eventType, 2111d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov String text) { 2112d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov AccessibilityEvent event = AccessibilityEvent.obtain(eventType); 2113d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov event.setClassName(Button.class.getName()); 2114d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov event.setPackageName(mContext.getPackageName()); 2115d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov event.getText().add(text); 2116d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov event.setEnabled(NumberPicker.this.isEnabled()); 2117d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov event.setSource(NumberPicker.this, virtualViewId); 2118d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov requestSendAccessibilityEvent(NumberPicker.this, event); 2119d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2120d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 2121d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private void findAccessibilityNodeInfosByTextInChild(String searchedLowerCase, 2122d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov int virtualViewId, List<AccessibilityNodeInfo> outResult) { 2123d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov switch (virtualViewId) { 2124d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov case VIRTUAL_VIEW_ID_DECREMENT: { 2125d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov String text = getVirtualDecrementButtonText(); 2126d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (!TextUtils.isEmpty(text) 2127d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov && text.toString().toLowerCase().contains(searchedLowerCase)) { 2128d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov outResult.add(createAccessibilityNodeInfo(VIRTUAL_VIEW_ID_DECREMENT)); 2129d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2130d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } return; 2131d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov case VIRTUAL_VIEW_ID_INPUT: { 2132d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov CharSequence text = mInputText.getText(); 2133d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (!TextUtils.isEmpty(text) && 2134d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov text.toString().toLowerCase().contains(searchedLowerCase)) { 2135d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov outResult.add(createAccessibilityNodeInfo(VIRTUAL_VIEW_ID_INPUT)); 2136d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return; 2137d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2138d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov CharSequence contentDesc = mInputText.getText(); 2139d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (!TextUtils.isEmpty(contentDesc) && 2140d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov contentDesc.toString().toLowerCase().contains(searchedLowerCase)) { 2141d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov outResult.add(createAccessibilityNodeInfo(VIRTUAL_VIEW_ID_INPUT)); 2142d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return; 2143d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2144d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } break; 2145d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov case VIRTUAL_VIEW_ID_INCREMENT: { 2146d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov String text = getVirtualIncrementButtonText(); 2147d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (!TextUtils.isEmpty(text) 2148d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov && text.toString().toLowerCase().contains(searchedLowerCase)) { 2149d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov outResult.add(createAccessibilityNodeInfo(VIRTUAL_VIEW_ID_INCREMENT)); 2150d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2151d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } return; 2152d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2153d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2154d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 2155d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private AccessibilityNodeInfo createAccessibiltyNodeInfoForInputText() { 2156d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov AccessibilityNodeInfo info = mInputText.createAccessibilityNodeInfo(); 2157d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov info.setLongClickable(true); 2158d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov info.setSource(NumberPicker.this, VIRTUAL_VIEW_ID_INPUT); 2159d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return info; 2160d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2161d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 2162d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private AccessibilityNodeInfo createAccessibilityNodeInfoForVirtualButton(int virtualViewId, 2163d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov String text, int left, int top, int right, int bottom) { 2164d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain(); 2165d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov info.setClassName(Button.class.getName()); 2166d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov info.setPackageName(mContext.getPackageName()); 2167d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov info.setSource(NumberPicker.this, virtualViewId); 2168d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov info.setParent(NumberPicker.this); 2169d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov info.addChild(NumberPicker.this, VIRTUAL_VIEW_ID_DECREMENT); 2170d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov info.addChild(NumberPicker.this, VIRTUAL_VIEW_ID_INPUT); 2171d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov info.addChild(NumberPicker.this, VIRTUAL_VIEW_ID_INCREMENT); 2172d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov info.setText(text); 2173d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov info.setClickable(true); 2174d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov info.setLongClickable(true); 2175d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov info.setEnabled(NumberPicker.this.isEnabled()); 2176d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov Rect boundsInParent = mTempRect; 2177d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov boundsInParent.set(left, top, right, bottom); 2178d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov info.setBoundsInParent(boundsInParent); 2179d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov Rect boundsInScreen = boundsInParent; 2180d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov int[] locationOnScreen = mTempArray; 2181d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov getLocationOnScreen(locationOnScreen); 2182d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov boundsInScreen.offsetTo(0, 0); 2183d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov boundsInScreen.offset(locationOnScreen[0], locationOnScreen[1]); 2184d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov info.setBoundsInScreen(boundsInScreen); 2185d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return info; 2186d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2187d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 2188d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private AccessibilityNodeInfo createAccessibilityNodeInfoForNumberPicker(int left, int top, 2189d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov int right, int bottom) { 2190d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain(); 2191d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov info.setClassName(Button.class.getName()); 2192d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov info.setPackageName(mContext.getPackageName()); 2193d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov info.setSource(NumberPicker.this); 2194d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov info.setParent((View) getParent()); 2195d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov info.setEnabled(NumberPicker.this.isEnabled()); 2196d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov info.setScrollable(true); 2197d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov Rect boundsInParent = mTempRect; 2198d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov boundsInParent.set(left, top, right, bottom); 2199d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov info.setBoundsInParent(boundsInParent); 2200d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov Rect boundsInScreen = boundsInParent; 2201d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov int[] locationOnScreen = mTempArray; 2202d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov getLocationOnScreen(locationOnScreen); 2203d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov boundsInScreen.offsetTo(0, 0); 2204d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov boundsInScreen.offset(locationOnScreen[0], locationOnScreen[1]); 2205d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov info.setBoundsInScreen(boundsInScreen); 2206d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return info; 2207d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2208d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 2209d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private String getVirtualDecrementButtonText() { 2210d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov int value = mValue - 1; 2211d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (mWrapSelectorWheel) { 2212d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov value = getWrappedSelectorIndex(value); 2213d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2214d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (value >= mMinValue) { 2215d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return (mDisplayedValues == null) ? formatNumber(value) 2216d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov : mDisplayedValues[value - mMinValue]; 2217d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2218d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return null; 2219d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2220d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 2221d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private String getVirtualIncrementButtonText() { 2222d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov int value = mValue + 1; 2223d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (mWrapSelectorWheel) { 2224d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov value = getWrappedSelectorIndex(value); 2225d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2226d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (value <= mMaxValue) { 2227d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return (mDisplayedValues == null) ? formatNumber(value) 2228d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov : mDisplayedValues[value - mMinValue]; 2229d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2230d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return null; 2231d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2232d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 22337762d93621f508f4410fd37b5bbdfec0071b0420Paul Westbrook} 2234