NumberPicker.java revision 6d8a99fecc5dd3aec502c0419af61e8d2a3c398d
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; 29aa780c110922148a6a4ba06734bb2b0bb8c98f93Svetoslav Ganovimport android.os.Bundle; 309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.text.InputFilter; 319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.text.InputType; 329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.text.Spanned; 33206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganovimport android.text.TextUtils; 349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.text.method.NumberKeyListener; 359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.AttributeSet; 36206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganovimport android.util.SparseArray; 379cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganovimport android.util.TypedValue; 38206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganovimport android.view.KeyEvent; 399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.LayoutInflater; 40b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganovimport android.view.LayoutInflater.Filter; 41206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganovimport android.view.MotionEvent; 42206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganovimport android.view.VelocityTracker; 439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.View; 44206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganovimport android.view.ViewConfiguration; 453fec3fe0e3a83c5e0d1264f34bcc55b158537bc6Svetoslav Ganovimport android.view.accessibility.AccessibilityEvent; 463fec3fe0e3a83c5e0d1264f34bcc55b158537bc6Svetoslav Ganovimport android.view.accessibility.AccessibilityManager; 478a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganovimport android.view.accessibility.AccessibilityNodeInfo; 48d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganovimport android.view.accessibility.AccessibilityNodeProvider; 499cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganovimport android.view.animation.DecelerateInterpolator; 50a2b41b438d45570867e4682c0caaf93ace5e712eSvetoslav Ganovimport android.view.inputmethod.EditorInfo; 51206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganovimport android.view.inputmethod.InputMethodManager; 529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 53b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganovimport com.android.internal.R; 54d88e3054d08b1f821bb2e27b2647aa16a60d8742Fabrice Di Meglioimport libcore.icu.LocaleData; 55b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov 56d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganovimport java.util.ArrayList; 57d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganovimport java.util.Collections; 58d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganovimport java.util.List; 59d88e3054d08b1f821bb2e27b2647aa16a60d8742Fabrice Di Meglioimport java.util.Locale; 60d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 6168f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook/** 624bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * A widget that enables the user to select a number form a predefined range. 63d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * There are two flavors of this widget and which one is presented to the user 64d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * depends on the current theme. 65d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * <ul> 66d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * <li> 67d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * If the current theme is derived from {@link android.R.style#Theme} the widget 68d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * presents the current value as an editable input field with an increment button 69d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * above and a decrement button below. Long pressing the buttons allows for a quick 70d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * change of the current value. Tapping on the input field allows to type in 71d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * a desired value. 72d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * </li> 73d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * <li> 74d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * If the current theme is derived from {@link android.R.style#Theme_Holo} or 75d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * {@link android.R.style#Theme_Holo_Light} the widget presents the current 76d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * value as an editable input field with a lesser value above and a greater 77d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * value below. Tapping on the lesser or greater value selects it by animating 78d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * the number axis up or down to make the chosen value current. Flinging up 79d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * or down allows for multiple increments or decrements of the current value. 80d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * Long pressing on the lesser and greater values also allows for a quick change 81d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * of the current value. Tapping on the current value allows to type in a 82d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * desired value. 83d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * </li> 84d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * </ul> 854bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * <p> 864bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * For an example of using this widget, see {@link android.widget.TimePicker}. 874bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * </p> 8868f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook */ 8968f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook@Widget 9068f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrookpublic class NumberPicker extends LinearLayout { 91fdf6db6748b32f620a7f68b13a67c38b4e59e5edTom Taylor 9268f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook /** 933f9c9eab7b41c409c3c7b503b89ad340e408b6a0Svetoslav Ganov * The number of items show in the selector wheel. 943f9c9eab7b41c409c3c7b503b89ad340e408b6a0Svetoslav Ganov */ 95d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private static final int SELECTOR_WHEEL_ITEM_COUNT = 3; 963f9c9eab7b41c409c3c7b503b89ad340e408b6a0Svetoslav Ganov 973f9c9eab7b41c409c3c7b503b89ad340e408b6a0Svetoslav Ganov /** 98e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * The default update interval during long press. 99e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov */ 100e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov private static final long DEFAULT_LONG_PRESS_UPDATE_INTERVAL = 300; 101e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov 102e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov /** 103206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * The index of the middle selector item. 10468f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook */ 105d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private static final int SELECTOR_MIDDLE_ITEM_INDEX = SELECTOR_WHEEL_ITEM_COUNT / 2; 1069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10768f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook /** 108206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * The coefficient by which to adjust (divide) the max fling velocity. 10968f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook */ 110206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private static final int SELECTOR_MAX_FLING_VELOCITY_ADJUSTMENT = 8; 1119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 112206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 113206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * The the duration for adjusting the selector wheel. 114206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 115206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private static final int SELECTOR_ADJUSTMENT_DURATION_MILLIS = 800; 116fdf6db6748b32f620a7f68b13a67c38b4e59e5edTom Taylor 117206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 1184213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov * The duration of scrolling while snapping to a given position. 119b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov */ 120fe41ce4ef97e7da585fdbf06988da8047e72b9f6Svetoslav Ganov private static final int SNAP_SCROLL_DURATION = 300; 121b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov 122b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov /** 123b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov * The strength of fading in the top and bottom while drawing the selector. 124206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 125b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov private static final float TOP_AND_BOTTOM_FADING_EDGE_STRENGTH = 0.9f; 126206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 127206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 128b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov * The default unscaled height of the selection divider. 129206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 130b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov private static final int UNSCALED_DEFAULT_SELECTION_DIVIDER_HEIGHT = 2; 131206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 132206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 133d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * The default unscaled distance between the selection dividers. 134b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov */ 135d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private static final int UNSCALED_DEFAULT_SELECTION_DIVIDERS_DISTANCE = 48; 136b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov 137b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov /** 138d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * The resource id for the default layout. 139b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov */ 140d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private static final int DEFAULT_LAYOUT_RESOURCE_ID = R.layout.number_picker; 1419cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov 1429cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov /** 1439f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov * Constant for unspecified size. 1449f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov */ 1459f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov private static final int SIZE_UNSPECIFIED = -1; 1469f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov 1479f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov /** 148206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Use a custom NumberPicker formatting callback to use two-digit minutes 149206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * strings like "01". Keeping a static formatter etc. is the most efficient 150206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * way to do this; it avoids creating temporary objects on every call to 151206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * format(). 152206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 153d88e3054d08b1f821bb2e27b2647aa16a60d8742Fabrice Di Meglio private static class TwoDigitFormatter implements NumberPicker.Formatter { 154206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov final StringBuilder mBuilder = new StringBuilder(); 155206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 156d88e3054d08b1f821bb2e27b2647aa16a60d8742Fabrice Di Meglio char mZeroDigit; 157d88e3054d08b1f821bb2e27b2647aa16a60d8742Fabrice Di Meglio java.util.Formatter mFmt; 158206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 159206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov final Object[] mArgs = new Object[1]; 160206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 161d88e3054d08b1f821bb2e27b2647aa16a60d8742Fabrice Di Meglio TwoDigitFormatter() { 162d88e3054d08b1f821bb2e27b2647aa16a60d8742Fabrice Di Meglio final Locale locale = Locale.getDefault(); 163d88e3054d08b1f821bb2e27b2647aa16a60d8742Fabrice Di Meglio init(locale); 164d88e3054d08b1f821bb2e27b2647aa16a60d8742Fabrice Di Meglio } 165d88e3054d08b1f821bb2e27b2647aa16a60d8742Fabrice Di Meglio 166d88e3054d08b1f821bb2e27b2647aa16a60d8742Fabrice Di Meglio private void init(Locale locale) { 167d88e3054d08b1f821bb2e27b2647aa16a60d8742Fabrice Di Meglio mFmt = createFormatter(locale); 168d88e3054d08b1f821bb2e27b2647aa16a60d8742Fabrice Di Meglio mZeroDigit = getZeroDigit(locale); 169d88e3054d08b1f821bb2e27b2647aa16a60d8742Fabrice Di Meglio } 170d88e3054d08b1f821bb2e27b2647aa16a60d8742Fabrice Di Meglio 171e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov public String format(int value) { 172d88e3054d08b1f821bb2e27b2647aa16a60d8742Fabrice Di Meglio final Locale currentLocale = Locale.getDefault(); 173d88e3054d08b1f821bb2e27b2647aa16a60d8742Fabrice Di Meglio if (mZeroDigit != getZeroDigit(currentLocale)) { 174d88e3054d08b1f821bb2e27b2647aa16a60d8742Fabrice Di Meglio init(currentLocale); 175d88e3054d08b1f821bb2e27b2647aa16a60d8742Fabrice Di Meglio } 176206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mArgs[0] = value; 177206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mBuilder.delete(0, mBuilder.length()); 178206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mFmt.format("%02d", mArgs); 179206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return mFmt.toString(); 1809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 181d88e3054d08b1f821bb2e27b2647aa16a60d8742Fabrice Di Meglio 182d88e3054d08b1f821bb2e27b2647aa16a60d8742Fabrice Di Meglio private static char getZeroDigit(Locale locale) { 183d88e3054d08b1f821bb2e27b2647aa16a60d8742Fabrice Di Meglio return LocaleData.get(locale).zeroDigit; 184d88e3054d08b1f821bb2e27b2647aa16a60d8742Fabrice Di Meglio } 185d88e3054d08b1f821bb2e27b2647aa16a60d8742Fabrice Di Meglio 186d88e3054d08b1f821bb2e27b2647aa16a60d8742Fabrice Di Meglio private java.util.Formatter createFormatter(Locale locale) { 187d88e3054d08b1f821bb2e27b2647aa16a60d8742Fabrice Di Meglio return new java.util.Formatter(mBuilder, locale); 188d88e3054d08b1f821bb2e27b2647aa16a60d8742Fabrice Di Meglio } 189d88e3054d08b1f821bb2e27b2647aa16a60d8742Fabrice Di Meglio } 190d88e3054d08b1f821bb2e27b2647aa16a60d8742Fabrice Di Meglio 191d88e3054d08b1f821bb2e27b2647aa16a60d8742Fabrice Di Meglio private static final TwoDigitFormatter sTwoDigitFormatter = new TwoDigitFormatter(); 192d88e3054d08b1f821bb2e27b2647aa16a60d8742Fabrice Di Meglio 193a65fe884d1bba4c64b961df27bd04e33e28a7209Fabrice Di Meglio /** 194a65fe884d1bba4c64b961df27bd04e33e28a7209Fabrice Di Meglio * @hide 195a65fe884d1bba4c64b961df27bd04e33e28a7209Fabrice Di Meglio */ 196a65fe884d1bba4c64b961df27bd04e33e28a7209Fabrice Di Meglio public static final Formatter getTwoDigitFormatter() { 197d88e3054d08b1f821bb2e27b2647aa16a60d8742Fabrice Di Meglio return sTwoDigitFormatter; 198d88e3054d08b1f821bb2e27b2647aa16a60d8742Fabrice Di Meglio } 199d88e3054d08b1f821bb2e27b2647aa16a60d8742Fabrice Di Meglio 200206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 201206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * The increment button. 202206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 203206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private final ImageButton mIncrementButton; 204206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 205206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 206206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * The decrement button. 207206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 208206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private final ImageButton mDecrementButton; 209206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 210206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 211206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * The text for showing the current value. 212206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 213206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private final EditText mInputText; 214206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 215206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 216d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * The distance between the two selection dividers. 217d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov */ 218d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private final int mSelectionDividersDistance; 219d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 220d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov /** 221ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov * The min height of this widget. 222ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov */ 223ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov private final int mMinHeight; 224ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov 225ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov /** 226e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov * The max height of this widget. 227e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov */ 228e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov private final int mMaxHeight; 229e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov 230e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov /** 231e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov * The max width of this widget. 232e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov */ 233ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov private final int mMinWidth; 234ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov 235ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov /** 236ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov * The max width of this widget. 237ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov */ 238ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov private int mMaxWidth; 239ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov 240ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov /** 241ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov * Flag whether to compute the max width. 242ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov */ 243ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov private final boolean mComputeMaxWidth; 244e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov 245e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov /** 246206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * The height of the text. 247206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 248206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private final int mTextSize; 2499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 250206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 251b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov * The height of the gap between text elements if the selector wheel. 252b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov */ 253b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov private int mSelectorTextGapHeight; 254b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov 255b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov /** 256206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * The values to be displayed instead the indices. 257206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 2589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private String[] mDisplayedValues; 25968f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook 26068f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook /** 26168f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook * Lower value of the range of numbers allowed for the NumberPicker 26268f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook */ 263e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov private int mMinValue; 26468f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook 26568f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook /** 26668f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook * Upper value of the range of numbers allowed for the NumberPicker 26768f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook */ 268e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov private int mMaxValue; 26968f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook 27068f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook /** 27168f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook * Current value of this NumberPicker 27268f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook */ 273e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov private int mValue; 27468f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook 27568f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook /** 276206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Listener to be notified upon current value change. 27768f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook */ 278cedc446684e94c9971c38c3206f1f224314bda2aSvetoslav Ganov private OnValueChangeListener mOnValueChangeListener; 27950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 28050f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov /** 28150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * Listener to be notified upon scroll state change. 28250f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov */ 28350f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov private OnScrollListener mOnScrollListener; 284206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 285206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 286206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Formatter for for displaying the current value. 287206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 2889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private Formatter mFormatter; 289fdf6db6748b32f620a7f68b13a67c38b4e59e5edTom Taylor 290206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 291206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * The speed for updating the value form long press. 292206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 293e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov private long mLongPressUpdateInterval = DEFAULT_LONG_PRESS_UPDATE_INTERVAL; 294fdf6db6748b32f620a7f68b13a67c38b4e59e5edTom Taylor 29568f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook /** 296206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Cache for the string representation of selector indices. 297206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 298206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private final SparseArray<String> mSelectorIndexToStringCache = new SparseArray<String>(); 299206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 300206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 301206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * The selector indices whose value are show by the selector. 302206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 303d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private final int[] mSelectorIndices = new int[SELECTOR_WHEEL_ITEM_COUNT]; 304206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 305206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 306206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * The {@link Paint} for drawing the selector. 307206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 308b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov private final Paint mSelectorWheelPaint; 309206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 310206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 311232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov * The {@link Drawable} for pressed virtual (increment/decrement) buttons. 312232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov */ 313232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov private final Drawable mVirtualButtonPressedDrawable; 314232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov 315232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov /** 316206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * The height of a selector element (text + gap). 317206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 318206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private int mSelectorElementHeight; 319206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 320206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 321206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * The initial offset of the scroll selector. 322206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 323206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private int mInitialScrollOffset = Integer.MIN_VALUE; 324206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 325206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 326206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * The current offset of the scroll selector. 327206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 328206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private int mCurrentScrollOffset; 329206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 330206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 331206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * The {@link Scroller} responsible for flinging the selector. 332206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 333206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private final Scroller mFlingScroller; 334206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 335206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 336206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * The {@link Scroller} responsible for adjusting the selector. 337206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 338206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private final Scroller mAdjustScroller; 339206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 340206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 341206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * The previous Y coordinate while scrolling the selector. 342206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 343206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private int mPreviousScrollerY; 344206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 345206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 346206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Handle to the reusable command for setting the input text selection. 347206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 348206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private SetSelectionCommand mSetSelectionCommand; 349206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 350206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 351b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov * Handle to the reusable command for changing the current value from long 352b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov * press by one. 353206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 354b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov private ChangeCurrentByOneFromLongPressCommand mChangeCurrentByOneFromLongPressCommand; 355206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 356206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 357d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * Command for beginning an edit of the current value via IME on long press. 358b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov */ 359d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private BeginSoftInputOnLongPressCommand mBeginSoftInputOnLongPressCommand; 360b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov 361b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov /** 362206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * The Y position of the last down event. 363206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 364206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private float mLastDownEventY; 365206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 366206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 367d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * The time of the last down event. 368206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 369d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private long mLastDownEventTime; 370206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 371206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 372d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * The Y position of the last down or move event. 373206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 374d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private float mLastDownOrMoveEventY; 375206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 376206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 377206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Determines speed during touch scrolling. 378206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 379206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private VelocityTracker mVelocityTracker; 380206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 381206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 382206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * @see ViewConfiguration#getScaledTouchSlop() 383206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 384206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private int mTouchSlop; 385206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 386206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 387206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * @see ViewConfiguration#getScaledMinimumFlingVelocity() 388206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 389206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private int mMinimumFlingVelocity; 390206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 391206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 392206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * @see ViewConfiguration#getScaledMaximumFlingVelocity() 393206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 394206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private int mMaximumFlingVelocity; 395206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 396206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 397206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Flag whether the selector should wrap around. 398206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 399e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov private boolean mWrapSelectorWheel; 400206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 401206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 402206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * The back ground color used to optimize scroller fading. 40368f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook */ 404206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private final int mSolidColor; 405206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 406206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 407d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * Flag whether this widget has a selector wheel. 4084243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov */ 409d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private final boolean mHasSelectorWheel; 4104243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov 4114243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov /** 4129cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov * Divider for showing item to be selected while scrolling 4139cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov */ 4149cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov private final Drawable mSelectionDivider; 4159cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov 4169cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov /** 4179cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov * The height of the selection divider. 4189cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov */ 4199cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov private final int mSelectionDividerHeight; 4209cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov 4219cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov /** 422d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * The current scroll state of the number picker. 423206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 424d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private int mScrollState = OnScrollListener.SCROLL_STATE_IDLE; 425206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 426206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 427d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * Flag whether to ignore move events - we ignore such when we show in IME 428d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * to prevent the content from scrolling. 42950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov */ 430d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private boolean mIngonreMoveEvents; 43150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 43250f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov /** 433d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * Flag whether to show soft input on tap. 4349cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov */ 435d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private boolean mShowSoftInputOnTap; 4369cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov 4379cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov /** 438d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * The top of the top selection divider. 439b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov */ 440d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private int mTopSelectionDividerTop; 441b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov 442b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov /** 443d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * The bottom of the bottom selection divider. 444a2b41b438d45570867e4682c0caaf93ace5e712eSvetoslav Ganov */ 445d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private int mBottomSelectionDividerBottom; 446d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 447d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov /** 448d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * The virtual id of the last hovered child. 449d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov */ 450d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private int mLastHoveredChildVirtualViewId; 451d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 452d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov /** 453232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov * Whether the increment virtual button is pressed. 454232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov */ 455232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov private boolean mIncrementVirtualButtonPressed; 456232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov 457232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov /** 458232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov * Whether the decrement virtual button is pressed. 459232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov */ 460232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov private boolean mDecrementVirtualButtonPressed; 461232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov 462232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov /** 463d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * Provider to report to clients the semantic structure of this widget. 464d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov */ 465d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private AccessibilityNodeProviderImpl mAccessibilityNodeProvider; 466a2b41b438d45570867e4682c0caaf93ace5e712eSvetoslav Ganov 467a2b41b438d45570867e4682c0caaf93ace5e712eSvetoslav Ganov /** 468232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov * Helper class for managing pressed state of the virtual buttons. 469232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov */ 470232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov private final PressedStateHelper mPressedStateHelper; 471232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov 472232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov /** 4735dc21d9b340fe2c1cb4c37435d8a29429cf3f79eSvetoslav Ganov * The keycode of the last handled DPAD down event. 4745dc21d9b340fe2c1cb4c37435d8a29429cf3f79eSvetoslav Ganov */ 4755dc21d9b340fe2c1cb4c37435d8a29429cf3f79eSvetoslav Ganov private int mLastHandledDownDpadKeyCode = -1; 4765dc21d9b340fe2c1cb4c37435d8a29429cf3f79eSvetoslav Ganov 4775dc21d9b340fe2c1cb4c37435d8a29429cf3f79eSvetoslav Ganov /** 478e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * Interface to listen for changes of the current value. 479206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 480cedc446684e94c9971c38c3206f1f224314bda2aSvetoslav Ganov public interface OnValueChangeListener { 481e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov 482206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 4834bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * Called upon a change of the current value. 4844bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * 485206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * @param picker The NumberPicker associated with this listener. 486206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * @param oldVal The previous value. 487206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * @param newVal The new value. 488206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 489e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov void onValueChange(NumberPicker picker, int oldVal, int newVal); 490206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 491206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 492206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 493e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * Interface to listen for the picker scroll state. 49450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov */ 49550f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov public interface OnScrollListener { 49650f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 49750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov /** 49850f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * The view is not scrolling. 49950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov */ 50050f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov public static int SCROLL_STATE_IDLE = 0; 50150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 50250f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov /** 503d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * The user is scrolling using touch, and his finger is still on the screen. 50450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov */ 50550f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov public static int SCROLL_STATE_TOUCH_SCROLL = 1; 50650f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 50750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov /** 50850f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * The user had previously been scrolling using touch and performed a fling. 50950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov */ 51050f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov public static int SCROLL_STATE_FLING = 2; 51150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 51250f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov /** 513e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * Callback invoked while the number picker scroll state has changed. 51450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * 515e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @param view The view whose scroll state is being reported. 516e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @param scrollState The current scroll state. One of 517e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * {@link #SCROLL_STATE_IDLE}, 518e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * {@link #SCROLL_STATE_TOUCH_SCROLL} or 519e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * {@link #SCROLL_STATE_IDLE}. 52050f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov */ 5214bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov public void onScrollStateChange(NumberPicker view, int scrollState); 52250f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov } 52350f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 52450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov /** 525e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * Interface used to format current value into a string for presentation. 526206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 527206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov public interface Formatter { 5284bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov 5294bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov /** 530e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * Formats a string representation of the current value. 5314bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * 5324bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * @param value The currently selected value. 5334bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * @return A formatted string representation. 5344bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov */ 535e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov public String format(int value); 5369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 537fdf6db6748b32f620a7f68b13a67c38b4e59e5edTom Taylor 53868f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook /** 5394bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * Create a new number picker. 5404bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * 5414bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * @param context The application environment. 5424bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov */ 5434bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov public NumberPicker(Context context) { 5444bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov this(context, null); 5454bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov } 5464bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov 5474bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov /** 5484bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * Create a new number picker. 549206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * 550206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * @param context The application environment. 551206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * @param attrs A collection of attributes. 55268f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook */ 5539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public NumberPicker(Context context, AttributeSet attrs) { 554206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov this(context, attrs, R.attr.numberPickerStyle); 555206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 556206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 557206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 558206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Create a new number picker 559206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * 560206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * @param context the application environment. 561206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * @param attrs a collection of attributes. 562206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * @param defStyle The default style to apply to this view. 563206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 564206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov public NumberPicker(Context context, AttributeSet attrs, int defStyle) { 565206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov super(context, attrs, defStyle); 566206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 567206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // process style attributes 568d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov TypedArray attributesArray = context.obtainStyledAttributes( 569d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov attrs, R.styleable.NumberPicker, defStyle, 0); 570d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov final int layoutResId = attributesArray.getResourceId( 571d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov R.styleable.NumberPicker_internalLayout, DEFAULT_LAYOUT_RESOURCE_ID); 572d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 573d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mHasSelectorWheel = (layoutResId != DEFAULT_LAYOUT_RESOURCE_ID); 574d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 575206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mSolidColor = attributesArray.getColor(R.styleable.NumberPicker_solidColor, 0); 576d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 5779cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov mSelectionDivider = attributesArray.getDrawable(R.styleable.NumberPicker_selectionDivider); 578d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 579d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov final int defSelectionDividerHeight = (int) TypedValue.applyDimension( 580d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov TypedValue.COMPLEX_UNIT_DIP, UNSCALED_DEFAULT_SELECTION_DIVIDER_HEIGHT, 5819cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov getResources().getDisplayMetrics()); 5829cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov mSelectionDividerHeight = attributesArray.getDimensionPixelSize( 5839cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov R.styleable.NumberPicker_selectionDividerHeight, defSelectionDividerHeight); 584d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 585d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov final int defSelectionDividerDistance = (int) TypedValue.applyDimension( 586d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov TypedValue.COMPLEX_UNIT_DIP, UNSCALED_DEFAULT_SELECTION_DIVIDERS_DISTANCE, 587d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov getResources().getDisplayMetrics()); 588d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mSelectionDividersDistance = attributesArray.getDimensionPixelSize( 589d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov R.styleable.NumberPicker_selectionDividersDistance, defSelectionDividerDistance); 590d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 591e8331bd2e7ad3d62140143cafba3ff69be028557Svetoslav Ganov mMinHeight = attributesArray.getDimensionPixelSize( 592e8331bd2e7ad3d62140143cafba3ff69be028557Svetoslav Ganov R.styleable.NumberPicker_internalMinHeight, SIZE_UNSPECIFIED); 593d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 594e8331bd2e7ad3d62140143cafba3ff69be028557Svetoslav Ganov mMaxHeight = attributesArray.getDimensionPixelSize( 595e8331bd2e7ad3d62140143cafba3ff69be028557Svetoslav Ganov R.styleable.NumberPicker_internalMaxHeight, SIZE_UNSPECIFIED); 5969f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov if (mMinHeight != SIZE_UNSPECIFIED && mMaxHeight != SIZE_UNSPECIFIED 5979f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov && mMinHeight > mMaxHeight) { 598ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov throw new IllegalArgumentException("minHeight > maxHeight"); 599ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov } 600d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 601d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mMinWidth = attributesArray.getDimensionPixelSize( 602d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov R.styleable.NumberPicker_internalMinWidth, SIZE_UNSPECIFIED); 603d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 604d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mMaxWidth = attributesArray.getDimensionPixelSize( 605d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov R.styleable.NumberPicker_internalMaxWidth, SIZE_UNSPECIFIED); 6069f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov if (mMinWidth != SIZE_UNSPECIFIED && mMaxWidth != SIZE_UNSPECIFIED 6079f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov && mMinWidth > mMaxWidth) { 608ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov throw new IllegalArgumentException("minWidth > maxWidth"); 609ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov } 610d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 611f7c83bc4d3e1996b491824902a6a0f98ac69bedeSvetoslav Ganov mComputeMaxWidth = (mMaxWidth == SIZE_UNSPECIFIED); 612206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 613232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov mVirtualButtonPressedDrawable = attributesArray.getDrawable( 614232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov R.styleable.NumberPicker_virtualButtonPressedDrawable); 615232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov 616d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov attributesArray.recycle(); 6179cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov 618232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov mPressedStateHelper = new PressedStateHelper(); 619232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov 620206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // By default Linearlayout that we extend is not drawn. This is 621206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // its draw() method is not called but dispatchDraw() is called 622206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // directly (see ViewGroup.drawChild()). However, this class uses 623206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // the fading edge effect implemented by View and we need our 624206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // draw() method to be called. Therefore, we declare we will draw. 625d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov setWillNotDraw(!mHasSelectorWheel); 626206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 627206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov LayoutInflater inflater = (LayoutInflater) getContext().getSystemService( 628206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov Context.LAYOUT_INFLATER_SERVICE); 629d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov inflater.inflate(layoutResId, this, true); 63068f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook 631206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov OnClickListener onClickListener = new OnClickListener() { 63268f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook public void onClick(View v) { 633b52d9729bfb2ef7ad50d9a5125ebf3a8322429a9Svetoslav Ganov hideSoftInput(); 634206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mInputText.clearFocus(); 635206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (v.getId() == R.id.increment) { 636d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov changeValueByOne(true); 637206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } else { 638d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov changeValueByOne(false); 63968f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook } 64068f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook } 64168f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook }; 64268f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook 643206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov OnLongClickListener onLongClickListener = new OnLongClickListener() { 644206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov public boolean onLongClick(View v) { 645b52d9729bfb2ef7ad50d9a5125ebf3a8322429a9Svetoslav Ganov hideSoftInput(); 646206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mInputText.clearFocus(); 647206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (v.getId() == R.id.increment) { 648d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov postChangeCurrentByOneFromLongPress(true, 0); 649206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } else { 650d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov postChangeCurrentByOneFromLongPress(false, 0); 651206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 652206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return true; 653206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 654206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov }; 65568f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook 656206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // increment button 657d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (!mHasSelectorWheel) { 658d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mIncrementButton = (ImageButton) findViewById(R.id.increment); 659d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mIncrementButton.setOnClickListener(onClickListener); 660d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mIncrementButton.setOnLongClickListener(onLongClickListener); 661d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } else { 662d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mIncrementButton = null; 663d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 664206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 665206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // decrement button 666d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (!mHasSelectorWheel) { 667d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mDecrementButton = (ImageButton) findViewById(R.id.decrement); 668d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mDecrementButton.setOnClickListener(onClickListener); 669d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mDecrementButton.setOnLongClickListener(onLongClickListener); 670d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } else { 671d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mDecrementButton = null; 672d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 673206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 674206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // input text 675012dd5a461f18a2e5dad38c60282fac1c21ff7feSvetoslav Ganov mInputText = (EditText) findViewById(R.id.numberpicker_input); 676206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mInputText.setOnFocusChangeListener(new OnFocusChangeListener() { 677206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov public void onFocusChange(View v, boolean hasFocus) { 678a53efe9923bedab4fe5d578f32eaff308e5b9e76Svetoslav Ganov if (hasFocus) { 679a53efe9923bedab4fe5d578f32eaff308e5b9e76Svetoslav Ganov mInputText.selectAll(); 680a53efe9923bedab4fe5d578f32eaff308e5b9e76Svetoslav Ganov } else { 681a53efe9923bedab4fe5d578f32eaff308e5b9e76Svetoslav Ganov mInputText.setSelection(0, 0); 682206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov validateInputTextView(v); 68368f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook } 68468f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook } 685206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov }); 686206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mInputText.setFilters(new InputFilter[] { 687206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov new InputTextFilter() 688206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov }); 68968f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook 690206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mInputText.setRawInputType(InputType.TYPE_CLASS_NUMBER); 691a2b41b438d45570867e4682c0caaf93ace5e712eSvetoslav Ganov mInputText.setImeOptions(EditorInfo.IME_ACTION_DONE); 692206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 693206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // initialize constants 694206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov ViewConfiguration configuration = ViewConfiguration.get(context); 695206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mTouchSlop = configuration.getScaledTouchSlop(); 696206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mMinimumFlingVelocity = configuration.getScaledMinimumFlingVelocity(); 697206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mMaximumFlingVelocity = configuration.getScaledMaximumFlingVelocity() 698206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov / SELECTOR_MAX_FLING_VELOCITY_ADJUSTMENT; 699206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mTextSize = (int) mInputText.getTextSize(); 700206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 701206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // create the selector wheel paint 702206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov Paint paint = new Paint(); 703206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov paint.setAntiAlias(true); 704206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov paint.setTextAlign(Align.CENTER); 705206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov paint.setTextSize(mTextSize); 706206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov paint.setTypeface(mInputText.getTypeface()); 707206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov ColorStateList colors = mInputText.getTextColors(); 708206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov int color = colors.getColorForState(ENABLED_STATE_SET, Color.WHITE); 709206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov paint.setColor(color); 710b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov mSelectorWheelPaint = paint; 711206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 712206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // create the fling and adjust scrollers 713bf80562d22b2bbe7944d80d0524c69d0238010cbSvetoslav Ganov mFlingScroller = new Scroller(getContext(), null, true); 7149cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov mAdjustScroller = new Scroller(getContext(), new DecelerateInterpolator(2.5f)); 715fdf6db6748b32f620a7f68b13a67c38b4e59e5edTom Taylor 716206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov updateInputTextView(); 7174213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov 7184213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov // If not explicitly specified this view is important for accessibility. 7194213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov if (getImportantForAccessibility() == IMPORTANT_FOR_ACCESSIBILITY_AUTO) { 7204213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES); 7214213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov } 722206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 723206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 724206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov @Override 7259cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov protected void onLayout(boolean changed, int left, int top, int right, int bottom) { 726d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (!mHasSelectorWheel) { 727d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov super.onLayout(changed, left, top, right, bottom); 728d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return; 729d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 730ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov final int msrdWdth = getMeasuredWidth(); 731ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov final int msrdHght = getMeasuredHeight(); 732ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov 733ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov // Input text centered horizontally. 734ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov final int inptTxtMsrdWdth = mInputText.getMeasuredWidth(); 735ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov final int inptTxtMsrdHght = mInputText.getMeasuredHeight(); 736ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov final int inptTxtLeft = (msrdWdth - inptTxtMsrdWdth) / 2; 737ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov final int inptTxtTop = (msrdHght - inptTxtMsrdHght) / 2; 738ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov final int inptTxtRight = inptTxtLeft + inptTxtMsrdWdth; 739ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov final int inptTxtBottom = inptTxtTop + inptTxtMsrdHght; 740ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov mInputText.layout(inptTxtLeft, inptTxtTop, inptTxtRight, inptTxtBottom); 741ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov 742d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (changed) { 743b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov // need to do all this when we know our size 744b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov initializeSelectorWheel(); 745b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov initializeFadingEdges(); 746d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mTopSelectionDividerTop = (getHeight() - mSelectionDividersDistance) / 2 747d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov - mSelectionDividerHeight; 748d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mBottomSelectionDividerBottom = mTopSelectionDividerTop + 2 * mSelectionDividerHeight 749d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov + mSelectionDividersDistance; 750b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov } 751206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 752206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 753206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov @Override 754e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 755d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (!mHasSelectorWheel) { 756d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov super.onMeasure(widthMeasureSpec, heightMeasureSpec); 757d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return; 758d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 759698e1d5d867a7ac653fa1d6f29cef4cfb73fad38Svetoslav Ganov // Try greedily to fit the max width and height. 760698e1d5d867a7ac653fa1d6f29cef4cfb73fad38Svetoslav Ganov final int newWidthMeasureSpec = makeMeasureSpec(widthMeasureSpec, mMaxWidth); 761698e1d5d867a7ac653fa1d6f29cef4cfb73fad38Svetoslav Ganov final int newHeightMeasureSpec = makeMeasureSpec(heightMeasureSpec, mMaxHeight); 762ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov super.onMeasure(newWidthMeasureSpec, newHeightMeasureSpec); 763698e1d5d867a7ac653fa1d6f29cef4cfb73fad38Svetoslav Ganov // Flag if we are measured with width or height less than the respective min. 7649f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov final int widthSize = resolveSizeAndStateRespectingMinSize(mMinWidth, getMeasuredWidth(), 7659f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov widthMeasureSpec); 7669f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov final int heightSize = resolveSizeAndStateRespectingMinSize(mMinHeight, getMeasuredHeight(), 7679f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov heightMeasureSpec); 768698e1d5d867a7ac653fa1d6f29cef4cfb73fad38Svetoslav Ganov setMeasuredDimension(widthSize, heightSize); 769e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov } 770e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov 771d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov /** 772d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * Move to the final position of a scroller. Ensures to force finish the scroller 773d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * and if it is not at its final position a scroll of the selector wheel is 774d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * performed to fast forward to the final position. 775d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * 776d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * @param scroller The scroller to whose final position to get. 777d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * @return True of the a move was performed, i.e. the scroller was not in final position. 778d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov */ 779d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private boolean moveToFinalScrollerPosition(Scroller scroller) { 780d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov scroller.forceFinished(true); 781d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov int amountToScroll = scroller.getFinalY() - scroller.getCurrY(); 782d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov int futureScrollOffset = (mCurrentScrollOffset + amountToScroll) % mSelectorElementHeight; 783d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov int overshootAdjustment = mInitialScrollOffset - futureScrollOffset; 784d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (overshootAdjustment != 0) { 785d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (Math.abs(overshootAdjustment) > mSelectorElementHeight / 2) { 786d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (overshootAdjustment > 0) { 787d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov overshootAdjustment -= mSelectorElementHeight; 788d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } else { 789d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov overshootAdjustment += mSelectorElementHeight; 790d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 791d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 792d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov amountToScroll += overshootAdjustment; 793d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov scrollBy(0, amountToScroll); 794d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return true; 795d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 796d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return false; 797d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 798d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 799e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov @Override 800206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov public boolean onInterceptTouchEvent(MotionEvent event) { 801d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (!mHasSelectorWheel || !isEnabled()) { 80251c52edad7d40697d7fb2a091f850506fa897643Svetoslav Ganov return false; 80351c52edad7d40697d7fb2a091f850506fa897643Svetoslav Ganov } 804d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov final int action = event.getActionMasked(); 805d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov switch (action) { 806d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov case MotionEvent.ACTION_DOWN: { 807206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov removeAllCallbacks(); 808d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mInputText.setVisibility(View.INVISIBLE); 809d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mLastDownOrMoveEventY = mLastDownEventY = event.getY(); 810d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mLastDownEventTime = event.getEventTime(); 811d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mIngonreMoveEvents = false; 812d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mShowSoftInputOnTap = false; 813232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov // Handle pressed state before any state change. 814232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov if (mLastDownEventY < mTopSelectionDividerTop) { 815232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov if (mScrollState == OnScrollListener.SCROLL_STATE_IDLE) { 816232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov mPressedStateHelper.buttonPressDelayed( 817232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov PressedStateHelper.BUTTON_DECREMENT); 818232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov } 819232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov } else if (mLastDownEventY > mBottomSelectionDividerBottom) { 820232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov if (mScrollState == OnScrollListener.SCROLL_STATE_IDLE) { 821232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov mPressedStateHelper.buttonPressDelayed( 822232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov PressedStateHelper.BUTTON_INCREMENT); 823232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov } 824232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov } 825232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov // Make sure we support flinging inside scrollables. 82683dc45c65988e9b86e156d59f59ede48195ed1d5Svetoslav Ganov getParent().requestDisallowInterceptTouchEvent(true); 827d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (!mFlingScroller.isFinished()) { 828d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mFlingScroller.forceFinished(true); 829d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mAdjustScroller.forceFinished(true); 830d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov onScrollStateChange(OnScrollListener.SCROLL_STATE_IDLE); 831d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } else if (!mAdjustScroller.isFinished()) { 832d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mFlingScroller.forceFinished(true); 833d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mAdjustScroller.forceFinished(true); 834d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } else if (mLastDownEventY < mTopSelectionDividerTop) { 835b52d9729bfb2ef7ad50d9a5125ebf3a8322429a9Svetoslav Ganov hideSoftInput(); 836d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov postChangeCurrentByOneFromLongPress( 837d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov false, ViewConfiguration.getLongPressTimeout()); 838d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } else if (mLastDownEventY > mBottomSelectionDividerBottom) { 839b52d9729bfb2ef7ad50d9a5125ebf3a8322429a9Svetoslav Ganov hideSoftInput(); 840d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov postChangeCurrentByOneFromLongPress( 841d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov true, ViewConfiguration.getLongPressTimeout()); 842d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } else { 843d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mShowSoftInputOnTap = true; 844d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov postBeginSoftInputOnLongPressCommand(); 845206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 846d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return true; 847d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 848206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 849206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return false; 850206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 851206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 852206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov @Override 853d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov public boolean onTouchEvent(MotionEvent event) { 854d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (!isEnabled() || !mHasSelectorWheel) { 85551c52edad7d40697d7fb2a091f850506fa897643Svetoslav Ganov return false; 85651c52edad7d40697d7fb2a091f850506fa897643Svetoslav Ganov } 857206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (mVelocityTracker == null) { 858206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mVelocityTracker = VelocityTracker.obtain(); 859206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 860d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mVelocityTracker.addMovement(event); 861d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov int action = event.getActionMasked(); 862206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov switch (action) { 863d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov case MotionEvent.ACTION_MOVE: { 864d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (mIngonreMoveEvents) { 865d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov break; 866d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 867d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov float currentMoveY = event.getY(); 868d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (mScrollState != OnScrollListener.SCROLL_STATE_TOUCH_SCROLL) { 869206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov int deltaDownY = (int) Math.abs(currentMoveY - mLastDownEventY); 870206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (deltaDownY > mTouchSlop) { 871d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov removeAllCallbacks(); 8729cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov onScrollStateChange(OnScrollListener.SCROLL_STATE_TOUCH_SCROLL); 873206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 874d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } else { 875232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov int deltaMoveY = (int) ((currentMoveY - mLastDownOrMoveEventY)); 876d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov scrollBy(0, deltaMoveY); 877d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov invalidate(); 878206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 879d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mLastDownOrMoveEventY = currentMoveY; 880d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } break; 881d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov case MotionEvent.ACTION_UP: { 882d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov removeBeginSoftInputCommand(); 883d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov removeChangeCurrentByOneFromLongPress(); 884232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov mPressedStateHelper.cancel(); 885206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov VelocityTracker velocityTracker = mVelocityTracker; 886206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov velocityTracker.computeCurrentVelocity(1000, mMaximumFlingVelocity); 887206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov int initialVelocity = (int) velocityTracker.getYVelocity(); 888206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (Math.abs(initialVelocity) > mMinimumFlingVelocity) { 889232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov fling(initialVelocity); 8909cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov onScrollStateChange(OnScrollListener.SCROLL_STATE_FLING); 891206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } else { 892d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov int eventY = (int) event.getY(); 893d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov int deltaMoveY = (int) Math.abs(eventY - mLastDownEventY); 894d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov long deltaTime = event.getEventTime() - mLastDownEventTime; 895d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (deltaMoveY <= mTouchSlop && deltaTime < ViewConfiguration.getTapTimeout()) { 896d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (mShowSoftInputOnTap) { 897d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mShowSoftInputOnTap = false; 898d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov showSoftInput(); 899d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } else { 900d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov int selectorIndexOffset = (eventY / mSelectorElementHeight) 901d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov - SELECTOR_MIDDLE_ITEM_INDEX; 902d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (selectorIndexOffset > 0) { 903d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov changeValueByOne(true); 904232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov mPressedStateHelper.buttonTapped( 905232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov PressedStateHelper.BUTTON_INCREMENT); 906d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } else if (selectorIndexOffset < 0) { 907d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov changeValueByOne(false); 908232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov mPressedStateHelper.buttonTapped( 909232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov PressedStateHelper.BUTTON_DECREMENT); 910d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 911206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 912206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } else { 913d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov ensureScrollWheelAdjusted(); 914206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 915d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov onScrollStateChange(OnScrollListener.SCROLL_STATE_IDLE); 916206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 917206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mVelocityTracker.recycle(); 918206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mVelocityTracker = null; 919d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } break; 920206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 921206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return true; 922206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 923206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 924206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov @Override 925206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov public boolean dispatchTouchEvent(MotionEvent event) { 926b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov final int action = event.getActionMasked(); 927b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov switch (action) { 928b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov case MotionEvent.ACTION_CANCEL: 929b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov case MotionEvent.ACTION_UP: 930b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov removeAllCallbacks(); 931b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov break; 932206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 933206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return super.dispatchTouchEvent(event); 934206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 935206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 936206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov @Override 937206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov public boolean dispatchKeyEvent(KeyEvent event) { 938d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov final int keyCode = event.getKeyCode(); 939d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov switch (keyCode) { 940d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov case KeyEvent.KEYCODE_DPAD_CENTER: 941d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov case KeyEvent.KEYCODE_ENTER: 942d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov removeAllCallbacks(); 943d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov break; 9445dc21d9b340fe2c1cb4c37435d8a29429cf3f79eSvetoslav Ganov case KeyEvent.KEYCODE_DPAD_DOWN: 9455dc21d9b340fe2c1cb4c37435d8a29429cf3f79eSvetoslav Ganov case KeyEvent.KEYCODE_DPAD_UP: 9465dc21d9b340fe2c1cb4c37435d8a29429cf3f79eSvetoslav Ganov if (!mHasSelectorWheel) { 9475dc21d9b340fe2c1cb4c37435d8a29429cf3f79eSvetoslav Ganov break; 9485dc21d9b340fe2c1cb4c37435d8a29429cf3f79eSvetoslav Ganov } 9495dc21d9b340fe2c1cb4c37435d8a29429cf3f79eSvetoslav Ganov switch (event.getAction()) { 9505dc21d9b340fe2c1cb4c37435d8a29429cf3f79eSvetoslav Ganov case KeyEvent.ACTION_DOWN: 95186cf0cdfe14ce9606d42671b2961081f3220a789Justin Mattson if (mWrapSelectorWheel || (keyCode == KeyEvent.KEYCODE_DPAD_DOWN) 9525dc21d9b340fe2c1cb4c37435d8a29429cf3f79eSvetoslav Ganov ? getValue() < getMaxValue() : getValue() > getMinValue()) { 9535dc21d9b340fe2c1cb4c37435d8a29429cf3f79eSvetoslav Ganov requestFocus(); 9545dc21d9b340fe2c1cb4c37435d8a29429cf3f79eSvetoslav Ganov mLastHandledDownDpadKeyCode = keyCode; 9555dc21d9b340fe2c1cb4c37435d8a29429cf3f79eSvetoslav Ganov removeAllCallbacks(); 9565dc21d9b340fe2c1cb4c37435d8a29429cf3f79eSvetoslav Ganov if (mFlingScroller.isFinished()) { 95786cf0cdfe14ce9606d42671b2961081f3220a789Justin Mattson changeValueByOne(keyCode == KeyEvent.KEYCODE_DPAD_DOWN); 9585dc21d9b340fe2c1cb4c37435d8a29429cf3f79eSvetoslav Ganov } 9595dc21d9b340fe2c1cb4c37435d8a29429cf3f79eSvetoslav Ganov return true; 9605dc21d9b340fe2c1cb4c37435d8a29429cf3f79eSvetoslav Ganov } 9615dc21d9b340fe2c1cb4c37435d8a29429cf3f79eSvetoslav Ganov break; 9625dc21d9b340fe2c1cb4c37435d8a29429cf3f79eSvetoslav Ganov case KeyEvent.ACTION_UP: 9635dc21d9b340fe2c1cb4c37435d8a29429cf3f79eSvetoslav Ganov if (mLastHandledDownDpadKeyCode == keyCode) { 9645dc21d9b340fe2c1cb4c37435d8a29429cf3f79eSvetoslav Ganov mLastHandledDownDpadKeyCode = -1; 9655dc21d9b340fe2c1cb4c37435d8a29429cf3f79eSvetoslav Ganov return true; 9665dc21d9b340fe2c1cb4c37435d8a29429cf3f79eSvetoslav Ganov } 9675dc21d9b340fe2c1cb4c37435d8a29429cf3f79eSvetoslav Ganov break; 9685dc21d9b340fe2c1cb4c37435d8a29429cf3f79eSvetoslav Ganov } 969206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 970206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return super.dispatchKeyEvent(event); 971206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 972206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 973206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov @Override 974206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov public boolean dispatchTrackballEvent(MotionEvent event) { 975d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov final int action = event.getActionMasked(); 976d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov switch (action) { 977d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov case MotionEvent.ACTION_CANCEL: 978d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov case MotionEvent.ACTION_UP: 979d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov removeAllCallbacks(); 980d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov break; 981206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 982206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return super.dispatchTrackballEvent(event); 983206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 9849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 985206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov @Override 986d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov protected boolean dispatchHoverEvent(MotionEvent event) { 987d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (!mHasSelectorWheel) { 988d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return super.dispatchHoverEvent(event); 989d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 990d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (AccessibilityManager.getInstance(mContext).isEnabled()) { 991d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov final int eventY = (int) event.getY(); 992d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov final int hoveredVirtualViewId; 993d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (eventY < mTopSelectionDividerTop) { 994d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov hoveredVirtualViewId = AccessibilityNodeProviderImpl.VIRTUAL_VIEW_ID_DECREMENT; 995d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } else if (eventY > mBottomSelectionDividerBottom) { 996d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov hoveredVirtualViewId = AccessibilityNodeProviderImpl.VIRTUAL_VIEW_ID_INCREMENT; 997d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } else { 998d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov hoveredVirtualViewId = AccessibilityNodeProviderImpl.VIRTUAL_VIEW_ID_INPUT; 999d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 1000d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov final int action = event.getActionMasked(); 1001d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov AccessibilityNodeProviderImpl provider = 1002d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov (AccessibilityNodeProviderImpl) getAccessibilityNodeProvider(); 1003d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov switch (action) { 1004d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov case MotionEvent.ACTION_HOVER_ENTER: { 1005d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov provider.sendAccessibilityEventForVirtualView(hoveredVirtualViewId, 1006d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov AccessibilityEvent.TYPE_VIEW_HOVER_ENTER); 1007d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mLastHoveredChildVirtualViewId = hoveredVirtualViewId; 1008791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov provider.performAction(hoveredVirtualViewId, 1009791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS, null); 1010d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } break; 1011d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov case MotionEvent.ACTION_HOVER_MOVE: { 1012d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (mLastHoveredChildVirtualViewId != hoveredVirtualViewId 1013d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov && mLastHoveredChildVirtualViewId != View.NO_ID) { 1014d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov provider.sendAccessibilityEventForVirtualView( 1015d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mLastHoveredChildVirtualViewId, 1016d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov AccessibilityEvent.TYPE_VIEW_HOVER_EXIT); 1017d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov provider.sendAccessibilityEventForVirtualView(hoveredVirtualViewId, 1018d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov AccessibilityEvent.TYPE_VIEW_HOVER_ENTER); 1019d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mLastHoveredChildVirtualViewId = hoveredVirtualViewId; 1020791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov provider.performAction(hoveredVirtualViewId, 1021791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS, null); 1022d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 1023d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } break; 1024d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov case MotionEvent.ACTION_HOVER_EXIT: { 1025d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov provider.sendAccessibilityEventForVirtualView(hoveredVirtualViewId, 1026d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov AccessibilityEvent.TYPE_VIEW_HOVER_EXIT); 1027d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mLastHoveredChildVirtualViewId = View.NO_ID; 1028d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } break; 1029d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 1030206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1031d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return false; 1032d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 1033d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 1034d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov @Override 1035d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov public void computeScroll() { 1036206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov Scroller scroller = mFlingScroller; 1037206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (scroller.isFinished()) { 1038206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov scroller = mAdjustScroller; 1039206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (scroller.isFinished()) { 1040206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return; 1041206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1042206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1043206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov scroller.computeScrollOffset(); 1044206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov int currentScrollerY = scroller.getCurrY(); 1045206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (mPreviousScrollerY == 0) { 1046206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mPreviousScrollerY = scroller.getStartY(); 1047206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1048206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov scrollBy(0, currentScrollerY - mPreviousScrollerY); 1049206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mPreviousScrollerY = currentScrollerY; 1050206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (scroller.isFinished()) { 1051206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov onScrollerFinished(scroller); 1052206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } else { 1053206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov invalidate(); 10549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1056fdf6db6748b32f620a7f68b13a67c38b4e59e5edTom Taylor 10579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 10589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void setEnabled(boolean enabled) { 10599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project super.setEnabled(enabled); 1060d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (!mHasSelectorWheel) { 1061d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mIncrementButton.setEnabled(enabled); 1062d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 1063d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (!mHasSelectorWheel) { 1064d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mDecrementButton.setEnabled(enabled); 1065d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 1066206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mInputText.setEnabled(enabled); 1067206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1068206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 1069206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov @Override 1070206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov public void scrollBy(int x, int y) { 1071b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov int[] selectorIndices = mSelectorIndices; 107234c0688ceafbeef2648bd2287b3b3c3801679448Svetoslav Ganov if (!mWrapSelectorWheel && y > 0 107334c0688ceafbeef2648bd2287b3b3c3801679448Svetoslav Ganov && selectorIndices[SELECTOR_MIDDLE_ITEM_INDEX] <= mMinValue) { 1074206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mCurrentScrollOffset = mInitialScrollOffset; 1075206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return; 1076206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 107734c0688ceafbeef2648bd2287b3b3c3801679448Svetoslav Ganov if (!mWrapSelectorWheel && y < 0 107834c0688ceafbeef2648bd2287b3b3c3801679448Svetoslav Ganov && selectorIndices[SELECTOR_MIDDLE_ITEM_INDEX] >= mMaxValue) { 1079206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mCurrentScrollOffset = mInitialScrollOffset; 1080206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return; 1081206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1082206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mCurrentScrollOffset += y; 1083b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov while (mCurrentScrollOffset - mInitialScrollOffset > mSelectorTextGapHeight) { 1084206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mCurrentScrollOffset -= mSelectorElementHeight; 1085206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov decrementSelectorIndices(selectorIndices); 1086d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov setValueInternal(selectorIndices[SELECTOR_MIDDLE_ITEM_INDEX], true); 1087b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov if (!mWrapSelectorWheel && selectorIndices[SELECTOR_MIDDLE_ITEM_INDEX] <= mMinValue) { 1088206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mCurrentScrollOffset = mInitialScrollOffset; 1089206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1090206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1091b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov while (mCurrentScrollOffset - mInitialScrollOffset < -mSelectorTextGapHeight) { 1092206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mCurrentScrollOffset += mSelectorElementHeight; 1093b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov incrementSelectorIndices(selectorIndices); 1094d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov setValueInternal(selectorIndices[SELECTOR_MIDDLE_ITEM_INDEX], true); 1095b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov if (!mWrapSelectorWheel && selectorIndices[SELECTOR_MIDDLE_ITEM_INDEX] >= mMaxValue) { 1096206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mCurrentScrollOffset = mInitialScrollOffset; 1097206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1098206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 10999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1100fdf6db6748b32f620a7f68b13a67c38b4e59e5edTom Taylor 11014bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov @Override 11024bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov public int getSolidColor() { 11034bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov return mSolidColor; 11044bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov } 11054bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov 110668f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook /** 11074bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * Sets the listener to be notified on change of the current value. 1108206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * 1109e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @param onValueChangedListener The listener. 111068f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook */ 1111cedc446684e94c9971c38c3206f1f224314bda2aSvetoslav Ganov public void setOnValueChangedListener(OnValueChangeListener onValueChangedListener) { 1112cedc446684e94c9971c38c3206f1f224314bda2aSvetoslav Ganov mOnValueChangeListener = onValueChangedListener; 111350f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov } 111450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 111550f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov /** 11164bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * Set listener to be notified for scroll state changes. 111750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * 1118e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @param onScrollListener The listener. 111950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov */ 112050f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov public void setOnScrollListener(OnScrollListener onScrollListener) { 112150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov mOnScrollListener = onScrollListener; 11229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1123fdf6db6748b32f620a7f68b13a67c38b4e59e5edTom Taylor 112468f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook /** 11254bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * Set the formatter to be used for formatting the current value. 11264bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * <p> 1127e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * Note: If you have provided alternative values for the values this 1128e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * formatter is never invoked. 11294bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * </p> 1130206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * 1131e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @param formatter The formatter object. If formatter is <code>null</code>, 1132e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * {@link String#valueOf(int)} will be used. 1133d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov *@see #setDisplayedValues(String[]) 113468f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook */ 11359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void setFormatter(Formatter formatter) { 1136e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov if (formatter == mFormatter) { 1137e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov return; 1138e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov } 11399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mFormatter = formatter; 1140b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov initializeSelectorWheelIndices(); 11419cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov updateInputTextView(); 1142206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1143206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 1144206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 1145e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * Set the current value for the number picker. 11464bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * <p> 1147e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * If the argument is less than the {@link NumberPicker#getMinValue()} and 1148e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * {@link NumberPicker#getWrapSelectorWheel()} is <code>false</code> the 1149e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * current value is set to the {@link NumberPicker#getMinValue()} value. 1150e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * </p> 1151e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * <p> 1152e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * If the argument is less than the {@link NumberPicker#getMinValue()} and 1153e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * {@link NumberPicker#getWrapSelectorWheel()} is <code>true</code> the 1154e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * current value is set to the {@link NumberPicker#getMaxValue()} value. 1155e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * </p> 1156e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * <p> 1157e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * If the argument is less than the {@link NumberPicker#getMaxValue()} and 1158e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * {@link NumberPicker#getWrapSelectorWheel()} is <code>false</code> the 1159e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * current value is set to the {@link NumberPicker#getMaxValue()} value. 1160e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * </p> 1161e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * <p> 1162e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * If the argument is less than the {@link NumberPicker#getMaxValue()} and 1163e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * {@link NumberPicker#getWrapSelectorWheel()} is <code>true</code> the 1164e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * current value is set to the {@link NumberPicker#getMinValue()} value. 11654bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * </p> 1166206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * 1167e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @param value The current value. 11684bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * @see #setWrapSelectorWheel(boolean) 1169e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @see #setMinValue(int) 1170e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @see #setMaxValue(int) 1171206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 1172e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov public void setValue(int value) { 1173d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov setValueInternal(value, false); 11749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1175fdf6db6748b32f620a7f68b13a67c38b4e59e5edTom Taylor 117668f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook /** 1177d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * Shows the soft input for its input text. 1178d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov */ 1179d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private void showSoftInput() { 1180d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov InputMethodManager inputMethodManager = InputMethodManager.peekInstance(); 1181d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (inputMethodManager != null) { 1182d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (mHasSelectorWheel) { 1183d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mInputText.setVisibility(View.VISIBLE); 1184d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 1185d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mInputText.requestFocus(); 1186d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov inputMethodManager.showSoftInput(mInputText, 0); 1187d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 1188d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 1189d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 1190d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov /** 1191d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * Hides the soft input if it is active for the input text. 1192b52d9729bfb2ef7ad50d9a5125ebf3a8322429a9Svetoslav Ganov */ 1193b52d9729bfb2ef7ad50d9a5125ebf3a8322429a9Svetoslav Ganov private void hideSoftInput() { 1194b52d9729bfb2ef7ad50d9a5125ebf3a8322429a9Svetoslav Ganov InputMethodManager inputMethodManager = InputMethodManager.peekInstance(); 1195b52d9729bfb2ef7ad50d9a5125ebf3a8322429a9Svetoslav Ganov if (inputMethodManager != null && inputMethodManager.isActive(mInputText)) { 1196b52d9729bfb2ef7ad50d9a5125ebf3a8322429a9Svetoslav Ganov inputMethodManager.hideSoftInputFromWindow(getWindowToken(), 0); 1197d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (mHasSelectorWheel) { 1198d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mInputText.setVisibility(View.INVISIBLE); 1199d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 1200b52d9729bfb2ef7ad50d9a5125ebf3a8322429a9Svetoslav Ganov } 1201b52d9729bfb2ef7ad50d9a5125ebf3a8322429a9Svetoslav Ganov } 1202b52d9729bfb2ef7ad50d9a5125ebf3a8322429a9Svetoslav Ganov 1203b52d9729bfb2ef7ad50d9a5125ebf3a8322429a9Svetoslav Ganov /** 1204ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov * Computes the max width if no such specified as an attribute. 1205ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov */ 1206ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov private void tryComputeMaxWidth() { 1207ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov if (!mComputeMaxWidth) { 1208ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov return; 1209ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov } 1210ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov int maxTextWidth = 0; 1211ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov if (mDisplayedValues == null) { 1212ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov float maxDigitWidth = 0; 1213ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov for (int i = 0; i <= 9; i++) { 1214d88e3054d08b1f821bb2e27b2647aa16a60d8742Fabrice Di Meglio final float digitWidth = mSelectorWheelPaint.measureText(formatNumberWithLocale(i)); 1215ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov if (digitWidth > maxDigitWidth) { 1216ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov maxDigitWidth = digitWidth; 1217ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov } 1218ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov } 1219ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov int numberOfDigits = 0; 1220ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov int current = mMaxValue; 1221ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov while (current > 0) { 1222ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov numberOfDigits++; 1223ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov current = current / 10; 1224ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov } 1225ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov maxTextWidth = (int) (numberOfDigits * maxDigitWidth); 1226ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov } else { 1227ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov final int valueCount = mDisplayedValues.length; 1228ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov for (int i = 0; i < valueCount; i++) { 1229ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov final float textWidth = mSelectorWheelPaint.measureText(mDisplayedValues[i]); 1230ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov if (textWidth > maxTextWidth) { 1231ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov maxTextWidth = (int) textWidth; 1232ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov } 1233ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov } 1234ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov } 1235ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov maxTextWidth += mInputText.getPaddingLeft() + mInputText.getPaddingRight(); 1236ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov if (mMaxWidth != maxTextWidth) { 1237ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov if (maxTextWidth > mMinWidth) { 1238ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov mMaxWidth = maxTextWidth; 1239ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov } else { 1240ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov mMaxWidth = mMinWidth; 1241ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov } 1242ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov invalidate(); 1243ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov } 1244ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov } 1245ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov 1246ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov /** 1247e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * Gets whether the selector wheel wraps when reaching the min/max value. 124868f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook * 1249e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @return True if the selector wheel wraps. 12504bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * 1251e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @see #getMinValue() 1252e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @see #getMaxValue() 125368f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook */ 1254e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov public boolean getWrapSelectorWheel() { 1255e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov return mWrapSelectorWheel; 1256206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1257206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 1258206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 1259e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * Sets whether the selector wheel shown during flinging/scrolling should 1260e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * wrap around the {@link NumberPicker#getMinValue()} and 1261e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * {@link NumberPicker#getMaxValue()} values. 1262e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * <p> 1263d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * By default if the range (max - min) is more than the number of items shown 1264d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * on the selector wheel the selector wheel wrapping is enabled. 1265e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * </p> 12663f9c9eab7b41c409c3c7b503b89ad340e408b6a0Svetoslav Ganov * <p> 1267d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * <strong>Note:</strong> If the number of items, i.e. the range ( 1268d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * {@link #getMaxValue()} - {@link #getMinValue()}) is less than 1269d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * the number of items shown on the selector wheel, the selector wheel will 1270d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * not wrap. Hence, in such a case calling this method is a NOP. 12713f9c9eab7b41c409c3c7b503b89ad340e408b6a0Svetoslav Ganov * </p> 1272d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * 12736304b0d58e74509a9f21b67b5227b2fee2f1b60fSvetoslav Ganov * @param wrapSelectorWheel Whether to wrap. 1274206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 12756304b0d58e74509a9f21b67b5227b2fee2f1b60fSvetoslav Ganov public void setWrapSelectorWheel(boolean wrapSelectorWheel) { 12763f9c9eab7b41c409c3c7b503b89ad340e408b6a0Svetoslav Ganov final boolean wrappingAllowed = (mMaxValue - mMinValue) >= mSelectorIndices.length; 12773f9c9eab7b41c409c3c7b503b89ad340e408b6a0Svetoslav Ganov if ((!wrapSelectorWheel || wrappingAllowed) && wrapSelectorWheel != mWrapSelectorWheel) { 12786304b0d58e74509a9f21b67b5227b2fee2f1b60fSvetoslav Ganov mWrapSelectorWheel = wrapSelectorWheel; 1279206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 12809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 12834bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * Sets the speed at which the numbers be incremented and decremented when 12844bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * the up and down buttons are long pressed respectively. 1285e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * <p> 1286e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * The default value is 300 ms. 1287e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * </p> 128868f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook * 12894bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * @param intervalMillis The speed (in milliseconds) at which the numbers 1290e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * will be incremented and decremented. 12919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 12924bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov public void setOnLongPressUpdateInterval(long intervalMillis) { 12934bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov mLongPressUpdateInterval = intervalMillis; 12949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1295fdf6db6748b32f620a7f68b13a67c38b4e59e5edTom Taylor 1296206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 1297e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * Returns the value of the picker. 1298e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * 1299e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @return The value. 1300e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov */ 1301e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov public int getValue() { 1302e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov return mValue; 1303e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov } 1304e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov 1305e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov /** 1306e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * Returns the min value of the picker. 1307e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * 1308e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @return The min value 1309e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov */ 1310e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov public int getMinValue() { 1311e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov return mMinValue; 1312e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov } 1313e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov 1314e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov /** 1315e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * Sets the min value of the picker. 1316206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * 13177018cfdc05dc6135949806749ff5c370dce09cedSvetoslav Ganov * @param minValue The min value inclusive. 13187018cfdc05dc6135949806749ff5c370dce09cedSvetoslav Ganov * 13197018cfdc05dc6135949806749ff5c370dce09cedSvetoslav Ganov * <strong>Note:</strong> The length of the displayed values array 13207018cfdc05dc6135949806749ff5c370dce09cedSvetoslav Ganov * set via {@link #setDisplayedValues(String[])} must be equal to the 13217018cfdc05dc6135949806749ff5c370dce09cedSvetoslav Ganov * range of selectable numbers which is equal to 13227018cfdc05dc6135949806749ff5c370dce09cedSvetoslav Ganov * {@link #getMaxValue()} - {@link #getMinValue()} + 1. 1323206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 1324e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov public void setMinValue(int minValue) { 1325e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov if (mMinValue == minValue) { 1326e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov return; 1327e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov } 1328e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov if (minValue < 0) { 1329e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov throw new IllegalArgumentException("minValue must be >= 0"); 1330e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov } 1331e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov mMinValue = minValue; 1332e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov if (mMinValue > mValue) { 1333e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov mValue = mMinValue; 1334e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov } 1335e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov boolean wrapSelectorWheel = mMaxValue - mMinValue > mSelectorIndices.length; 1336e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov setWrapSelectorWheel(wrapSelectorWheel); 1337b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov initializeSelectorWheelIndices(); 1338e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov updateInputTextView(); 1339ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov tryComputeMaxWidth(); 1340d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov invalidate(); 1341206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1342206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 13434bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov /** 1344e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * Returns the max value of the picker. 13454bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * 1346e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @return The max value. 13474bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov */ 1348e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov public int getMaxValue() { 1349e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov return mMaxValue; 13504bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov } 13514bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov 13524bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov /** 1353e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * Sets the max value of the picker. 13544bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * 13557018cfdc05dc6135949806749ff5c370dce09cedSvetoslav Ganov * @param maxValue The max value inclusive. 13567018cfdc05dc6135949806749ff5c370dce09cedSvetoslav Ganov * 13577018cfdc05dc6135949806749ff5c370dce09cedSvetoslav Ganov * <strong>Note:</strong> The length of the displayed values array 13587018cfdc05dc6135949806749ff5c370dce09cedSvetoslav Ganov * set via {@link #setDisplayedValues(String[])} must be equal to the 13597018cfdc05dc6135949806749ff5c370dce09cedSvetoslav Ganov * range of selectable numbers which is equal to 13607018cfdc05dc6135949806749ff5c370dce09cedSvetoslav Ganov * {@link #getMaxValue()} - {@link #getMinValue()} + 1. 13614bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov */ 1362e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov public void setMaxValue(int maxValue) { 1363e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov if (mMaxValue == maxValue) { 1364e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov return; 1365e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov } 1366e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov if (maxValue < 0) { 1367e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov throw new IllegalArgumentException("maxValue must be >= 0"); 1368e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov } 1369e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov mMaxValue = maxValue; 1370e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov if (mMaxValue < mValue) { 1371e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov mValue = mMaxValue; 1372e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov } 1373e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov boolean wrapSelectorWheel = mMaxValue - mMinValue > mSelectorIndices.length; 1374e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov setWrapSelectorWheel(wrapSelectorWheel); 1375b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov initializeSelectorWheelIndices(); 1376e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov updateInputTextView(); 1377ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov tryComputeMaxWidth(); 1378d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov invalidate(); 1379e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov } 1380e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov 1381e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov /** 1382e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * Gets the values to be displayed instead of string values. 1383e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * 1384e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @return The displayed values. 1385e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov */ 1386e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov public String[] getDisplayedValues() { 1387e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov return mDisplayedValues; 1388e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov } 1389e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov 1390e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov /** 1391e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * Sets the values to be displayed. 1392e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * 1393e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @param displayedValues The displayed values. 13947018cfdc05dc6135949806749ff5c370dce09cedSvetoslav Ganov * 13957018cfdc05dc6135949806749ff5c370dce09cedSvetoslav Ganov * <strong>Note:</strong> The length of the displayed values array 13967018cfdc05dc6135949806749ff5c370dce09cedSvetoslav Ganov * must be equal to the range of selectable numbers which is equal to 13977018cfdc05dc6135949806749ff5c370dce09cedSvetoslav Ganov * {@link #getMaxValue()} - {@link #getMinValue()} + 1. 1398e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov */ 1399e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov public void setDisplayedValues(String[] displayedValues) { 1400e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov if (mDisplayedValues == displayedValues) { 1401e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov return; 1402e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov } 1403e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov mDisplayedValues = displayedValues; 1404e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov if (mDisplayedValues != null) { 1405e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov // Allow text entry rather than strictly numeric entry. 1406e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov mInputText.setRawInputType(InputType.TYPE_CLASS_TEXT 1407e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov | InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS); 1408e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov } else { 1409e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov mInputText.setRawInputType(InputType.TYPE_CLASS_NUMBER); 1410e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov } 1411e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov updateInputTextView(); 1412b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov initializeSelectorWheelIndices(); 14139f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov tryComputeMaxWidth(); 1414206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1415206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 1416206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov @Override 1417206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov protected float getTopFadingEdgeStrength() { 1418206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return TOP_AND_BOTTOM_FADING_EDGE_STRENGTH; 1419206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1420206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 1421206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov @Override 1422206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov protected float getBottomFadingEdgeStrength() { 1423206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return TOP_AND_BOTTOM_FADING_EDGE_STRENGTH; 1424206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1425206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 1426206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov @Override 1427206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov protected void onDetachedFromWindow() { 1428206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov removeAllCallbacks(); 1429206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1430206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 1431206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov @Override 1432206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov protected void onDraw(Canvas canvas) { 1433d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (!mHasSelectorWheel) { 1434d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov super.onDraw(canvas); 1435206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return; 1436206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1437206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov float x = (mRight - mLeft) / 2; 1438206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov float y = mCurrentScrollOffset; 1439206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 1440232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov // draw the virtual buttons pressed state if needed 1441232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov if (mVirtualButtonPressedDrawable != null 1442232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov && mScrollState == OnScrollListener.SCROLL_STATE_IDLE) { 1443232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov if (mDecrementVirtualButtonPressed) { 1444232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov mVirtualButtonPressedDrawable.setState(PRESSED_STATE_SET); 1445232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov mVirtualButtonPressedDrawable.setBounds(0, 0, mRight, mTopSelectionDividerTop); 1446232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov mVirtualButtonPressedDrawable.draw(canvas); 1447232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov } 1448232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov if (mIncrementVirtualButtonPressed) { 1449232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov mVirtualButtonPressedDrawable.setState(PRESSED_STATE_SET); 1450232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov mVirtualButtonPressedDrawable.setBounds(0, mBottomSelectionDividerBottom, mRight, 1451232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov mBottom); 1452232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov mVirtualButtonPressedDrawable.draw(canvas); 1453232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov } 1454232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov } 1455232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov 14569cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov // draw the selector wheel 1457b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov int[] selectorIndices = mSelectorIndices; 1458206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov for (int i = 0; i < selectorIndices.length; i++) { 1459206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov int selectorIndex = selectorIndices[i]; 1460206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov String scrollSelectorValue = mSelectorIndexToStringCache.get(selectorIndex); 1461d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov // Do not draw the middle item if input is visible since the input 1462d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov // is shown only if the wheel is static and it covers the middle 1463d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov // item. Otherwise, if the user starts editing the text via the 1464d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov // IME he may see a dimmed version of the old value intermixed 1465d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov // with the new one. 14666304b0d58e74509a9f21b67b5227b2fee2f1b60fSvetoslav Ganov if (i != SELECTOR_MIDDLE_ITEM_INDEX || mInputText.getVisibility() != VISIBLE) { 14676304b0d58e74509a9f21b67b5227b2fee2f1b60fSvetoslav Ganov canvas.drawText(scrollSelectorValue, x, y, mSelectorWheelPaint); 14686304b0d58e74509a9f21b67b5227b2fee2f1b60fSvetoslav Ganov } 1469206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov y += mSelectorElementHeight; 1470206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 14719cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov 1472d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov // draw the selection dividers 14739cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov if (mSelectionDivider != null) { 14749cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov // draw the top divider 1475d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov int topOfTopDivider = mTopSelectionDividerTop; 14769cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov int bottomOfTopDivider = topOfTopDivider + mSelectionDividerHeight; 14779cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov mSelectionDivider.setBounds(0, topOfTopDivider, mRight, bottomOfTopDivider); 14789cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov mSelectionDivider.draw(canvas); 14799cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov 14809cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov // draw the bottom divider 1481d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov int bottomOfBottomDivider = mBottomSelectionDividerBottom; 1482d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov int topOfBottomDivider = bottomOfBottomDivider - mSelectionDividerHeight; 14839cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov mSelectionDivider.setBounds(0, topOfBottomDivider, mRight, bottomOfBottomDivider); 14849cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov mSelectionDivider.draw(canvas); 14859cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov } 14869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1487fdf6db6748b32f620a7f68b13a67c38b4e59e5edTom Taylor 14883fec3fe0e3a83c5e0d1264f34bcc55b158537bc6Svetoslav Ganov @Override 14898a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov public void onInitializeAccessibilityEvent(AccessibilityEvent event) { 14908a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov super.onInitializeAccessibilityEvent(event); 14918a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov event.setClassName(NumberPicker.class.getName()); 1492d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov event.setScrollable(true); 1493d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov event.setScrollY((mMinValue + mValue) * mSelectorElementHeight); 1494d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov event.setMaxScrollY((mMaxValue - mMinValue) * mSelectorElementHeight); 14958a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov } 14968a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov 14978a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov @Override 1498d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov public AccessibilityNodeProvider getAccessibilityNodeProvider() { 1499d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (!mHasSelectorWheel) { 1500d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return super.getAccessibilityNodeProvider(); 1501d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 1502d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (mAccessibilityNodeProvider == null) { 1503d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mAccessibilityNodeProvider = new AccessibilityNodeProviderImpl(); 1504d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 1505d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return mAccessibilityNodeProvider; 15068a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov } 15078a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov 150868f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook /** 1509ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov * Makes a measure spec that tries greedily to use the max value. 1510e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov * 1511e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov * @param measureSpec The measure spec. 1512698e1d5d867a7ac653fa1d6f29cef4cfb73fad38Svetoslav Ganov * @param maxSize The max value for the size. 1513ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov * @return A measure spec greedily imposing the max size. 1514e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov */ 1515698e1d5d867a7ac653fa1d6f29cef4cfb73fad38Svetoslav Ganov private int makeMeasureSpec(int measureSpec, int maxSize) { 15169f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov if (maxSize == SIZE_UNSPECIFIED) { 15179f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov return measureSpec; 15189f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov } 1519ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov final int size = MeasureSpec.getSize(measureSpec); 1520e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov final int mode = MeasureSpec.getMode(measureSpec); 1521e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov switch (mode) { 1522e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov case MeasureSpec.EXACTLY: 1523ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov return measureSpec; 1524e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov case MeasureSpec.AT_MOST: 1525698e1d5d867a7ac653fa1d6f29cef4cfb73fad38Svetoslav Ganov return MeasureSpec.makeMeasureSpec(Math.min(size, maxSize), MeasureSpec.EXACTLY); 1526e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov case MeasureSpec.UNSPECIFIED: 1527698e1d5d867a7ac653fa1d6f29cef4cfb73fad38Svetoslav Ganov return MeasureSpec.makeMeasureSpec(maxSize, MeasureSpec.EXACTLY); 1528e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov default: 1529ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov throw new IllegalArgumentException("Unknown measure mode: " + mode); 1530e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov } 1531e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov } 1532e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov 1533e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov /** 1534d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * Utility to reconcile a desired size and state, with constraints imposed 1535d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * by a MeasureSpec. Tries to respect the min size, unless a different size 1536d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * is imposed by the constraints. 15379f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov * 15389f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov * @param minSize The minimal desired size. 15399f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov * @param measuredSize The currently measured size. 15409f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov * @param measureSpec The current measure spec. 15419f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov * @return The resolved size and state. 15429f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov */ 1543d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private int resolveSizeAndStateRespectingMinSize( 1544d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov int minSize, int measuredSize, int measureSpec) { 15459f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov if (minSize != SIZE_UNSPECIFIED) { 15469f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov final int desiredWidth = Math.max(minSize, measuredSize); 15479f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov return resolveSizeAndState(desiredWidth, measureSpec, 0); 15489f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov } else { 15499f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov return measuredSize; 15509f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov } 15519f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov } 15529f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov 15539f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov /** 1554d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * Resets the selector indices and clear the cached string representation of 1555d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * these indices. 1556a911d4a2b1be7e9ea909a579167826e4a5bac1a3Svetoslav Ganov */ 1557b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov private void initializeSelectorWheelIndices() { 1558a911d4a2b1be7e9ea909a579167826e4a5bac1a3Svetoslav Ganov mSelectorIndexToStringCache.clear(); 1559232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov int[] selectorIndices = mSelectorIndices; 1560b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov int current = getValue(); 1561b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov for (int i = 0; i < mSelectorIndices.length; i++) { 1562b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov int selectorIndex = current + (i - SELECTOR_MIDDLE_ITEM_INDEX); 1563b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov if (mWrapSelectorWheel) { 1564b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov selectorIndex = getWrappedSelectorIndex(selectorIndex); 1565b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov } 1566232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov selectorIndices[i] = selectorIndex; 1567232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov ensureCachedScrollSelectorValue(selectorIndices[i]); 1568a911d4a2b1be7e9ea909a579167826e4a5bac1a3Svetoslav Ganov } 1569a911d4a2b1be7e9ea909a579167826e4a5bac1a3Svetoslav Ganov } 1570a911d4a2b1be7e9ea909a579167826e4a5bac1a3Svetoslav Ganov 1571a911d4a2b1be7e9ea909a579167826e4a5bac1a3Svetoslav Ganov /** 1572d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * Sets the current value of this NumberPicker. 157368f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook * 1574d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * @param current The new value of the NumberPicker. 1575d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * @param notifyChange Whether to notify if the current value changed. 157668f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook */ 1577d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private void setValueInternal(int current, boolean notifyChange) { 1578e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov if (mValue == current) { 1579206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return; 1580206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 15819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Wrap around the values if we go past the start or end 1582e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov if (mWrapSelectorWheel) { 1583206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov current = getWrappedSelectorIndex(current); 1584d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } else { 1585d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov current = Math.max(current, mMinValue); 1586d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov current = Math.min(current, mMaxValue); 15879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1588e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov int previous = mValue; 1589d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mValue = current; 1590d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov updateInputTextView(); 1591d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (notifyChange) { 1592d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov notifyChange(previous, current); 1593d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 1594fac14f9731ce7fc765de582c983af751aab697deSvetoslav Ganov initializeSelectorWheelIndices(); 1595fac14f9731ce7fc765de582c983af751aab697deSvetoslav Ganov invalidate(); 15969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1597fdf6db6748b32f620a7f68b13a67c38b4e59e5edTom Taylor 159868f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook /** 1599b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov * Changes the current value by one which is increment or 1600b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov * decrement based on the passes argument. 1601d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * decrement the current value. 1602b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov * 1603b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov * @param increment True to increment, false to decrement. 1604b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov */ 1605d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private void changeValueByOne(boolean increment) { 1606d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (mHasSelectorWheel) { 1607b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov mInputText.setVisibility(View.INVISIBLE); 1608d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (!moveToFinalScrollerPosition(mFlingScroller)) { 1609d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov moveToFinalScrollerPosition(mAdjustScroller); 1610d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 1611b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov mPreviousScrollerY = 0; 1612b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov if (increment) { 1613fe41ce4ef97e7da585fdbf06988da8047e72b9f6Svetoslav Ganov mFlingScroller.startScroll(0, 0, 0, -mSelectorElementHeight, SNAP_SCROLL_DURATION); 1614b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov } else { 1615fe41ce4ef97e7da585fdbf06988da8047e72b9f6Svetoslav Ganov mFlingScroller.startScroll(0, 0, 0, mSelectorElementHeight, SNAP_SCROLL_DURATION); 1616b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov } 1617b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov invalidate(); 1618b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov } else { 1619b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov if (increment) { 1620d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov setValueInternal(mValue + 1, true); 1621b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov } else { 1622d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov setValueInternal(mValue - 1, true); 1623b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov } 1624b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov } 1625b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov } 1626b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov 1627b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov private void initializeSelectorWheel() { 1628b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov initializeSelectorWheelIndices(); 1629b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov int[] selectorIndices = mSelectorIndices; 16309cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov int totalTextHeight = selectorIndices.length * mTextSize; 163101fa0d7aae1a551e1e7cfb90d2aeaf2fcb3978afSvetoslav Ganov float totalTextGapHeight = (mBottom - mTop) - totalTextHeight; 1632d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov float textGapCount = selectorIndices.length; 1633b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov mSelectorTextGapHeight = (int) (totalTextGapHeight / textGapCount + 0.5f); 1634b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov mSelectorElementHeight = mTextSize + mSelectorTextGapHeight; 1635d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov // Ensure that the middle item is positioned the same as the text in 1636d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov // mInputText 1637eeafd4296b7cf4c2ad9c985562f6d70e2a3ffc03Chet Haase int editTextTextPosition = mInputText.getBaseline() + mInputText.getTop(); 1638d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mInitialScrollOffset = editTextTextPosition 1639d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov - (mSelectorElementHeight * SELECTOR_MIDDLE_ITEM_INDEX); 16406a19fcde07527706c2a9175e0b9f2a71549b7ffeSvetoslav Ganov mCurrentScrollOffset = mInitialScrollOffset; 16419cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov updateInputTextView(); 16429cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov } 16439cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov 1644b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov private void initializeFadingEdges() { 1645b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov setVerticalFadingEdgeEnabled(true); 1646b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov setFadingEdgeLength((mBottom - mTop - mTextSize) / 2); 1647b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov } 1648b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov 1649206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 1650206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Callback invoked upon completion of a given <code>scroller</code>. 1651206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 1652206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private void onScrollerFinished(Scroller scroller) { 1653206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (scroller == mFlingScroller) { 1654d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (!ensureScrollWheelAdjusted()) { 1655b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov updateInputTextView(); 1656b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov } 1657d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov onScrollStateChange(OnScrollListener.SCROLL_STATE_IDLE); 16589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 1659d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (mScrollState != OnScrollListener.SCROLL_STATE_TOUCH_SCROLL) { 1660d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov updateInputTextView(); 1661d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 16629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1664fdf6db6748b32f620a7f68b13a67c38b4e59e5edTom Taylor 1665206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 16669cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov * Handles transition to a given <code>scrollState</code> 166750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov */ 16689cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov private void onScrollStateChange(int scrollState) { 16699cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov if (mScrollState == scrollState) { 16709cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov return; 16719cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov } 16729cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov mScrollState = scrollState; 16739cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov if (mOnScrollListener != null) { 16744bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov mOnScrollListener.onScrollStateChange(this, scrollState); 167550f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov } 167650f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov } 167750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 167850f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov /** 1679206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Flings the selector with the given <code>velocityY</code>. 1680206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 1681206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private void fling(int velocityY) { 1682206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mPreviousScrollerY = 0; 1683206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 1684234484a9fb53786aa8b7ed2a3df7e24d41817689Svetoslav Ganov if (velocityY > 0) { 1685234484a9fb53786aa8b7ed2a3df7e24d41817689Svetoslav Ganov mFlingScroller.fling(0, 0, 0, velocityY, 0, 0, 0, Integer.MAX_VALUE); 1686206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } else { 1687234484a9fb53786aa8b7ed2a3df7e24d41817689Svetoslav Ganov mFlingScroller.fling(0, Integer.MAX_VALUE, 0, velocityY, 0, 0, 0, Integer.MAX_VALUE); 16889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1689206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 1690206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov invalidate(); 16919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1693206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 1694206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * @return The wrapped index <code>selectorIndex</code> value. 169568f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook */ 1696206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private int getWrappedSelectorIndex(int selectorIndex) { 1697e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov if (selectorIndex > mMaxValue) { 1698e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov return mMinValue + (selectorIndex - mMaxValue) % (mMaxValue - mMinValue) - 1; 1699e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov } else if (selectorIndex < mMinValue) { 1700e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov return mMaxValue - (mMinValue - selectorIndex) % (mMaxValue - mMinValue) + 1; 1701206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1702206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return selectorIndex; 17039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1704fdf6db6748b32f620a7f68b13a67c38b4e59e5edTom Taylor 1705206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 1706206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Increments the <code>selectorIndices</code> whose string representations 1707206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * will be displayed in the selector. 1708206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 1709b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov private void incrementSelectorIndices(int[] selectorIndices) { 1710206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov for (int i = 0; i < selectorIndices.length - 1; i++) { 1711206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov selectorIndices[i] = selectorIndices[i + 1]; 1712206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1713206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov int nextScrollSelectorIndex = selectorIndices[selectorIndices.length - 2] + 1; 1714e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov if (mWrapSelectorWheel && nextScrollSelectorIndex > mMaxValue) { 1715e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov nextScrollSelectorIndex = mMinValue; 1716206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1717206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov selectorIndices[selectorIndices.length - 1] = nextScrollSelectorIndex; 1718206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov ensureCachedScrollSelectorValue(nextScrollSelectorIndex); 1719206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1720fdf6db6748b32f620a7f68b13a67c38b4e59e5edTom Taylor 1721206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 1722206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Decrements the <code>selectorIndices</code> whose string representations 1723206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * will be displayed in the selector. 1724206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 1725206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private void decrementSelectorIndices(int[] selectorIndices) { 1726206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov for (int i = selectorIndices.length - 1; i > 0; i--) { 1727206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov selectorIndices[i] = selectorIndices[i - 1]; 1728206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1729206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov int nextScrollSelectorIndex = selectorIndices[1] - 1; 1730e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov if (mWrapSelectorWheel && nextScrollSelectorIndex < mMinValue) { 1731e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov nextScrollSelectorIndex = mMaxValue; 1732206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1733206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov selectorIndices[0] = nextScrollSelectorIndex; 1734206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov ensureCachedScrollSelectorValue(nextScrollSelectorIndex); 1735206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1736fdf6db6748b32f620a7f68b13a67c38b4e59e5edTom Taylor 1737206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 1738206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Ensures we have a cached string representation of the given <code> 1739d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * selectorIndex</code> to avoid multiple instantiations of the same string. 1740206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 1741206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private void ensureCachedScrollSelectorValue(int selectorIndex) { 1742206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov SparseArray<String> cache = mSelectorIndexToStringCache; 1743206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov String scrollSelectorValue = cache.get(selectorIndex); 1744206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (scrollSelectorValue != null) { 1745206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return; 1746206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1747e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov if (selectorIndex < mMinValue || selectorIndex > mMaxValue) { 1748206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov scrollSelectorValue = ""; 1749206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } else { 1750206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (mDisplayedValues != null) { 1751e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov int displayedValueIndex = selectorIndex - mMinValue; 175250f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov scrollSelectorValue = mDisplayedValues[displayedValueIndex]; 1753206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } else { 1754206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov scrollSelectorValue = formatNumber(selectorIndex); 17559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 17569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1757206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov cache.put(selectorIndex, scrollSelectorValue); 17589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1759fdf6db6748b32f620a7f68b13a67c38b4e59e5edTom Taylor 1760206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private String formatNumber(int value) { 1761d88e3054d08b1f821bb2e27b2647aa16a60d8742Fabrice Di Meglio return (mFormatter != null) ? mFormatter.format(value) : formatNumberWithLocale(value); 1762206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 17639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1764206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private void validateInputTextView(View v) { 1765206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov String str = String.valueOf(((TextView) v).getText()); 1766206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (TextUtils.isEmpty(str)) { 1767206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // Restore to the old value as we don't allow empty values 1768206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov updateInputTextView(); 1769206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } else { 1770206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // Check the new value and ensure it's in range 1771206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov int current = getSelectedPos(str.toString()); 1772d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov setValueInternal(current, true); 17739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1774206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1775fdf6db6748b32f620a7f68b13a67c38b4e59e5edTom Taylor 1776206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 1777206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Updates the view of this NumberPicker. If displayValues were specified in 17789cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov * the string corresponding to the index specified by the current value will 17799cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov * be returned. Otherwise, the formatter specified in {@link #setFormatter} 17809cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov * will be used to format the number. 1781d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * 1782d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * @return Whether the text was updated. 1783206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 1784d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private boolean updateInputTextView() { 1785206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /* 1786206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * If we don't have displayed values then use the current number else 1787206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * find the correct value in the displayed values for the current 1788206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * number. 1789206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 1790d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov String text = (mDisplayedValues == null) ? formatNumber(mValue) 1791d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov : mDisplayedValues[mValue - mMinValue]; 1792d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (!TextUtils.isEmpty(text) && !text.equals(mInputText.getText().toString())) { 1793d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mInputText.setText(text); 1794d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return true; 17959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 17963fec3fe0e3a83c5e0d1264f34bcc55b158537bc6Svetoslav Ganov 1797d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return false; 1798206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1799fdf6db6748b32f620a7f68b13a67c38b4e59e5edTom Taylor 1800206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 1801206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Notifies the listener, if registered, of a change of the value of this 1802206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * NumberPicker. 1803206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 1804206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private void notifyChange(int previous, int current) { 1805cedc446684e94c9971c38c3206f1f224314bda2aSvetoslav Ganov if (mOnValueChangeListener != null) { 1806cedc446684e94c9971c38c3206f1f224314bda2aSvetoslav Ganov mOnValueChangeListener.onValueChange(this, previous, mValue); 1807206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1808206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 18099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1810206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 1811b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov * Posts a command for changing the current value by one. 1812b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov * 1813b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov * @param increment Whether to increment or decrement the value. 1814206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 1815d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private void postChangeCurrentByOneFromLongPress(boolean increment, long delayMillis) { 1816b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov if (mChangeCurrentByOneFromLongPressCommand == null) { 1817b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov mChangeCurrentByOneFromLongPressCommand = new ChangeCurrentByOneFromLongPressCommand(); 1818d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } else { 1819d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov removeCallbacks(mChangeCurrentByOneFromLongPressCommand); 1820d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 1821d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mChangeCurrentByOneFromLongPressCommand.setStep(increment); 1822d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov postDelayed(mChangeCurrentByOneFromLongPressCommand, delayMillis); 1823d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 1824d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 1825d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov /** 1826d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * Removes the command for changing the current value by one. 1827d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov */ 1828d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private void removeChangeCurrentByOneFromLongPress() { 1829d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (mChangeCurrentByOneFromLongPressCommand != null) { 1830d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov removeCallbacks(mChangeCurrentByOneFromLongPressCommand); 1831d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 1832d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 1833d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 1834d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov /** 1835d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * Posts a command for beginning an edit of the current value via IME on 1836d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * long press. 1837d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov */ 1838d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private void postBeginSoftInputOnLongPressCommand() { 1839d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (mBeginSoftInputOnLongPressCommand == null) { 1840d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mBeginSoftInputOnLongPressCommand = new BeginSoftInputOnLongPressCommand(); 1841d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } else { 1842d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov removeCallbacks(mBeginSoftInputOnLongPressCommand); 1843d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 1844d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov postDelayed(mBeginSoftInputOnLongPressCommand, ViewConfiguration.getLongPressTimeout()); 1845d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 1846d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 1847d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov /** 1848d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * Removes the command for beginning an edit of the current value via IME. 1849d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov */ 1850d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private void removeBeginSoftInputCommand() { 1851d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (mBeginSoftInputOnLongPressCommand != null) { 1852d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov removeCallbacks(mBeginSoftInputOnLongPressCommand); 1853206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1854206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 18559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1856206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 1857206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Removes all pending callback from the message queue. 1858206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 1859206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private void removeAllCallbacks() { 1860b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov if (mChangeCurrentByOneFromLongPressCommand != null) { 1861b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov removeCallbacks(mChangeCurrentByOneFromLongPressCommand); 1862206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1863206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (mSetSelectionCommand != null) { 1864206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov removeCallbacks(mSetSelectionCommand); 18659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1866d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (mBeginSoftInputOnLongPressCommand != null) { 1867d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov removeCallbacks(mBeginSoftInputOnLongPressCommand); 1868d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 1869232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov mPressedStateHelper.cancel(); 18709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 18719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1872206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 1873206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * @return The selected index given its displayed <code>value</code>. 1874206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 1875206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private int getSelectedPos(String value) { 18769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mDisplayedValues == null) { 1877aa516beb79693ceffbd81a7c9d14c940e412cccbRomain Guy try { 1878206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return Integer.parseInt(value); 1879aa516beb79693ceffbd81a7c9d14c940e412cccbRomain Guy } catch (NumberFormatException e) { 1880206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // Ignore as if it's not a number we don't care 1881aa516beb79693ceffbd81a7c9d14c940e412cccbRomain Guy } 18829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 18839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < mDisplayedValues.length; i++) { 1884206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // Don't force the user to type in jan when ja will do 1885206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov value = value.toLowerCase(); 1886206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (mDisplayedValues[i].toLowerCase().startsWith(value)) { 1887e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov return mMinValue + i; 18889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 18899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1890fdf6db6748b32f620a7f68b13a67c38b4e59e5edTom Taylor 1891206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /* 1892206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * The user might have typed in a number into the month field i.e. 18939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 10 instead of OCT so support that too. 18949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 18959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 1896206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return Integer.parseInt(value); 18979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (NumberFormatException e) { 1898fdf6db6748b32f620a7f68b13a67c38b4e59e5edTom Taylor 1899206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // Ignore as if it's not a number we don't care 19009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 19019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1902e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov return mMinValue; 19039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 19049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 19059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1906206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Posts an {@link SetSelectionCommand} from the given <code>selectionStart 1907d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * </code> to <code>selectionEnd</code>. 19089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1909206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private void postSetSelectionCommand(int selectionStart, int selectionEnd) { 1910206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (mSetSelectionCommand == null) { 1911206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mSetSelectionCommand = new SetSelectionCommand(); 1912206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } else { 1913206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov removeCallbacks(mSetSelectionCommand); 1914206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1915206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mSetSelectionCommand.mSelectionStart = selectionStart; 1916206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mSetSelectionCommand.mSelectionEnd = selectionEnd; 1917206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov post(mSetSelectionCommand); 19189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 191968f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook 192068f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook /** 1921d88e3054d08b1f821bb2e27b2647aa16a60d8742Fabrice Di Meglio * The numbers accepted by the input text's {@link Filter} 1922d88e3054d08b1f821bb2e27b2647aa16a60d8742Fabrice Di Meglio */ 1923d88e3054d08b1f821bb2e27b2647aa16a60d8742Fabrice Di Meglio private static final char[] DIGIT_CHARACTERS = new char[] { 1924d88e3054d08b1f821bb2e27b2647aa16a60d8742Fabrice Di Meglio // Latin digits are the common case 1925d88e3054d08b1f821bb2e27b2647aa16a60d8742Fabrice Di Meglio '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 1926d88e3054d08b1f821bb2e27b2647aa16a60d8742Fabrice Di Meglio // Arabic-Indic 1927d88e3054d08b1f821bb2e27b2647aa16a60d8742Fabrice Di Meglio '\u0660', '\u0661', '\u0662', '\u0663', '\u0664', '\u0665', '\u0666', '\u0667', '\u0668' 1928d88e3054d08b1f821bb2e27b2647aa16a60d8742Fabrice Di Meglio , '\u0669', 1929d88e3054d08b1f821bb2e27b2647aa16a60d8742Fabrice Di Meglio // Extended Arabic-Indic 1930d88e3054d08b1f821bb2e27b2647aa16a60d8742Fabrice Di Meglio '\u06f0', '\u06f1', '\u06f2', '\u06f3', '\u06f4', '\u06f5', '\u06f6', '\u06f7', '\u06f8' 1931d88e3054d08b1f821bb2e27b2647aa16a60d8742Fabrice Di Meglio , '\u06f9' 1932d88e3054d08b1f821bb2e27b2647aa16a60d8742Fabrice Di Meglio }; 1933d88e3054d08b1f821bb2e27b2647aa16a60d8742Fabrice Di Meglio 1934d88e3054d08b1f821bb2e27b2647aa16a60d8742Fabrice Di Meglio /** 1935206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Filter for accepting only valid indices or prefixes of the string 1936206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * representation of valid indices. 193768f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook */ 1938206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov class InputTextFilter extends NumberKeyListener { 1939206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 1940206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // XXX This doesn't allow for range limits when controlled by a 1941206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // soft input method! 1942206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov public int getInputType() { 1943206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return InputType.TYPE_CLASS_TEXT; 1944206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1945206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 1946206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov @Override 1947206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov protected char[] getAcceptedChars() { 1948206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return DIGIT_CHARACTERS; 1949206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1950206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 1951206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov @Override 1952d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov public CharSequence filter( 1953d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov CharSequence source, int start, int end, Spanned dest, int dstart, int dend) { 1954206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (mDisplayedValues == null) { 1955206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov CharSequence filtered = super.filter(source, start, end, dest, dstart, dend); 1956206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (filtered == null) { 1957206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov filtered = source.subSequence(start, end); 1958206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1959206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 1960206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov String result = String.valueOf(dest.subSequence(0, dstart)) + filtered 1961206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov + dest.subSequence(dend, dest.length()); 1962206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 1963206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if ("".equals(result)) { 1964206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return result; 1965206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1966206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov int val = getSelectedPos(result); 1967206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 1968206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /* 1969206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Ensure the user can't type in a value greater than the max 1970206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * allowed. We have to allow less than min as the user might 1971206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * want to delete some numbers and then type a new number. 19726d8a99fecc5dd3aec502c0419af61e8d2a3c398dSungmin Choi * And prevent multiple-"0" that exceeds the length of upper 19736d8a99fecc5dd3aec502c0419af61e8d2a3c398dSungmin Choi * bound number. 1974206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 19756d8a99fecc5dd3aec502c0419af61e8d2a3c398dSungmin Choi if (val > mMaxValue || result.length() > String.valueOf(mMaxValue).length()) { 1976206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return ""; 1977206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } else { 1978206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return filtered; 1979206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1980206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } else { 1981206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov CharSequence filtered = String.valueOf(source.subSequence(start, end)); 1982206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (TextUtils.isEmpty(filtered)) { 1983206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return ""; 1984206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1985206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov String result = String.valueOf(dest.subSequence(0, dstart)) + filtered 1986206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov + dest.subSequence(dend, dest.length()); 1987206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov String str = String.valueOf(result).toLowerCase(); 1988206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov for (String val : mDisplayedValues) { 1989206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov String valLowerCase = val.toLowerCase(); 1990206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (valLowerCase.startsWith(str)) { 1991206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov postSetSelectionCommand(result.length(), val.length()); 1992206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return val.subSequence(dstart, val.length()); 1993206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1994206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1995206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return ""; 1996206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1997206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1998206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1999206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 2000206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 2001d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * Ensures that the scroll wheel is adjusted i.e. there is no offset and the 2002d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * middle element is in the middle of the widget. 2003d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * 2004d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * @return Whether an adjustment has been made. 2005d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov */ 2006d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private boolean ensureScrollWheelAdjusted() { 2007d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov // adjust to the closest value 2008d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov int deltaY = mInitialScrollOffset - mCurrentScrollOffset; 2009d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (deltaY != 0) { 2010d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mPreviousScrollerY = 0; 2011d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (Math.abs(deltaY) > mSelectorElementHeight / 2) { 2012d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov deltaY += (deltaY > 0) ? -mSelectorElementHeight : mSelectorElementHeight; 2013d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2014d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mAdjustScroller.startScroll(0, 0, 0, deltaY, SELECTOR_ADJUSTMENT_DURATION_MILLIS); 2015d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov invalidate(); 2016d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return true; 2017d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2018d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return false; 2019d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2020d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 2021232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov class PressedStateHelper implements Runnable { 2022232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov public static final int BUTTON_INCREMENT = 1; 2023232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov public static final int BUTTON_DECREMENT = 2; 2024232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov 2025232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov private final int MODE_PRESS = 1; 2026232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov private final int MODE_TAPPED = 2; 2027232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov 2028232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov private int mManagedButton; 2029232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov private int mMode; 2030232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov 2031232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov public void cancel() { 2032232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov mMode = 0; 2033232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov mManagedButton = 0; 2034232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov NumberPicker.this.removeCallbacks(this); 2035232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov if (mIncrementVirtualButtonPressed) { 2036232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov mIncrementVirtualButtonPressed = false; 2037232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov invalidate(0, mBottomSelectionDividerBottom, mRight, mBottom); 2038232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov } 2039232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov mDecrementVirtualButtonPressed = false; 2040232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov if (mDecrementVirtualButtonPressed) { 2041232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov invalidate(0, 0, mRight, mTopSelectionDividerTop); 2042fe41ce4ef97e7da585fdbf06988da8047e72b9f6Svetoslav Ganov } 2043fe41ce4ef97e7da585fdbf06988da8047e72b9f6Svetoslav Ganov } 2044fe41ce4ef97e7da585fdbf06988da8047e72b9f6Svetoslav Ganov 2045232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov public void buttonPressDelayed(int button) { 2046232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov cancel(); 2047232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov mMode = MODE_PRESS; 2048232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov mManagedButton = button; 2049232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov NumberPicker.this.postDelayed(this, ViewConfiguration.getTapTimeout()); 2050232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov } 2051232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov 2052232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov public void buttonTapped(int button) { 2053232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov cancel(); 2054232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov mMode = MODE_TAPPED; 2055232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov mManagedButton = button; 2056232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov NumberPicker.this.post(this); 2057232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov } 2058232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov 2059232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov @Override 2060232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov public void run() { 2061232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov switch (mMode) { 2062232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov case MODE_PRESS: { 2063232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov switch (mManagedButton) { 2064232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov case BUTTON_INCREMENT: { 2065232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov mIncrementVirtualButtonPressed = true; 2066232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov invalidate(0, mBottomSelectionDividerBottom, mRight, mBottom); 2067232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov } break; 2068232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov case BUTTON_DECREMENT: { 2069232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov mDecrementVirtualButtonPressed = true; 2070232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov invalidate(0, 0, mRight, mTopSelectionDividerTop); 2071232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov } 2072232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov } 2073232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov } break; 2074232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov case MODE_TAPPED: { 2075232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov switch (mManagedButton) { 2076232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov case BUTTON_INCREMENT: { 2077232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov if (!mIncrementVirtualButtonPressed) { 2078232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov NumberPicker.this.postDelayed(this, 2079232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov ViewConfiguration.getPressedStateDuration()); 2080232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov } 2081232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov mIncrementVirtualButtonPressed ^= true; 2082232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov invalidate(0, mBottomSelectionDividerBottom, mRight, mBottom); 2083232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov } break; 2084232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov case BUTTON_DECREMENT: { 2085232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov if (!mDecrementVirtualButtonPressed) { 2086232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov NumberPicker.this.postDelayed(this, 2087232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov ViewConfiguration.getPressedStateDuration()); 2088232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov } 2089232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov mDecrementVirtualButtonPressed ^= true; 2090232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov invalidate(0, 0, mRight, mTopSelectionDividerTop); 2091232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov } 2092232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov } 2093232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov } break; 2094fe41ce4ef97e7da585fdbf06988da8047e72b9f6Svetoslav Ganov } 2095fe41ce4ef97e7da585fdbf06988da8047e72b9f6Svetoslav Ganov } 2096fe41ce4ef97e7da585fdbf06988da8047e72b9f6Svetoslav Ganov } 2097fe41ce4ef97e7da585fdbf06988da8047e72b9f6Svetoslav Ganov 2098d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov /** 2099206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Command for setting the input text selection. 2100206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 2101206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov class SetSelectionCommand implements Runnable { 2102206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private int mSelectionStart; 2103206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 2104206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private int mSelectionEnd; 2105206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 2106206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov public void run() { 2107206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mInputText.setSelection(mSelectionStart, mSelectionEnd); 2108206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 2109206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 2110206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 2111206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 2112b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov * Command for changing the current value from a long press by one. 2113206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 2114b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov class ChangeCurrentByOneFromLongPressCommand implements Runnable { 2115b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov private boolean mIncrement; 2116206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 2117d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private void setStep(boolean increment) { 2118b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov mIncrement = increment; 2119206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 2120206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 2121d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov @Override 2122206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov public void run() { 2123d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov changeValueByOne(mIncrement); 21244bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov postDelayed(this, mLongPressUpdateInterval); 2125206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 212668f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook } 2127a2b41b438d45570867e4682c0caaf93ace5e712eSvetoslav Ganov 2128a2b41b438d45570867e4682c0caaf93ace5e712eSvetoslav Ganov /** 2129a2b41b438d45570867e4682c0caaf93ace5e712eSvetoslav Ganov * @hide 2130a2b41b438d45570867e4682c0caaf93ace5e712eSvetoslav Ganov */ 2131a2b41b438d45570867e4682c0caaf93ace5e712eSvetoslav Ganov public static class CustomEditText extends EditText { 2132a2b41b438d45570867e4682c0caaf93ace5e712eSvetoslav Ganov 2133a2b41b438d45570867e4682c0caaf93ace5e712eSvetoslav Ganov public CustomEditText(Context context, AttributeSet attrs) { 2134a2b41b438d45570867e4682c0caaf93ace5e712eSvetoslav Ganov super(context, attrs); 2135a2b41b438d45570867e4682c0caaf93ace5e712eSvetoslav Ganov } 2136a2b41b438d45570867e4682c0caaf93ace5e712eSvetoslav Ganov 2137a2b41b438d45570867e4682c0caaf93ace5e712eSvetoslav Ganov @Override 2138a2b41b438d45570867e4682c0caaf93ace5e712eSvetoslav Ganov public void onEditorAction(int actionCode) { 2139a2b41b438d45570867e4682c0caaf93ace5e712eSvetoslav Ganov super.onEditorAction(actionCode); 2140a2b41b438d45570867e4682c0caaf93ace5e712eSvetoslav Ganov if (actionCode == EditorInfo.IME_ACTION_DONE) { 2141a2b41b438d45570867e4682c0caaf93ace5e712eSvetoslav Ganov clearFocus(); 2142a2b41b438d45570867e4682c0caaf93ace5e712eSvetoslav Ganov } 2143a2b41b438d45570867e4682c0caaf93ace5e712eSvetoslav Ganov } 2144a2b41b438d45570867e4682c0caaf93ace5e712eSvetoslav Ganov } 2145d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 2146d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov /** 2147d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * Command for beginning soft input on long press. 2148d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov */ 2149d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov class BeginSoftInputOnLongPressCommand implements Runnable { 2150d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 2151d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov @Override 2152d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov public void run() { 2153d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov showSoftInput(); 2154d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mIngonreMoveEvents = true; 2155d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2156d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2157d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 2158791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov /** 2159791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov * Class for managing virtual view tree rooted at this picker. 2160791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov */ 2161d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov class AccessibilityNodeProviderImpl extends AccessibilityNodeProvider { 2162791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov private static final int UNDEFINED = Integer.MIN_VALUE; 2163791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov 2164d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private static final int VIRTUAL_VIEW_ID_INCREMENT = 1; 2165d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 2166d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private static final int VIRTUAL_VIEW_ID_INPUT = 2; 2167d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 2168d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private static final int VIRTUAL_VIEW_ID_DECREMENT = 3; 2169d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 2170d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private final Rect mTempRect = new Rect(); 2171d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 2172d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private final int[] mTempArray = new int[2]; 2173d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 2174791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov private int mAccessibilityFocusedView = UNDEFINED; 2175791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov 2176d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov @Override 2177d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov public AccessibilityNodeInfo createAccessibilityNodeInfo(int virtualViewId) { 2178d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov switch (virtualViewId) { 2179d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov case View.NO_ID: 2180d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return createAccessibilityNodeInfoForNumberPicker( mScrollX, mScrollY, 2181d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mScrollX + (mRight - mLeft), mScrollY + (mBottom - mTop)); 2182d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov case VIRTUAL_VIEW_ID_DECREMENT: 2183d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return createAccessibilityNodeInfoForVirtualButton(VIRTUAL_VIEW_ID_DECREMENT, 2184d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov getVirtualDecrementButtonText(), mScrollX, mScrollY, 2185d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mScrollX + (mRight - mLeft), 2186d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mTopSelectionDividerTop + mSelectionDividerHeight); 2187d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov case VIRTUAL_VIEW_ID_INPUT: 2188d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return createAccessibiltyNodeInfoForInputText(); 2189d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov case VIRTUAL_VIEW_ID_INCREMENT: 2190d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return createAccessibilityNodeInfoForVirtualButton(VIRTUAL_VIEW_ID_INCREMENT, 2191d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov getVirtualIncrementButtonText(), mScrollX, 2192d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mBottomSelectionDividerBottom - mSelectionDividerHeight, 2193d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mScrollX + (mRight - mLeft), mScrollY + (mBottom - mTop)); 2194d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2195d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return super.createAccessibilityNodeInfo(virtualViewId); 2196d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2197d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 2198d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov @Override 2199d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov public List<AccessibilityNodeInfo> findAccessibilityNodeInfosByText(String searched, 2200d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov int virtualViewId) { 2201d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (TextUtils.isEmpty(searched)) { 2202d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return Collections.emptyList(); 2203d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2204d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov String searchedLowerCase = searched.toLowerCase(); 2205d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov List<AccessibilityNodeInfo> result = new ArrayList<AccessibilityNodeInfo>(); 2206d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov switch (virtualViewId) { 2207d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov case View.NO_ID: { 2208d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov findAccessibilityNodeInfosByTextInChild(searchedLowerCase, 2209d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov VIRTUAL_VIEW_ID_DECREMENT, result); 2210d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov findAccessibilityNodeInfosByTextInChild(searchedLowerCase, 2211d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov VIRTUAL_VIEW_ID_INPUT, result); 2212d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov findAccessibilityNodeInfosByTextInChild(searchedLowerCase, 2213d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov VIRTUAL_VIEW_ID_INCREMENT, result); 2214d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return result; 2215d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2216d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov case VIRTUAL_VIEW_ID_DECREMENT: 2217d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov case VIRTUAL_VIEW_ID_INCREMENT: 2218d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov case VIRTUAL_VIEW_ID_INPUT: { 2219d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov findAccessibilityNodeInfosByTextInChild(searchedLowerCase, virtualViewId, 2220d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov result); 2221d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return result; 2222d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2223d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2224d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return super.findAccessibilityNodeInfosByText(searched, virtualViewId); 2225d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2226d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 2227d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov @Override 2228aa780c110922148a6a4ba06734bb2b0bb8c98f93Svetoslav Ganov public boolean performAction(int virtualViewId, int action, Bundle arguments) { 2229d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov switch (virtualViewId) { 2230791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov case View.NO_ID: { 2231791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov switch (action) { 2232791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov case AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS: { 2233791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov if (mAccessibilityFocusedView != virtualViewId) { 2234791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov mAccessibilityFocusedView = virtualViewId; 2235791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov requestAccessibilityFocus(); 2236791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov return true; 2237791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } 2238791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } return false; 2239791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov case AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS: { 2240791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov if (mAccessibilityFocusedView == virtualViewId) { 2241791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov mAccessibilityFocusedView = UNDEFINED; 2242791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov clearAccessibilityFocus(); 2243791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov return true; 2244791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } 2245791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov return false; 2246791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } 224748d1586f4065fc9ab97a679da1e4f7c327c943f2Svetoslav Ganov case AccessibilityNodeInfo.ACTION_SCROLL_FORWARD: { 2248fb1e80a247221ee7e8f5c5deba04812021d9d07eSvetoslav Ganov if (NumberPicker.this.isEnabled() 2249fb1e80a247221ee7e8f5c5deba04812021d9d07eSvetoslav Ganov && (getWrapSelectorWheel() || getValue() < getMaxValue())) { 225048d1586f4065fc9ab97a679da1e4f7c327c943f2Svetoslav Ganov changeValueByOne(true); 225148d1586f4065fc9ab97a679da1e4f7c327c943f2Svetoslav Ganov return true; 225248d1586f4065fc9ab97a679da1e4f7c327c943f2Svetoslav Ganov } 225348d1586f4065fc9ab97a679da1e4f7c327c943f2Svetoslav Ganov } return false; 225448d1586f4065fc9ab97a679da1e4f7c327c943f2Svetoslav Ganov case AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD: { 2255fb1e80a247221ee7e8f5c5deba04812021d9d07eSvetoslav Ganov if (NumberPicker.this.isEnabled() 2256fb1e80a247221ee7e8f5c5deba04812021d9d07eSvetoslav Ganov && (getWrapSelectorWheel() || getValue() > getMinValue())) { 225748d1586f4065fc9ab97a679da1e4f7c327c943f2Svetoslav Ganov changeValueByOne(false); 225848d1586f4065fc9ab97a679da1e4f7c327c943f2Svetoslav Ganov return true; 225948d1586f4065fc9ab97a679da1e4f7c327c943f2Svetoslav Ganov } 226048d1586f4065fc9ab97a679da1e4f7c327c943f2Svetoslav Ganov } return false; 2261791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } 2262791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } break; 2263d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov case VIRTUAL_VIEW_ID_INPUT: { 2264d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov switch (action) { 2265d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov case AccessibilityNodeInfo.ACTION_FOCUS: { 2266fb1e80a247221ee7e8f5c5deba04812021d9d07eSvetoslav Ganov if (NumberPicker.this.isEnabled() && !mInputText.isFocused()) { 2267d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return mInputText.requestFocus(); 2268d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2269d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } break; 2270d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov case AccessibilityNodeInfo.ACTION_CLEAR_FOCUS: { 2271fb1e80a247221ee7e8f5c5deba04812021d9d07eSvetoslav Ganov if (NumberPicker.this.isEnabled() && mInputText.isFocused()) { 2272d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mInputText.clearFocus(); 2273d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return true; 2274d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2275791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov return false; 2276791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } 2277791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov case AccessibilityNodeInfo.ACTION_CLICK: { 2278fb1e80a247221ee7e8f5c5deba04812021d9d07eSvetoslav Ganov if (NumberPicker.this.isEnabled()) { 2279fb1e80a247221ee7e8f5c5deba04812021d9d07eSvetoslav Ganov showSoftInput(); 2280fb1e80a247221ee7e8f5c5deba04812021d9d07eSvetoslav Ganov return true; 2281fb1e80a247221ee7e8f5c5deba04812021d9d07eSvetoslav Ganov } 2282fb1e80a247221ee7e8f5c5deba04812021d9d07eSvetoslav Ganov return false; 2283791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } 2284791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov case AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS: { 2285791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov if (mAccessibilityFocusedView != virtualViewId) { 2286791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov mAccessibilityFocusedView = virtualViewId; 2287791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov sendAccessibilityEventForVirtualView(virtualViewId, 2288791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED); 2289791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov mInputText.invalidate(); 2290791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov return true; 2291791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } 2292791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } return false; 2293791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov case AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS: { 2294791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov if (mAccessibilityFocusedView == virtualViewId) { 2295791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov mAccessibilityFocusedView = UNDEFINED; 2296791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov sendAccessibilityEventForVirtualView(virtualViewId, 2297791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED); 2298791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov mInputText.invalidate(); 2299791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov return true; 2300791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } 2301791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } return false; 2302791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov default: { 2303791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov return mInputText.performAccessibilityAction(action, arguments); 2304791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } 2305d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2306791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } return false; 2307791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov case VIRTUAL_VIEW_ID_INCREMENT: { 2308791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov switch (action) { 2309791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov case AccessibilityNodeInfo.ACTION_CLICK: { 2310fb1e80a247221ee7e8f5c5deba04812021d9d07eSvetoslav Ganov if (NumberPicker.this.isEnabled()) { 2311fb1e80a247221ee7e8f5c5deba04812021d9d07eSvetoslav Ganov NumberPicker.this.changeValueByOne(true); 2312fb1e80a247221ee7e8f5c5deba04812021d9d07eSvetoslav Ganov sendAccessibilityEventForVirtualView(virtualViewId, 2313fb1e80a247221ee7e8f5c5deba04812021d9d07eSvetoslav Ganov AccessibilityEvent.TYPE_VIEW_CLICKED); 2314fb1e80a247221ee7e8f5c5deba04812021d9d07eSvetoslav Ganov return true; 2315fb1e80a247221ee7e8f5c5deba04812021d9d07eSvetoslav Ganov } 2316fb1e80a247221ee7e8f5c5deba04812021d9d07eSvetoslav Ganov } return false; 2317791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov case AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS: { 2318791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov if (mAccessibilityFocusedView != virtualViewId) { 2319791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov mAccessibilityFocusedView = virtualViewId; 2320791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov sendAccessibilityEventForVirtualView(virtualViewId, 2321791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED); 2322791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov invalidate(0, mBottomSelectionDividerBottom, mRight, mBottom); 2323791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov return true; 2324791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } 2325791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } return false; 2326791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov case AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS: { 2327791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov if (mAccessibilityFocusedView == virtualViewId) { 2328791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov mAccessibilityFocusedView = UNDEFINED; 2329791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov sendAccessibilityEventForVirtualView(virtualViewId, 2330791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED); 2331791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov invalidate(0, mBottomSelectionDividerBottom, mRight, mBottom); 2332791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov return true; 2333791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } 2334791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } return false; 2335791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } 2336791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } return false; 2337791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov case VIRTUAL_VIEW_ID_DECREMENT: { 2338791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov switch (action) { 2339791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov case AccessibilityNodeInfo.ACTION_CLICK: { 2340fb1e80a247221ee7e8f5c5deba04812021d9d07eSvetoslav Ganov if (NumberPicker.this.isEnabled()) { 2341fb1e80a247221ee7e8f5c5deba04812021d9d07eSvetoslav Ganov final boolean increment = (virtualViewId == VIRTUAL_VIEW_ID_INCREMENT); 2342fb1e80a247221ee7e8f5c5deba04812021d9d07eSvetoslav Ganov NumberPicker.this.changeValueByOne(increment); 2343fb1e80a247221ee7e8f5c5deba04812021d9d07eSvetoslav Ganov sendAccessibilityEventForVirtualView(virtualViewId, 2344fb1e80a247221ee7e8f5c5deba04812021d9d07eSvetoslav Ganov AccessibilityEvent.TYPE_VIEW_CLICKED); 2345fb1e80a247221ee7e8f5c5deba04812021d9d07eSvetoslav Ganov return true; 2346fb1e80a247221ee7e8f5c5deba04812021d9d07eSvetoslav Ganov } 2347fb1e80a247221ee7e8f5c5deba04812021d9d07eSvetoslav Ganov } return false; 2348791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov case AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS: { 2349791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov if (mAccessibilityFocusedView != virtualViewId) { 2350791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov mAccessibilityFocusedView = virtualViewId; 2351791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov sendAccessibilityEventForVirtualView(virtualViewId, 2352791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED); 2353791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov invalidate(0, 0, mRight, mTopSelectionDividerTop); 2354791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov return true; 2355791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } 2356791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } return false; 2357791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov case AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS: { 2358791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov if (mAccessibilityFocusedView == virtualViewId) { 2359791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov mAccessibilityFocusedView = UNDEFINED; 2360791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov sendAccessibilityEventForVirtualView(virtualViewId, 2361791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED); 2362791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov invalidate(0, 0, mRight, mTopSelectionDividerTop); 2363791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov return true; 2364791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } 2365791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } return false; 2366791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } 2367791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } return false; 2368d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2369aa780c110922148a6a4ba06734bb2b0bb8c98f93Svetoslav Ganov return super.performAction(virtualViewId, action, arguments); 2370d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2371d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 2372d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov public void sendAccessibilityEventForVirtualView(int virtualViewId, int eventType) { 2373d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov switch (virtualViewId) { 2374d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov case VIRTUAL_VIEW_ID_DECREMENT: { 2375791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov if (hasVirtualDecrementButton()) { 2376791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov sendAccessibilityEventForVirtualButton(virtualViewId, eventType, 2377791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov getVirtualDecrementButtonText()); 2378791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } 2379d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } break; 2380d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov case VIRTUAL_VIEW_ID_INPUT: { 2381d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov sendAccessibilityEventForVirtualText(eventType); 2382d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } break; 2383d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov case VIRTUAL_VIEW_ID_INCREMENT: { 2384791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov if (hasVirtualIncrementButton()) { 2385791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov sendAccessibilityEventForVirtualButton(virtualViewId, eventType, 2386791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov getVirtualIncrementButtonText()); 2387791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } 2388d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } break; 2389d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2390d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2391d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 2392d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private void sendAccessibilityEventForVirtualText(int eventType) { 2393a90927629881f0faf54c1003ebd38c27a730045eSvetoslav Ganov if (AccessibilityManager.getInstance(mContext).isEnabled()) { 2394a90927629881f0faf54c1003ebd38c27a730045eSvetoslav Ganov AccessibilityEvent event = AccessibilityEvent.obtain(eventType); 2395a90927629881f0faf54c1003ebd38c27a730045eSvetoslav Ganov mInputText.onInitializeAccessibilityEvent(event); 2396a90927629881f0faf54c1003ebd38c27a730045eSvetoslav Ganov mInputText.onPopulateAccessibilityEvent(event); 2397a90927629881f0faf54c1003ebd38c27a730045eSvetoslav Ganov event.setSource(NumberPicker.this, VIRTUAL_VIEW_ID_INPUT); 2398a90927629881f0faf54c1003ebd38c27a730045eSvetoslav Ganov requestSendAccessibilityEvent(NumberPicker.this, event); 2399a90927629881f0faf54c1003ebd38c27a730045eSvetoslav Ganov } 2400d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2401d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 2402d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private void sendAccessibilityEventForVirtualButton(int virtualViewId, int eventType, 2403d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov String text) { 2404a90927629881f0faf54c1003ebd38c27a730045eSvetoslav Ganov if (AccessibilityManager.getInstance(mContext).isEnabled()) { 2405a90927629881f0faf54c1003ebd38c27a730045eSvetoslav Ganov AccessibilityEvent event = AccessibilityEvent.obtain(eventType); 2406a90927629881f0faf54c1003ebd38c27a730045eSvetoslav Ganov event.setClassName(Button.class.getName()); 2407a90927629881f0faf54c1003ebd38c27a730045eSvetoslav Ganov event.setPackageName(mContext.getPackageName()); 2408a90927629881f0faf54c1003ebd38c27a730045eSvetoslav Ganov event.getText().add(text); 2409a90927629881f0faf54c1003ebd38c27a730045eSvetoslav Ganov event.setEnabled(NumberPicker.this.isEnabled()); 2410a90927629881f0faf54c1003ebd38c27a730045eSvetoslav Ganov event.setSource(NumberPicker.this, virtualViewId); 2411a90927629881f0faf54c1003ebd38c27a730045eSvetoslav Ganov requestSendAccessibilityEvent(NumberPicker.this, event); 2412a90927629881f0faf54c1003ebd38c27a730045eSvetoslav Ganov } 2413d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2414d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 2415d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private void findAccessibilityNodeInfosByTextInChild(String searchedLowerCase, 2416d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov int virtualViewId, List<AccessibilityNodeInfo> outResult) { 2417d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov switch (virtualViewId) { 2418d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov case VIRTUAL_VIEW_ID_DECREMENT: { 2419d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov String text = getVirtualDecrementButtonText(); 2420d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (!TextUtils.isEmpty(text) 2421d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov && text.toString().toLowerCase().contains(searchedLowerCase)) { 2422d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov outResult.add(createAccessibilityNodeInfo(VIRTUAL_VIEW_ID_DECREMENT)); 2423d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2424d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } return; 2425d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov case VIRTUAL_VIEW_ID_INPUT: { 2426d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov CharSequence text = mInputText.getText(); 2427d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (!TextUtils.isEmpty(text) && 2428d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov text.toString().toLowerCase().contains(searchedLowerCase)) { 2429d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov outResult.add(createAccessibilityNodeInfo(VIRTUAL_VIEW_ID_INPUT)); 2430d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return; 2431d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2432d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov CharSequence contentDesc = mInputText.getText(); 2433d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (!TextUtils.isEmpty(contentDesc) && 2434d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov contentDesc.toString().toLowerCase().contains(searchedLowerCase)) { 2435d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov outResult.add(createAccessibilityNodeInfo(VIRTUAL_VIEW_ID_INPUT)); 2436d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return; 2437d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2438d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } break; 2439d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov case VIRTUAL_VIEW_ID_INCREMENT: { 2440d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov String text = getVirtualIncrementButtonText(); 2441d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (!TextUtils.isEmpty(text) 2442d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov && text.toString().toLowerCase().contains(searchedLowerCase)) { 2443d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov outResult.add(createAccessibilityNodeInfo(VIRTUAL_VIEW_ID_INCREMENT)); 2444d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2445d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } return; 2446d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2447d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2448d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 2449d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private AccessibilityNodeInfo createAccessibiltyNodeInfoForInputText() { 2450d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov AccessibilityNodeInfo info = mInputText.createAccessibilityNodeInfo(); 2451d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov info.setSource(NumberPicker.this, VIRTUAL_VIEW_ID_INPUT); 2452791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov if (mAccessibilityFocusedView != VIRTUAL_VIEW_ID_INPUT) { 2453791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov info.addAction(AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS); 2454791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } 2455791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov if (mAccessibilityFocusedView == VIRTUAL_VIEW_ID_INPUT) { 2456791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov info.addAction(AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS); 2457791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } 2458d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return info; 2459d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2460d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 2461d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private AccessibilityNodeInfo createAccessibilityNodeInfoForVirtualButton(int virtualViewId, 2462d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov String text, int left, int top, int right, int bottom) { 2463d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain(); 2464d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov info.setClassName(Button.class.getName()); 2465d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov info.setPackageName(mContext.getPackageName()); 2466d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov info.setSource(NumberPicker.this, virtualViewId); 2467d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov info.setParent(NumberPicker.this); 2468d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov info.setText(text); 2469d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov info.setClickable(true); 2470d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov info.setLongClickable(true); 2471d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov info.setEnabled(NumberPicker.this.isEnabled()); 2472d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov Rect boundsInParent = mTempRect; 2473d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov boundsInParent.set(left, top, right, bottom); 24740d607fbe546ac943de38dad33ae681b09efec6eaGuang Zhu info.setVisibleToUser(isVisibleToUser(boundsInParent)); 2475d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov info.setBoundsInParent(boundsInParent); 2476d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov Rect boundsInScreen = boundsInParent; 2477d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov int[] locationOnScreen = mTempArray; 2478d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov getLocationOnScreen(locationOnScreen); 2479d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov boundsInScreen.offset(locationOnScreen[0], locationOnScreen[1]); 2480d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov info.setBoundsInScreen(boundsInScreen); 2481791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov 2482791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov if (mAccessibilityFocusedView != virtualViewId) { 2483791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov info.addAction(AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS); 2484791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } 2485791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov if (mAccessibilityFocusedView == virtualViewId) { 2486791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov info.addAction(AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS); 2487791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } 2488fb1e80a247221ee7e8f5c5deba04812021d9d07eSvetoslav Ganov if (NumberPicker.this.isEnabled()) { 2489fb1e80a247221ee7e8f5c5deba04812021d9d07eSvetoslav Ganov info.addAction(AccessibilityNodeInfo.ACTION_CLICK); 2490fb1e80a247221ee7e8f5c5deba04812021d9d07eSvetoslav Ganov } 2491791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov 2492d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return info; 2493d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2494d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 2495d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private AccessibilityNodeInfo createAccessibilityNodeInfoForNumberPicker(int left, int top, 2496d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov int right, int bottom) { 2497d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain(); 24980d607fbe546ac943de38dad33ae681b09efec6eaGuang Zhu info.setClassName(NumberPicker.class.getName()); 2499d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov info.setPackageName(mContext.getPackageName()); 2500d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov info.setSource(NumberPicker.this); 2501791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov 2502791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov if (hasVirtualDecrementButton()) { 2503791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov info.addChild(NumberPicker.this, VIRTUAL_VIEW_ID_DECREMENT); 2504791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } 25050d607fbe546ac943de38dad33ae681b09efec6eaGuang Zhu info.addChild(NumberPicker.this, VIRTUAL_VIEW_ID_INPUT); 2506791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov if (hasVirtualIncrementButton()) { 2507791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov info.addChild(NumberPicker.this, VIRTUAL_VIEW_ID_INCREMENT); 2508791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } 2509791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov 25104528b4e882584745f48263fa6626987e63832a2aSvetoslav Ganov info.setParent((View) getParentForAccessibility()); 2511d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov info.setEnabled(NumberPicker.this.isEnabled()); 2512d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov info.setScrollable(true); 2513983119ab22a18c743e4084dff27f35e3f490dd34Svetoslav Ganov 2514983119ab22a18c743e4084dff27f35e3f490dd34Svetoslav Ganov final float applicationScale = 2515983119ab22a18c743e4084dff27f35e3f490dd34Svetoslav Ganov getContext().getResources().getCompatibilityInfo().applicationScale; 2516983119ab22a18c743e4084dff27f35e3f490dd34Svetoslav Ganov 2517d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov Rect boundsInParent = mTempRect; 2518d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov boundsInParent.set(left, top, right, bottom); 2519983119ab22a18c743e4084dff27f35e3f490dd34Svetoslav Ganov boundsInParent.scale(applicationScale); 2520d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov info.setBoundsInParent(boundsInParent); 2521983119ab22a18c743e4084dff27f35e3f490dd34Svetoslav Ganov 25220d607fbe546ac943de38dad33ae681b09efec6eaGuang Zhu info.setVisibleToUser(isVisibleToUser()); 2523983119ab22a18c743e4084dff27f35e3f490dd34Svetoslav Ganov 2524d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov Rect boundsInScreen = boundsInParent; 2525d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov int[] locationOnScreen = mTempArray; 2526d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov getLocationOnScreen(locationOnScreen); 2527d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov boundsInScreen.offset(locationOnScreen[0], locationOnScreen[1]); 2528983119ab22a18c743e4084dff27f35e3f490dd34Svetoslav Ganov boundsInScreen.scale(applicationScale); 2529d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov info.setBoundsInScreen(boundsInScreen); 2530791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov 2531791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov if (mAccessibilityFocusedView != View.NO_ID) { 2532791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov info.addAction(AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS); 2533791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } 2534791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov if (mAccessibilityFocusedView == View.NO_ID) { 2535791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov info.addAction(AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS); 2536791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } 2537fb1e80a247221ee7e8f5c5deba04812021d9d07eSvetoslav Ganov if (NumberPicker.this.isEnabled()) { 2538fb1e80a247221ee7e8f5c5deba04812021d9d07eSvetoslav Ganov if (getWrapSelectorWheel() || getValue() < getMaxValue()) { 2539fb1e80a247221ee7e8f5c5deba04812021d9d07eSvetoslav Ganov info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD); 2540fb1e80a247221ee7e8f5c5deba04812021d9d07eSvetoslav Ganov } 2541fb1e80a247221ee7e8f5c5deba04812021d9d07eSvetoslav Ganov if (getWrapSelectorWheel() || getValue() > getMinValue()) { 2542fb1e80a247221ee7e8f5c5deba04812021d9d07eSvetoslav Ganov info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD); 2543fb1e80a247221ee7e8f5c5deba04812021d9d07eSvetoslav Ganov } 254448d1586f4065fc9ab97a679da1e4f7c327c943f2Svetoslav Ganov } 2545791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov 2546d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return info; 2547d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2548d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 2549791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov private boolean hasVirtualDecrementButton() { 2550791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov return getWrapSelectorWheel() || getValue() > getMinValue(); 2551791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } 2552791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov 2553791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov private boolean hasVirtualIncrementButton() { 2554791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov return getWrapSelectorWheel() || getValue() < getMaxValue(); 2555791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } 2556791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov 2557d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private String getVirtualDecrementButtonText() { 2558d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov int value = mValue - 1; 2559d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (mWrapSelectorWheel) { 2560d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov value = getWrappedSelectorIndex(value); 2561d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2562d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (value >= mMinValue) { 2563d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return (mDisplayedValues == null) ? formatNumber(value) 2564d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov : mDisplayedValues[value - mMinValue]; 2565d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2566d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return null; 2567d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2568d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 2569d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private String getVirtualIncrementButtonText() { 2570d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov int value = mValue + 1; 2571d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (mWrapSelectorWheel) { 2572d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov value = getWrappedSelectorIndex(value); 2573d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2574d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (value <= mMaxValue) { 2575d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return (mDisplayedValues == null) ? formatNumber(value) 2576d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov : mDisplayedValues[value - mMinValue]; 2577d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2578d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return null; 2579d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2580d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2581d88e3054d08b1f821bb2e27b2647aa16a60d8742Fabrice Di Meglio 2582d88e3054d08b1f821bb2e27b2647aa16a60d8742Fabrice Di Meglio static private String formatNumberWithLocale(int value) { 2583d88e3054d08b1f821bb2e27b2647aa16a60d8742Fabrice Di Meglio return String.format(Locale.getDefault(), "%d", value); 2584d88e3054d08b1f821bb2e27b2647aa16a60d8742Fabrice Di Meglio } 25857762d93621f508f4410fd37b5bbdfec0071b0420Paul Westbrook} 2586