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 /** 473e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * Interface to listen for changes of the current value. 474206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 475cedc446684e94c9971c38c3206f1f224314bda2aSvetoslav Ganov public interface OnValueChangeListener { 476e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov 477206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 4784bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * Called upon a change of the current value. 4794bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * 480206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * @param picker The NumberPicker associated with this listener. 481206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * @param oldVal The previous value. 482206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * @param newVal The new value. 483206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 484e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov void onValueChange(NumberPicker picker, int oldVal, int newVal); 485206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 486206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 487206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 488e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * Interface to listen for the picker scroll state. 48950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov */ 49050f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov public interface OnScrollListener { 49150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 49250f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov /** 49350f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * The view is not scrolling. 49450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov */ 49550f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov public static int SCROLL_STATE_IDLE = 0; 49650f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 49750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov /** 498d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * The user is scrolling using touch, and his finger is still on the screen. 49950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov */ 50050f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov public static int SCROLL_STATE_TOUCH_SCROLL = 1; 50150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 50250f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov /** 50350f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * The user had previously been scrolling using touch and performed a fling. 50450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov */ 50550f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov public static int SCROLL_STATE_FLING = 2; 50650f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 50750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov /** 508e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * Callback invoked while the number picker scroll state has changed. 50950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * 510e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @param view The view whose scroll state is being reported. 511e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @param scrollState The current scroll state. One of 512e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * {@link #SCROLL_STATE_IDLE}, 513e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * {@link #SCROLL_STATE_TOUCH_SCROLL} or 514e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * {@link #SCROLL_STATE_IDLE}. 51550f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov */ 5164bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov public void onScrollStateChange(NumberPicker view, int scrollState); 51750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov } 51850f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 51950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov /** 520e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * Interface used to format current value into a string for presentation. 521206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 522206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov public interface Formatter { 5234bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov 5244bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov /** 525e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * Formats a string representation of the current value. 5264bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * 5274bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * @param value The currently selected value. 5284bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * @return A formatted string representation. 5294bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov */ 530e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov public String format(int value); 5319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 532fdf6db6748b32f620a7f68b13a67c38b4e59e5edTom Taylor 53368f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook /** 5344bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * Create a new number picker. 5354bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * 5364bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * @param context The application environment. 5374bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov */ 5384bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov public NumberPicker(Context context) { 5394bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov this(context, null); 5404bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov } 5414bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov 5424bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov /** 5434bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * Create a new number picker. 544206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * 545206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * @param context The application environment. 546206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * @param attrs A collection of attributes. 54768f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook */ 5489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public NumberPicker(Context context, AttributeSet attrs) { 549206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov this(context, attrs, R.attr.numberPickerStyle); 550206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 551206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 552206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 553206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Create a new number picker 554206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * 555206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * @param context the application environment. 556206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * @param attrs a collection of attributes. 557206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * @param defStyle The default style to apply to this view. 558206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 559206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov public NumberPicker(Context context, AttributeSet attrs, int defStyle) { 560206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov super(context, attrs, defStyle); 561206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 562206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // process style attributes 563d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov TypedArray attributesArray = context.obtainStyledAttributes( 564d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov attrs, R.styleable.NumberPicker, defStyle, 0); 565d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov final int layoutResId = attributesArray.getResourceId( 566d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov R.styleable.NumberPicker_internalLayout, DEFAULT_LAYOUT_RESOURCE_ID); 567d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 568d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mHasSelectorWheel = (layoutResId != DEFAULT_LAYOUT_RESOURCE_ID); 569d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 570206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mSolidColor = attributesArray.getColor(R.styleable.NumberPicker_solidColor, 0); 571d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 5729cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov mSelectionDivider = attributesArray.getDrawable(R.styleable.NumberPicker_selectionDivider); 573d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 574d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov final int defSelectionDividerHeight = (int) TypedValue.applyDimension( 575d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov TypedValue.COMPLEX_UNIT_DIP, UNSCALED_DEFAULT_SELECTION_DIVIDER_HEIGHT, 5769cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov getResources().getDisplayMetrics()); 5779cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov mSelectionDividerHeight = attributesArray.getDimensionPixelSize( 5789cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov R.styleable.NumberPicker_selectionDividerHeight, defSelectionDividerHeight); 579d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 580d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov final int defSelectionDividerDistance = (int) TypedValue.applyDimension( 581d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov TypedValue.COMPLEX_UNIT_DIP, UNSCALED_DEFAULT_SELECTION_DIVIDERS_DISTANCE, 582d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov getResources().getDisplayMetrics()); 583d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mSelectionDividersDistance = attributesArray.getDimensionPixelSize( 584d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov R.styleable.NumberPicker_selectionDividersDistance, defSelectionDividerDistance); 585d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 586e8331bd2e7ad3d62140143cafba3ff69be028557Svetoslav Ganov mMinHeight = attributesArray.getDimensionPixelSize( 587e8331bd2e7ad3d62140143cafba3ff69be028557Svetoslav Ganov R.styleable.NumberPicker_internalMinHeight, SIZE_UNSPECIFIED); 588d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 589e8331bd2e7ad3d62140143cafba3ff69be028557Svetoslav Ganov mMaxHeight = attributesArray.getDimensionPixelSize( 590e8331bd2e7ad3d62140143cafba3ff69be028557Svetoslav Ganov R.styleable.NumberPicker_internalMaxHeight, SIZE_UNSPECIFIED); 5919f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov if (mMinHeight != SIZE_UNSPECIFIED && mMaxHeight != SIZE_UNSPECIFIED 5929f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov && mMinHeight > mMaxHeight) { 593ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov throw new IllegalArgumentException("minHeight > maxHeight"); 594ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov } 595d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 596d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mMinWidth = attributesArray.getDimensionPixelSize( 597d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov R.styleable.NumberPicker_internalMinWidth, SIZE_UNSPECIFIED); 598d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 599d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mMaxWidth = attributesArray.getDimensionPixelSize( 600d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov R.styleable.NumberPicker_internalMaxWidth, SIZE_UNSPECIFIED); 6019f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov if (mMinWidth != SIZE_UNSPECIFIED && mMaxWidth != SIZE_UNSPECIFIED 6029f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov && mMinWidth > mMaxWidth) { 603ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov throw new IllegalArgumentException("minWidth > maxWidth"); 604ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov } 605d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 606f7c83bc4d3e1996b491824902a6a0f98ac69bedeSvetoslav Ganov mComputeMaxWidth = (mMaxWidth == SIZE_UNSPECIFIED); 607206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 608232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov mVirtualButtonPressedDrawable = attributesArray.getDrawable( 609232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov R.styleable.NumberPicker_virtualButtonPressedDrawable); 610232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov 611d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov attributesArray.recycle(); 6129cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov 613232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov mPressedStateHelper = new PressedStateHelper(); 614232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov 615206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // By default Linearlayout that we extend is not drawn. This is 616206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // its draw() method is not called but dispatchDraw() is called 617206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // directly (see ViewGroup.drawChild()). However, this class uses 618206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // the fading edge effect implemented by View and we need our 619206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // draw() method to be called. Therefore, we declare we will draw. 620d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov setWillNotDraw(!mHasSelectorWheel); 621206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 622206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov LayoutInflater inflater = (LayoutInflater) getContext().getSystemService( 623206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov Context.LAYOUT_INFLATER_SERVICE); 624d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov inflater.inflate(layoutResId, this, true); 62568f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook 626206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov OnClickListener onClickListener = new OnClickListener() { 62768f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook public void onClick(View v) { 628b52d9729bfb2ef7ad50d9a5125ebf3a8322429a9Svetoslav Ganov hideSoftInput(); 629206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mInputText.clearFocus(); 630206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (v.getId() == R.id.increment) { 631d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov changeValueByOne(true); 632206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } else { 633d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov changeValueByOne(false); 63468f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook } 63568f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook } 63668f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook }; 63768f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook 638206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov OnLongClickListener onLongClickListener = new OnLongClickListener() { 639206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov public boolean onLongClick(View v) { 640b52d9729bfb2ef7ad50d9a5125ebf3a8322429a9Svetoslav Ganov hideSoftInput(); 641206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mInputText.clearFocus(); 642206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (v.getId() == R.id.increment) { 643d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov postChangeCurrentByOneFromLongPress(true, 0); 644206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } else { 645d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov postChangeCurrentByOneFromLongPress(false, 0); 646206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 647206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return true; 648206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 649206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov }; 65068f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook 651206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // increment button 652d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (!mHasSelectorWheel) { 653d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mIncrementButton = (ImageButton) findViewById(R.id.increment); 654d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mIncrementButton.setOnClickListener(onClickListener); 655d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mIncrementButton.setOnLongClickListener(onLongClickListener); 656d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } else { 657d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mIncrementButton = null; 658d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 659206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 660206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // decrement button 661d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (!mHasSelectorWheel) { 662d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mDecrementButton = (ImageButton) findViewById(R.id.decrement); 663d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mDecrementButton.setOnClickListener(onClickListener); 664d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mDecrementButton.setOnLongClickListener(onLongClickListener); 665d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } else { 666d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mDecrementButton = null; 667d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 668206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 669206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // input text 670012dd5a461f18a2e5dad38c60282fac1c21ff7feSvetoslav Ganov mInputText = (EditText) findViewById(R.id.numberpicker_input); 671206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mInputText.setOnFocusChangeListener(new OnFocusChangeListener() { 672206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov public void onFocusChange(View v, boolean hasFocus) { 673a53efe9923bedab4fe5d578f32eaff308e5b9e76Svetoslav Ganov if (hasFocus) { 674a53efe9923bedab4fe5d578f32eaff308e5b9e76Svetoslav Ganov mInputText.selectAll(); 675a53efe9923bedab4fe5d578f32eaff308e5b9e76Svetoslav Ganov } else { 676a53efe9923bedab4fe5d578f32eaff308e5b9e76Svetoslav Ganov mInputText.setSelection(0, 0); 677206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov validateInputTextView(v); 67868f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook } 67968f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook } 680206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov }); 681206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mInputText.setFilters(new InputFilter[] { 682206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov new InputTextFilter() 683206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov }); 68468f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook 685206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mInputText.setRawInputType(InputType.TYPE_CLASS_NUMBER); 686a2b41b438d45570867e4682c0caaf93ace5e712eSvetoslav Ganov mInputText.setImeOptions(EditorInfo.IME_ACTION_DONE); 687206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 688206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // initialize constants 689206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov ViewConfiguration configuration = ViewConfiguration.get(context); 690206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mTouchSlop = configuration.getScaledTouchSlop(); 691206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mMinimumFlingVelocity = configuration.getScaledMinimumFlingVelocity(); 692206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mMaximumFlingVelocity = configuration.getScaledMaximumFlingVelocity() 693206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov / SELECTOR_MAX_FLING_VELOCITY_ADJUSTMENT; 694206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mTextSize = (int) mInputText.getTextSize(); 695206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 696206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // create the selector wheel paint 697206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov Paint paint = new Paint(); 698206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov paint.setAntiAlias(true); 699206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov paint.setTextAlign(Align.CENTER); 700206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov paint.setTextSize(mTextSize); 701206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov paint.setTypeface(mInputText.getTypeface()); 702206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov ColorStateList colors = mInputText.getTextColors(); 703206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov int color = colors.getColorForState(ENABLED_STATE_SET, Color.WHITE); 704206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov paint.setColor(color); 705b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov mSelectorWheelPaint = paint; 706206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 707206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // create the fling and adjust scrollers 708bf80562d22b2bbe7944d80d0524c69d0238010cbSvetoslav Ganov mFlingScroller = new Scroller(getContext(), null, true); 7099cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov mAdjustScroller = new Scroller(getContext(), new DecelerateInterpolator(2.5f)); 710fdf6db6748b32f620a7f68b13a67c38b4e59e5edTom Taylor 711206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov updateInputTextView(); 7124213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov 7134213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov // If not explicitly specified this view is important for accessibility. 7144213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov if (getImportantForAccessibility() == IMPORTANT_FOR_ACCESSIBILITY_AUTO) { 7154213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES); 7164213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov } 717206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 718206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 719206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov @Override 7209cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov protected void onLayout(boolean changed, int left, int top, int right, int bottom) { 721d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (!mHasSelectorWheel) { 722d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov super.onLayout(changed, left, top, right, bottom); 723d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return; 724d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 725ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov final int msrdWdth = getMeasuredWidth(); 726ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov final int msrdHght = getMeasuredHeight(); 727ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov 728ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov // Input text centered horizontally. 729ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov final int inptTxtMsrdWdth = mInputText.getMeasuredWidth(); 730ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov final int inptTxtMsrdHght = mInputText.getMeasuredHeight(); 731ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov final int inptTxtLeft = (msrdWdth - inptTxtMsrdWdth) / 2; 732ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov final int inptTxtTop = (msrdHght - inptTxtMsrdHght) / 2; 733ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov final int inptTxtRight = inptTxtLeft + inptTxtMsrdWdth; 734ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov final int inptTxtBottom = inptTxtTop + inptTxtMsrdHght; 735ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov mInputText.layout(inptTxtLeft, inptTxtTop, inptTxtRight, inptTxtBottom); 736ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov 737d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (changed) { 738b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov // need to do all this when we know our size 739b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov initializeSelectorWheel(); 740b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov initializeFadingEdges(); 741d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mTopSelectionDividerTop = (getHeight() - mSelectionDividersDistance) / 2 742d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov - mSelectionDividerHeight; 743d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mBottomSelectionDividerBottom = mTopSelectionDividerTop + 2 * mSelectionDividerHeight 744d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov + mSelectionDividersDistance; 745b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov } 746206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 747206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 748206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov @Override 749e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 750d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (!mHasSelectorWheel) { 751d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov super.onMeasure(widthMeasureSpec, heightMeasureSpec); 752d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return; 753d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 754698e1d5d867a7ac653fa1d6f29cef4cfb73fad38Svetoslav Ganov // Try greedily to fit the max width and height. 755698e1d5d867a7ac653fa1d6f29cef4cfb73fad38Svetoslav Ganov final int newWidthMeasureSpec = makeMeasureSpec(widthMeasureSpec, mMaxWidth); 756698e1d5d867a7ac653fa1d6f29cef4cfb73fad38Svetoslav Ganov final int newHeightMeasureSpec = makeMeasureSpec(heightMeasureSpec, mMaxHeight); 757ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov super.onMeasure(newWidthMeasureSpec, newHeightMeasureSpec); 758698e1d5d867a7ac653fa1d6f29cef4cfb73fad38Svetoslav Ganov // Flag if we are measured with width or height less than the respective min. 7599f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov final int widthSize = resolveSizeAndStateRespectingMinSize(mMinWidth, getMeasuredWidth(), 7609f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov widthMeasureSpec); 7619f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov final int heightSize = resolveSizeAndStateRespectingMinSize(mMinHeight, getMeasuredHeight(), 7629f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov heightMeasureSpec); 763698e1d5d867a7ac653fa1d6f29cef4cfb73fad38Svetoslav Ganov setMeasuredDimension(widthSize, heightSize); 764e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov } 765e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov 766d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov /** 767d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * Move to the final position of a scroller. Ensures to force finish the scroller 768d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * and if it is not at its final position a scroll of the selector wheel is 769d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * performed to fast forward to the final position. 770d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * 771d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * @param scroller The scroller to whose final position to get. 772d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * @return True of the a move was performed, i.e. the scroller was not in final position. 773d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov */ 774d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private boolean moveToFinalScrollerPosition(Scroller scroller) { 775d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov scroller.forceFinished(true); 776d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov int amountToScroll = scroller.getFinalY() - scroller.getCurrY(); 777d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov int futureScrollOffset = (mCurrentScrollOffset + amountToScroll) % mSelectorElementHeight; 778d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov int overshootAdjustment = mInitialScrollOffset - futureScrollOffset; 779d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (overshootAdjustment != 0) { 780d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (Math.abs(overshootAdjustment) > mSelectorElementHeight / 2) { 781d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (overshootAdjustment > 0) { 782d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov overshootAdjustment -= mSelectorElementHeight; 783d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } else { 784d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov overshootAdjustment += mSelectorElementHeight; 785d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 786d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 787d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov amountToScroll += overshootAdjustment; 788d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov scrollBy(0, amountToScroll); 789d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return true; 790d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 791d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return false; 792d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 793d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 794e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov @Override 795206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov public boolean onInterceptTouchEvent(MotionEvent event) { 796d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (!mHasSelectorWheel || !isEnabled()) { 79751c52edad7d40697d7fb2a091f850506fa897643Svetoslav Ganov return false; 79851c52edad7d40697d7fb2a091f850506fa897643Svetoslav Ganov } 799d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov final int action = event.getActionMasked(); 800d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov switch (action) { 801d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov case MotionEvent.ACTION_DOWN: { 802206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov removeAllCallbacks(); 803d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mInputText.setVisibility(View.INVISIBLE); 804d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mLastDownOrMoveEventY = mLastDownEventY = event.getY(); 805d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mLastDownEventTime = event.getEventTime(); 806d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mIngonreMoveEvents = false; 807d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mShowSoftInputOnTap = false; 808232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov // Handle pressed state before any state change. 809232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov if (mLastDownEventY < mTopSelectionDividerTop) { 810232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov if (mScrollState == OnScrollListener.SCROLL_STATE_IDLE) { 811232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov mPressedStateHelper.buttonPressDelayed( 812232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov PressedStateHelper.BUTTON_DECREMENT); 813232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov } 814232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov } else if (mLastDownEventY > mBottomSelectionDividerBottom) { 815232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov if (mScrollState == OnScrollListener.SCROLL_STATE_IDLE) { 816232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov mPressedStateHelper.buttonPressDelayed( 817232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov PressedStateHelper.BUTTON_INCREMENT); 818232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov } 819232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov } 820232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov // Make sure we support flinging inside scrollables. 82183dc45c65988e9b86e156d59f59ede48195ed1d5Svetoslav Ganov getParent().requestDisallowInterceptTouchEvent(true); 822d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (!mFlingScroller.isFinished()) { 823d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mFlingScroller.forceFinished(true); 824d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mAdjustScroller.forceFinished(true); 825d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov onScrollStateChange(OnScrollListener.SCROLL_STATE_IDLE); 826d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } else if (!mAdjustScroller.isFinished()) { 827d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mFlingScroller.forceFinished(true); 828d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mAdjustScroller.forceFinished(true); 829d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } else if (mLastDownEventY < mTopSelectionDividerTop) { 830b52d9729bfb2ef7ad50d9a5125ebf3a8322429a9Svetoslav Ganov hideSoftInput(); 831d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov postChangeCurrentByOneFromLongPress( 832d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov false, ViewConfiguration.getLongPressTimeout()); 833d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } else if (mLastDownEventY > mBottomSelectionDividerBottom) { 834b52d9729bfb2ef7ad50d9a5125ebf3a8322429a9Svetoslav Ganov hideSoftInput(); 835d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov postChangeCurrentByOneFromLongPress( 836d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov true, ViewConfiguration.getLongPressTimeout()); 837d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } else { 838d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mShowSoftInputOnTap = true; 839d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov postBeginSoftInputOnLongPressCommand(); 840206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 841d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return true; 842d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 843206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 844206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return false; 845206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 846206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 847206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov @Override 848d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov public boolean onTouchEvent(MotionEvent event) { 849d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (!isEnabled() || !mHasSelectorWheel) { 85051c52edad7d40697d7fb2a091f850506fa897643Svetoslav Ganov return false; 85151c52edad7d40697d7fb2a091f850506fa897643Svetoslav Ganov } 852206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (mVelocityTracker == null) { 853206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mVelocityTracker = VelocityTracker.obtain(); 854206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 855d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mVelocityTracker.addMovement(event); 856d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov int action = event.getActionMasked(); 857206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov switch (action) { 858d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov case MotionEvent.ACTION_MOVE: { 859d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (mIngonreMoveEvents) { 860d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov break; 861d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 862d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov float currentMoveY = event.getY(); 863d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (mScrollState != OnScrollListener.SCROLL_STATE_TOUCH_SCROLL) { 864206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov int deltaDownY = (int) Math.abs(currentMoveY - mLastDownEventY); 865206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (deltaDownY > mTouchSlop) { 866d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov removeAllCallbacks(); 8679cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov onScrollStateChange(OnScrollListener.SCROLL_STATE_TOUCH_SCROLL); 868206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 869d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } else { 870232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov int deltaMoveY = (int) ((currentMoveY - mLastDownOrMoveEventY)); 871d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov scrollBy(0, deltaMoveY); 872d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov invalidate(); 873206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 874d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mLastDownOrMoveEventY = currentMoveY; 875d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } break; 876d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov case MotionEvent.ACTION_UP: { 877d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov removeBeginSoftInputCommand(); 878d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov removeChangeCurrentByOneFromLongPress(); 879232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov mPressedStateHelper.cancel(); 880206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov VelocityTracker velocityTracker = mVelocityTracker; 881206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov velocityTracker.computeCurrentVelocity(1000, mMaximumFlingVelocity); 882206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov int initialVelocity = (int) velocityTracker.getYVelocity(); 883206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (Math.abs(initialVelocity) > mMinimumFlingVelocity) { 884232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov fling(initialVelocity); 8859cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov onScrollStateChange(OnScrollListener.SCROLL_STATE_FLING); 886206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } else { 887d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov int eventY = (int) event.getY(); 888d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov int deltaMoveY = (int) Math.abs(eventY - mLastDownEventY); 889d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov long deltaTime = event.getEventTime() - mLastDownEventTime; 890d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (deltaMoveY <= mTouchSlop && deltaTime < ViewConfiguration.getTapTimeout()) { 891d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (mShowSoftInputOnTap) { 892d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mShowSoftInputOnTap = false; 893d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov showSoftInput(); 894d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } else { 895d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov int selectorIndexOffset = (eventY / mSelectorElementHeight) 896d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov - SELECTOR_MIDDLE_ITEM_INDEX; 897d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (selectorIndexOffset > 0) { 898d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov changeValueByOne(true); 899232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov mPressedStateHelper.buttonTapped( 900232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov PressedStateHelper.BUTTON_INCREMENT); 901d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } else if (selectorIndexOffset < 0) { 902d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov changeValueByOne(false); 903232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov mPressedStateHelper.buttonTapped( 904232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov PressedStateHelper.BUTTON_DECREMENT); 905d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 906206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 907206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } else { 908d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov ensureScrollWheelAdjusted(); 909206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 910d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov onScrollStateChange(OnScrollListener.SCROLL_STATE_IDLE); 911206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 912206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mVelocityTracker.recycle(); 913206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mVelocityTracker = null; 914d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } break; 915206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 916206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return true; 917206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 918206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 919206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov @Override 920206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov public boolean dispatchTouchEvent(MotionEvent event) { 921b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov final int action = event.getActionMasked(); 922b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov switch (action) { 923b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov case MotionEvent.ACTION_CANCEL: 924b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov case MotionEvent.ACTION_UP: 925b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov removeAllCallbacks(); 926b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov break; 927206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 928206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return super.dispatchTouchEvent(event); 929206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 930206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 931206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov @Override 932206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov public boolean dispatchKeyEvent(KeyEvent event) { 933d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov final int keyCode = event.getKeyCode(); 934d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov switch (keyCode) { 935d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov case KeyEvent.KEYCODE_DPAD_CENTER: 936d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov case KeyEvent.KEYCODE_ENTER: 937d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov removeAllCallbacks(); 938d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov break; 939206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 940206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return super.dispatchKeyEvent(event); 941206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 942206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 943206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov @Override 944206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov public boolean dispatchTrackballEvent(MotionEvent event) { 945d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov final int action = event.getActionMasked(); 946d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov switch (action) { 947d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov case MotionEvent.ACTION_CANCEL: 948d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov case MotionEvent.ACTION_UP: 949d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov removeAllCallbacks(); 950d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov break; 951206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 952206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return super.dispatchTrackballEvent(event); 953206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 9549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 955206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov @Override 956d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov protected boolean dispatchHoverEvent(MotionEvent event) { 957d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (!mHasSelectorWheel) { 958d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return super.dispatchHoverEvent(event); 959d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 960d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (AccessibilityManager.getInstance(mContext).isEnabled()) { 961d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov final int eventY = (int) event.getY(); 962d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov final int hoveredVirtualViewId; 963d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (eventY < mTopSelectionDividerTop) { 964d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov hoveredVirtualViewId = AccessibilityNodeProviderImpl.VIRTUAL_VIEW_ID_DECREMENT; 965d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } else if (eventY > mBottomSelectionDividerBottom) { 966d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov hoveredVirtualViewId = AccessibilityNodeProviderImpl.VIRTUAL_VIEW_ID_INCREMENT; 967d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } else { 968d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov hoveredVirtualViewId = AccessibilityNodeProviderImpl.VIRTUAL_VIEW_ID_INPUT; 969d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 970d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov final int action = event.getActionMasked(); 971d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov AccessibilityNodeProviderImpl provider = 972d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov (AccessibilityNodeProviderImpl) getAccessibilityNodeProvider(); 973d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov switch (action) { 974d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov case MotionEvent.ACTION_HOVER_ENTER: { 975d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov provider.sendAccessibilityEventForVirtualView(hoveredVirtualViewId, 976d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov AccessibilityEvent.TYPE_VIEW_HOVER_ENTER); 977d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mLastHoveredChildVirtualViewId = hoveredVirtualViewId; 978791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov provider.performAction(hoveredVirtualViewId, 979791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS, null); 980d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } break; 981d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov case MotionEvent.ACTION_HOVER_MOVE: { 982d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (mLastHoveredChildVirtualViewId != hoveredVirtualViewId 983d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov && mLastHoveredChildVirtualViewId != View.NO_ID) { 984d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov provider.sendAccessibilityEventForVirtualView( 985d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mLastHoveredChildVirtualViewId, 986d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov AccessibilityEvent.TYPE_VIEW_HOVER_EXIT); 987d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov provider.sendAccessibilityEventForVirtualView(hoveredVirtualViewId, 988d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov AccessibilityEvent.TYPE_VIEW_HOVER_ENTER); 989d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mLastHoveredChildVirtualViewId = hoveredVirtualViewId; 990791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov provider.performAction(hoveredVirtualViewId, 991791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS, null); 992d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 993d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } break; 994d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov case MotionEvent.ACTION_HOVER_EXIT: { 995d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov provider.sendAccessibilityEventForVirtualView(hoveredVirtualViewId, 996d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov AccessibilityEvent.TYPE_VIEW_HOVER_EXIT); 997d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mLastHoveredChildVirtualViewId = View.NO_ID; 998d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } break; 999d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 1000206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1001d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return false; 1002d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 1003d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 1004d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov @Override 1005d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov public void computeScroll() { 1006206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov Scroller scroller = mFlingScroller; 1007206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (scroller.isFinished()) { 1008206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov scroller = mAdjustScroller; 1009206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (scroller.isFinished()) { 1010206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return; 1011206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1012206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1013206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov scroller.computeScrollOffset(); 1014206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov int currentScrollerY = scroller.getCurrY(); 1015206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (mPreviousScrollerY == 0) { 1016206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mPreviousScrollerY = scroller.getStartY(); 1017206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1018206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov scrollBy(0, currentScrollerY - mPreviousScrollerY); 1019206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mPreviousScrollerY = currentScrollerY; 1020206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (scroller.isFinished()) { 1021206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov onScrollerFinished(scroller); 1022206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } else { 1023206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov invalidate(); 10249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1026fdf6db6748b32f620a7f68b13a67c38b4e59e5edTom Taylor 10279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 10289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void setEnabled(boolean enabled) { 10299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project super.setEnabled(enabled); 1030d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (!mHasSelectorWheel) { 1031d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mIncrementButton.setEnabled(enabled); 1032d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 1033d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (!mHasSelectorWheel) { 1034d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mDecrementButton.setEnabled(enabled); 1035d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 1036206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mInputText.setEnabled(enabled); 1037206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1038206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 1039206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov @Override 1040206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov public void scrollBy(int x, int y) { 1041b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov int[] selectorIndices = mSelectorIndices; 104234c0688ceafbeef2648bd2287b3b3c3801679448Svetoslav Ganov if (!mWrapSelectorWheel && y > 0 104334c0688ceafbeef2648bd2287b3b3c3801679448Svetoslav Ganov && selectorIndices[SELECTOR_MIDDLE_ITEM_INDEX] <= mMinValue) { 1044206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mCurrentScrollOffset = mInitialScrollOffset; 1045206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return; 1046206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 104734c0688ceafbeef2648bd2287b3b3c3801679448Svetoslav Ganov if (!mWrapSelectorWheel && y < 0 104834c0688ceafbeef2648bd2287b3b3c3801679448Svetoslav Ganov && selectorIndices[SELECTOR_MIDDLE_ITEM_INDEX] >= mMaxValue) { 1049206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mCurrentScrollOffset = mInitialScrollOffset; 1050206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return; 1051206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1052206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mCurrentScrollOffset += y; 1053b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov while (mCurrentScrollOffset - mInitialScrollOffset > mSelectorTextGapHeight) { 1054206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mCurrentScrollOffset -= mSelectorElementHeight; 1055206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov decrementSelectorIndices(selectorIndices); 1056d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov setValueInternal(selectorIndices[SELECTOR_MIDDLE_ITEM_INDEX], true); 1057b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov if (!mWrapSelectorWheel && selectorIndices[SELECTOR_MIDDLE_ITEM_INDEX] <= mMinValue) { 1058206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mCurrentScrollOffset = mInitialScrollOffset; 1059206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1060206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1061b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov while (mCurrentScrollOffset - mInitialScrollOffset < -mSelectorTextGapHeight) { 1062206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mCurrentScrollOffset += mSelectorElementHeight; 1063b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov incrementSelectorIndices(selectorIndices); 1064d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov setValueInternal(selectorIndices[SELECTOR_MIDDLE_ITEM_INDEX], true); 1065b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov if (!mWrapSelectorWheel && selectorIndices[SELECTOR_MIDDLE_ITEM_INDEX] >= mMaxValue) { 1066206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mCurrentScrollOffset = mInitialScrollOffset; 1067206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1068206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 10699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1070fdf6db6748b32f620a7f68b13a67c38b4e59e5edTom Taylor 10714bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov @Override 10724bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov public int getSolidColor() { 10734bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov return mSolidColor; 10744bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov } 10754bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov 107668f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook /** 10774bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * Sets the listener to be notified on change of the current value. 1078206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * 1079e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @param onValueChangedListener The listener. 108068f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook */ 1081cedc446684e94c9971c38c3206f1f224314bda2aSvetoslav Ganov public void setOnValueChangedListener(OnValueChangeListener onValueChangedListener) { 1082cedc446684e94c9971c38c3206f1f224314bda2aSvetoslav Ganov mOnValueChangeListener = onValueChangedListener; 108350f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov } 108450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 108550f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov /** 10864bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * Set listener to be notified for scroll state changes. 108750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * 1088e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @param onScrollListener The listener. 108950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov */ 109050f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov public void setOnScrollListener(OnScrollListener onScrollListener) { 109150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov mOnScrollListener = onScrollListener; 10929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1093fdf6db6748b32f620a7f68b13a67c38b4e59e5edTom Taylor 109468f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook /** 10954bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * Set the formatter to be used for formatting the current value. 10964bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * <p> 1097e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * Note: If you have provided alternative values for the values this 1098e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * formatter is never invoked. 10994bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * </p> 1100206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * 1101e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @param formatter The formatter object. If formatter is <code>null</code>, 1102e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * {@link String#valueOf(int)} will be used. 1103d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov *@see #setDisplayedValues(String[]) 110468f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook */ 11059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void setFormatter(Formatter formatter) { 1106e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov if (formatter == mFormatter) { 1107e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov return; 1108e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov } 11099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mFormatter = formatter; 1110b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov initializeSelectorWheelIndices(); 11119cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov updateInputTextView(); 1112206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1113206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 1114206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 1115e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * Set the current value for the number picker. 11164bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * <p> 1117e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * If the argument is less than the {@link NumberPicker#getMinValue()} and 1118e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * {@link NumberPicker#getWrapSelectorWheel()} is <code>false</code> the 1119e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * current value is set to the {@link NumberPicker#getMinValue()} value. 1120e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * </p> 1121e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * <p> 1122e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * If the argument is less than the {@link NumberPicker#getMinValue()} and 1123e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * {@link NumberPicker#getWrapSelectorWheel()} is <code>true</code> the 1124e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * current value is set to the {@link NumberPicker#getMaxValue()} value. 1125e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * </p> 1126e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * <p> 1127e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * If the argument is less than the {@link NumberPicker#getMaxValue()} and 1128e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * {@link NumberPicker#getWrapSelectorWheel()} is <code>false</code> the 1129e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * current value is set to the {@link NumberPicker#getMaxValue()} value. 1130e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * </p> 1131e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * <p> 1132e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * If the argument is less than the {@link NumberPicker#getMaxValue()} and 1133e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * {@link NumberPicker#getWrapSelectorWheel()} is <code>true</code> the 1134e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * current value is set to the {@link NumberPicker#getMinValue()} value. 11354bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * </p> 1136206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * 1137e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @param value The current value. 11384bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * @see #setWrapSelectorWheel(boolean) 1139e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @see #setMinValue(int) 1140e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @see #setMaxValue(int) 1141206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 1142e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov public void setValue(int value) { 1143d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov setValueInternal(value, false); 11449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1145fdf6db6748b32f620a7f68b13a67c38b4e59e5edTom Taylor 114668f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook /** 1147d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * Shows the soft input for its input text. 1148d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov */ 1149d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private void showSoftInput() { 1150d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov InputMethodManager inputMethodManager = InputMethodManager.peekInstance(); 1151d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (inputMethodManager != null) { 1152d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (mHasSelectorWheel) { 1153d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mInputText.setVisibility(View.VISIBLE); 1154d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 1155d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mInputText.requestFocus(); 1156d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov inputMethodManager.showSoftInput(mInputText, 0); 1157d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 1158d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 1159d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 1160d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov /** 1161d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * Hides the soft input if it is active for the input text. 1162b52d9729bfb2ef7ad50d9a5125ebf3a8322429a9Svetoslav Ganov */ 1163b52d9729bfb2ef7ad50d9a5125ebf3a8322429a9Svetoslav Ganov private void hideSoftInput() { 1164b52d9729bfb2ef7ad50d9a5125ebf3a8322429a9Svetoslav Ganov InputMethodManager inputMethodManager = InputMethodManager.peekInstance(); 1165b52d9729bfb2ef7ad50d9a5125ebf3a8322429a9Svetoslav Ganov if (inputMethodManager != null && inputMethodManager.isActive(mInputText)) { 1166b52d9729bfb2ef7ad50d9a5125ebf3a8322429a9Svetoslav Ganov inputMethodManager.hideSoftInputFromWindow(getWindowToken(), 0); 1167d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (mHasSelectorWheel) { 1168d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mInputText.setVisibility(View.INVISIBLE); 1169d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 1170b52d9729bfb2ef7ad50d9a5125ebf3a8322429a9Svetoslav Ganov } 1171b52d9729bfb2ef7ad50d9a5125ebf3a8322429a9Svetoslav Ganov } 1172b52d9729bfb2ef7ad50d9a5125ebf3a8322429a9Svetoslav Ganov 1173b52d9729bfb2ef7ad50d9a5125ebf3a8322429a9Svetoslav Ganov /** 1174ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov * Computes the max width if no such specified as an attribute. 1175ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov */ 1176ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov private void tryComputeMaxWidth() { 1177ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov if (!mComputeMaxWidth) { 1178ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov return; 1179ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov } 1180ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov int maxTextWidth = 0; 1181ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov if (mDisplayedValues == null) { 1182ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov float maxDigitWidth = 0; 1183ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov for (int i = 0; i <= 9; i++) { 1184d88e3054d08b1f821bb2e27b2647aa16a60d8742Fabrice Di Meglio final float digitWidth = mSelectorWheelPaint.measureText(formatNumberWithLocale(i)); 1185ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov if (digitWidth > maxDigitWidth) { 1186ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov maxDigitWidth = digitWidth; 1187ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov } 1188ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov } 1189ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov int numberOfDigits = 0; 1190ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov int current = mMaxValue; 1191ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov while (current > 0) { 1192ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov numberOfDigits++; 1193ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov current = current / 10; 1194ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov } 1195ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov maxTextWidth = (int) (numberOfDigits * maxDigitWidth); 1196ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov } else { 1197ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov final int valueCount = mDisplayedValues.length; 1198ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov for (int i = 0; i < valueCount; i++) { 1199ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov final float textWidth = mSelectorWheelPaint.measureText(mDisplayedValues[i]); 1200ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov if (textWidth > maxTextWidth) { 1201ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov maxTextWidth = (int) textWidth; 1202ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov } 1203ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov } 1204ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov } 1205ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov maxTextWidth += mInputText.getPaddingLeft() + mInputText.getPaddingRight(); 1206ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov if (mMaxWidth != maxTextWidth) { 1207ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov if (maxTextWidth > mMinWidth) { 1208ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov mMaxWidth = maxTextWidth; 1209ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov } else { 1210ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov mMaxWidth = mMinWidth; 1211ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov } 1212ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov invalidate(); 1213ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov } 1214ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov } 1215ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov 1216ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov /** 1217e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * Gets whether the selector wheel wraps when reaching the min/max value. 121868f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook * 1219e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @return True if the selector wheel wraps. 12204bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * 1221e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @see #getMinValue() 1222e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @see #getMaxValue() 122368f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook */ 1224e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov public boolean getWrapSelectorWheel() { 1225e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov return mWrapSelectorWheel; 1226206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1227206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 1228206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 1229e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * Sets whether the selector wheel shown during flinging/scrolling should 1230e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * wrap around the {@link NumberPicker#getMinValue()} and 1231e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * {@link NumberPicker#getMaxValue()} values. 1232e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * <p> 1233d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * By default if the range (max - min) is more than the number of items shown 1234d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * on the selector wheel the selector wheel wrapping is enabled. 1235e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * </p> 12363f9c9eab7b41c409c3c7b503b89ad340e408b6a0Svetoslav Ganov * <p> 1237d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * <strong>Note:</strong> If the number of items, i.e. the range ( 1238d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * {@link #getMaxValue()} - {@link #getMinValue()}) is less than 1239d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * the number of items shown on the selector wheel, the selector wheel will 1240d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * not wrap. Hence, in such a case calling this method is a NOP. 12413f9c9eab7b41c409c3c7b503b89ad340e408b6a0Svetoslav Ganov * </p> 1242d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * 12436304b0d58e74509a9f21b67b5227b2fee2f1b60fSvetoslav Ganov * @param wrapSelectorWheel Whether to wrap. 1244206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 12456304b0d58e74509a9f21b67b5227b2fee2f1b60fSvetoslav Ganov public void setWrapSelectorWheel(boolean wrapSelectorWheel) { 12463f9c9eab7b41c409c3c7b503b89ad340e408b6a0Svetoslav Ganov final boolean wrappingAllowed = (mMaxValue - mMinValue) >= mSelectorIndices.length; 12473f9c9eab7b41c409c3c7b503b89ad340e408b6a0Svetoslav Ganov if ((!wrapSelectorWheel || wrappingAllowed) && wrapSelectorWheel != mWrapSelectorWheel) { 12486304b0d58e74509a9f21b67b5227b2fee2f1b60fSvetoslav Ganov mWrapSelectorWheel = wrapSelectorWheel; 1249206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 12509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 12534bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * Sets the speed at which the numbers be incremented and decremented when 12544bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * the up and down buttons are long pressed respectively. 1255e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * <p> 1256e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * The default value is 300 ms. 1257e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * </p> 125868f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook * 12594bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * @param intervalMillis The speed (in milliseconds) at which the numbers 1260e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * will be incremented and decremented. 12619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 12624bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov public void setOnLongPressUpdateInterval(long intervalMillis) { 12634bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov mLongPressUpdateInterval = intervalMillis; 12649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1265fdf6db6748b32f620a7f68b13a67c38b4e59e5edTom Taylor 1266206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 1267e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * Returns the value of the picker. 1268e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * 1269e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @return The value. 1270e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov */ 1271e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov public int getValue() { 1272e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov return mValue; 1273e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov } 1274e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov 1275e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov /** 1276e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * Returns the min value of the picker. 1277e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * 1278e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @return The min value 1279e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov */ 1280e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov public int getMinValue() { 1281e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov return mMinValue; 1282e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov } 1283e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov 1284e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov /** 1285e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * Sets the min value of the picker. 1286206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * 1287e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @param minValue The min value. 1288206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 1289e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov public void setMinValue(int minValue) { 1290e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov if (mMinValue == minValue) { 1291e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov return; 1292e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov } 1293e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov if (minValue < 0) { 1294e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov throw new IllegalArgumentException("minValue must be >= 0"); 1295e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov } 1296e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov mMinValue = minValue; 1297e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov if (mMinValue > mValue) { 1298e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov mValue = mMinValue; 1299e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov } 1300e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov boolean wrapSelectorWheel = mMaxValue - mMinValue > mSelectorIndices.length; 1301e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov setWrapSelectorWheel(wrapSelectorWheel); 1302b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov initializeSelectorWheelIndices(); 1303e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov updateInputTextView(); 1304ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov tryComputeMaxWidth(); 1305d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov invalidate(); 1306206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1307206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 13084bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov /** 1309e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * Returns the max value of the picker. 13104bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * 1311e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @return The max value. 13124bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov */ 1313e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov public int getMaxValue() { 1314e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov return mMaxValue; 13154bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov } 13164bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov 13174bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov /** 1318e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * Sets the max value of the picker. 13194bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * 1320e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @param maxValue The max value. 13214bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov */ 1322e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov public void setMaxValue(int maxValue) { 1323e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov if (mMaxValue == maxValue) { 1324e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov return; 1325e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov } 1326e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov if (maxValue < 0) { 1327e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov throw new IllegalArgumentException("maxValue must be >= 0"); 1328e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov } 1329e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov mMaxValue = maxValue; 1330e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov if (mMaxValue < mValue) { 1331e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov mValue = mMaxValue; 1332e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov } 1333e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov boolean wrapSelectorWheel = mMaxValue - mMinValue > mSelectorIndices.length; 1334e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov setWrapSelectorWheel(wrapSelectorWheel); 1335b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov initializeSelectorWheelIndices(); 1336e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov updateInputTextView(); 1337ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov tryComputeMaxWidth(); 1338d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov invalidate(); 1339e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov } 1340e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov 1341e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov /** 1342e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * Gets the values to be displayed instead of string values. 1343e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * 1344e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @return The displayed values. 1345e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov */ 1346e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov public String[] getDisplayedValues() { 1347e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov return mDisplayedValues; 1348e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov } 1349e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov 1350e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov /** 1351e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * Sets the values to be displayed. 1352e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * 1353e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @param displayedValues The displayed values. 1354e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov */ 1355e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov public void setDisplayedValues(String[] displayedValues) { 1356e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov if (mDisplayedValues == displayedValues) { 1357e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov return; 1358e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov } 1359e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov mDisplayedValues = displayedValues; 1360e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov if (mDisplayedValues != null) { 1361e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov // Allow text entry rather than strictly numeric entry. 1362e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov mInputText.setRawInputType(InputType.TYPE_CLASS_TEXT 1363e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov | InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS); 1364a1410e6789ce72bc423793315a51aea8b6bad6c7Svetoslav Ganov // Make sure the min, max, respect the size of the displayed 1365a1410e6789ce72bc423793315a51aea8b6bad6c7Svetoslav Ganov // values. This will take care of the current value as well. 1366a1410e6789ce72bc423793315a51aea8b6bad6c7Svetoslav Ganov if (getMinValue() >= displayedValues.length) { 1367a1410e6789ce72bc423793315a51aea8b6bad6c7Svetoslav Ganov setMinValue(0); 1368a1410e6789ce72bc423793315a51aea8b6bad6c7Svetoslav Ganov } 1369a1410e6789ce72bc423793315a51aea8b6bad6c7Svetoslav Ganov if (getMaxValue() >= displayedValues.length) { 1370a1410e6789ce72bc423793315a51aea8b6bad6c7Svetoslav Ganov setMaxValue(displayedValues.length - 1); 1371a1410e6789ce72bc423793315a51aea8b6bad6c7Svetoslav Ganov } 1372e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov } else { 1373e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov mInputText.setRawInputType(InputType.TYPE_CLASS_NUMBER); 1374e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov } 1375e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov updateInputTextView(); 1376b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov initializeSelectorWheelIndices(); 13779f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov tryComputeMaxWidth(); 1378206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1379206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 1380206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov @Override 1381206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov protected float getTopFadingEdgeStrength() { 1382206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return TOP_AND_BOTTOM_FADING_EDGE_STRENGTH; 1383206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1384206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 1385206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov @Override 1386206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov protected float getBottomFadingEdgeStrength() { 1387206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return TOP_AND_BOTTOM_FADING_EDGE_STRENGTH; 1388206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1389206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 1390206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov @Override 1391206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov protected void onDetachedFromWindow() { 1392206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov removeAllCallbacks(); 1393206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1394206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 1395206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov @Override 1396206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov protected void onDraw(Canvas canvas) { 1397d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (!mHasSelectorWheel) { 1398d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov super.onDraw(canvas); 1399206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return; 1400206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1401206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov float x = (mRight - mLeft) / 2; 1402206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov float y = mCurrentScrollOffset; 1403206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 1404232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov // draw the virtual buttons pressed state if needed 1405232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov if (mVirtualButtonPressedDrawable != null 1406232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov && mScrollState == OnScrollListener.SCROLL_STATE_IDLE) { 1407232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov if (mDecrementVirtualButtonPressed) { 1408232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov mVirtualButtonPressedDrawable.setState(PRESSED_STATE_SET); 1409232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov mVirtualButtonPressedDrawable.setBounds(0, 0, mRight, mTopSelectionDividerTop); 1410232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov mVirtualButtonPressedDrawable.draw(canvas); 1411232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov } 1412232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov if (mIncrementVirtualButtonPressed) { 1413232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov mVirtualButtonPressedDrawable.setState(PRESSED_STATE_SET); 1414232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov mVirtualButtonPressedDrawable.setBounds(0, mBottomSelectionDividerBottom, mRight, 1415232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov mBottom); 1416232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov mVirtualButtonPressedDrawable.draw(canvas); 1417232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov } 1418232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov } 1419232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov 14209cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov // draw the selector wheel 1421b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov int[] selectorIndices = mSelectorIndices; 1422206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov for (int i = 0; i < selectorIndices.length; i++) { 1423206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov int selectorIndex = selectorIndices[i]; 1424206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov String scrollSelectorValue = mSelectorIndexToStringCache.get(selectorIndex); 1425d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov // Do not draw the middle item if input is visible since the input 1426d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov // is shown only if the wheel is static and it covers the middle 1427d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov // item. Otherwise, if the user starts editing the text via the 1428d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov // IME he may see a dimmed version of the old value intermixed 1429d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov // with the new one. 14306304b0d58e74509a9f21b67b5227b2fee2f1b60fSvetoslav Ganov if (i != SELECTOR_MIDDLE_ITEM_INDEX || mInputText.getVisibility() != VISIBLE) { 14316304b0d58e74509a9f21b67b5227b2fee2f1b60fSvetoslav Ganov canvas.drawText(scrollSelectorValue, x, y, mSelectorWheelPaint); 14326304b0d58e74509a9f21b67b5227b2fee2f1b60fSvetoslav Ganov } 1433206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov y += mSelectorElementHeight; 1434206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 14359cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov 1436d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov // draw the selection dividers 14379cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov if (mSelectionDivider != null) { 14389cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov // draw the top divider 1439d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov int topOfTopDivider = mTopSelectionDividerTop; 14409cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov int bottomOfTopDivider = topOfTopDivider + mSelectionDividerHeight; 14419cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov mSelectionDivider.setBounds(0, topOfTopDivider, mRight, bottomOfTopDivider); 14429cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov mSelectionDivider.draw(canvas); 14439cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov 14449cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov // draw the bottom divider 1445d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov int bottomOfBottomDivider = mBottomSelectionDividerBottom; 1446d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov int topOfBottomDivider = bottomOfBottomDivider - mSelectionDividerHeight; 14479cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov mSelectionDivider.setBounds(0, topOfBottomDivider, mRight, bottomOfBottomDivider); 14489cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov mSelectionDivider.draw(canvas); 14499cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov } 14509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1451fdf6db6748b32f620a7f68b13a67c38b4e59e5edTom Taylor 14523fec3fe0e3a83c5e0d1264f34bcc55b158537bc6Svetoslav Ganov @Override 14538a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov public void onInitializeAccessibilityEvent(AccessibilityEvent event) { 14548a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov super.onInitializeAccessibilityEvent(event); 14558a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov event.setClassName(NumberPicker.class.getName()); 1456d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov event.setScrollable(true); 1457d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov event.setScrollY((mMinValue + mValue) * mSelectorElementHeight); 1458d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov event.setMaxScrollY((mMaxValue - mMinValue) * mSelectorElementHeight); 14598a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov } 14608a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov 14618a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov @Override 1462d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov public AccessibilityNodeProvider getAccessibilityNodeProvider() { 1463d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (!mHasSelectorWheel) { 1464d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return super.getAccessibilityNodeProvider(); 1465d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 1466d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (mAccessibilityNodeProvider == null) { 1467d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mAccessibilityNodeProvider = new AccessibilityNodeProviderImpl(); 1468d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 1469d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return mAccessibilityNodeProvider; 14708a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov } 14718a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov 147268f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook /** 1473ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov * Makes a measure spec that tries greedily to use the max value. 1474e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov * 1475e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov * @param measureSpec The measure spec. 1476698e1d5d867a7ac653fa1d6f29cef4cfb73fad38Svetoslav Ganov * @param maxSize The max value for the size. 1477ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov * @return A measure spec greedily imposing the max size. 1478e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov */ 1479698e1d5d867a7ac653fa1d6f29cef4cfb73fad38Svetoslav Ganov private int makeMeasureSpec(int measureSpec, int maxSize) { 14809f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov if (maxSize == SIZE_UNSPECIFIED) { 14819f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov return measureSpec; 14829f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov } 1483ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov final int size = MeasureSpec.getSize(measureSpec); 1484e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov final int mode = MeasureSpec.getMode(measureSpec); 1485e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov switch (mode) { 1486e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov case MeasureSpec.EXACTLY: 1487ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov return measureSpec; 1488e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov case MeasureSpec.AT_MOST: 1489698e1d5d867a7ac653fa1d6f29cef4cfb73fad38Svetoslav Ganov return MeasureSpec.makeMeasureSpec(Math.min(size, maxSize), MeasureSpec.EXACTLY); 1490e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov case MeasureSpec.UNSPECIFIED: 1491698e1d5d867a7ac653fa1d6f29cef4cfb73fad38Svetoslav Ganov return MeasureSpec.makeMeasureSpec(maxSize, MeasureSpec.EXACTLY); 1492e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov default: 1493ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov throw new IllegalArgumentException("Unknown measure mode: " + mode); 1494e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov } 1495e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov } 1496e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov 1497e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov /** 1498d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * Utility to reconcile a desired size and state, with constraints imposed 1499d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * by a MeasureSpec. Tries to respect the min size, unless a different size 1500d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * is imposed by the constraints. 15019f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov * 15029f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov * @param minSize The minimal desired size. 15039f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov * @param measuredSize The currently measured size. 15049f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov * @param measureSpec The current measure spec. 15059f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov * @return The resolved size and state. 15069f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov */ 1507d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private int resolveSizeAndStateRespectingMinSize( 1508d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov int minSize, int measuredSize, int measureSpec) { 15099f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov if (minSize != SIZE_UNSPECIFIED) { 15109f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov final int desiredWidth = Math.max(minSize, measuredSize); 15119f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov return resolveSizeAndState(desiredWidth, measureSpec, 0); 15129f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov } else { 15139f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov return measuredSize; 15149f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov } 15159f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov } 15169f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov 15179f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov /** 1518d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * Resets the selector indices and clear the cached string representation of 1519d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * these indices. 1520a911d4a2b1be7e9ea909a579167826e4a5bac1a3Svetoslav Ganov */ 1521b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov private void initializeSelectorWheelIndices() { 1522a911d4a2b1be7e9ea909a579167826e4a5bac1a3Svetoslav Ganov mSelectorIndexToStringCache.clear(); 1523232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov int[] selectorIndices = mSelectorIndices; 1524b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov int current = getValue(); 1525b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov for (int i = 0; i < mSelectorIndices.length; i++) { 1526b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov int selectorIndex = current + (i - SELECTOR_MIDDLE_ITEM_INDEX); 1527b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov if (mWrapSelectorWheel) { 1528b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov selectorIndex = getWrappedSelectorIndex(selectorIndex); 1529b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov } 1530232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov selectorIndices[i] = selectorIndex; 1531232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov ensureCachedScrollSelectorValue(selectorIndices[i]); 1532a911d4a2b1be7e9ea909a579167826e4a5bac1a3Svetoslav Ganov } 1533a911d4a2b1be7e9ea909a579167826e4a5bac1a3Svetoslav Ganov } 1534a911d4a2b1be7e9ea909a579167826e4a5bac1a3Svetoslav Ganov 1535a911d4a2b1be7e9ea909a579167826e4a5bac1a3Svetoslav Ganov /** 1536d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * Sets the current value of this NumberPicker. 153768f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook * 1538d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * @param current The new value of the NumberPicker. 1539d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * @param notifyChange Whether to notify if the current value changed. 154068f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook */ 1541d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private void setValueInternal(int current, boolean notifyChange) { 1542e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov if (mValue == current) { 1543206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return; 1544206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 15459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Wrap around the values if we go past the start or end 1546e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov if (mWrapSelectorWheel) { 1547206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov current = getWrappedSelectorIndex(current); 1548d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } else { 1549d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov current = Math.max(current, mMinValue); 1550d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov current = Math.min(current, mMaxValue); 15519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1552e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov int previous = mValue; 1553d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mValue = current; 1554d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov updateInputTextView(); 1555d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (notifyChange) { 1556d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov notifyChange(previous, current); 1557d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 1558fac14f9731ce7fc765de582c983af751aab697deSvetoslav Ganov initializeSelectorWheelIndices(); 1559fac14f9731ce7fc765de582c983af751aab697deSvetoslav Ganov invalidate(); 15609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1561fdf6db6748b32f620a7f68b13a67c38b4e59e5edTom Taylor 156268f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook /** 1563b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov * Changes the current value by one which is increment or 1564b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov * decrement based on the passes argument. 1565d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * decrement the current value. 1566b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov * 1567b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov * @param increment True to increment, false to decrement. 1568b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov */ 1569d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private void changeValueByOne(boolean increment) { 1570d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (mHasSelectorWheel) { 1571b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov mInputText.setVisibility(View.INVISIBLE); 1572d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (!moveToFinalScrollerPosition(mFlingScroller)) { 1573d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov moveToFinalScrollerPosition(mAdjustScroller); 1574d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 1575b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov mPreviousScrollerY = 0; 1576b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov if (increment) { 1577fe41ce4ef97e7da585fdbf06988da8047e72b9f6Svetoslav Ganov mFlingScroller.startScroll(0, 0, 0, -mSelectorElementHeight, SNAP_SCROLL_DURATION); 1578b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov } else { 1579fe41ce4ef97e7da585fdbf06988da8047e72b9f6Svetoslav Ganov mFlingScroller.startScroll(0, 0, 0, mSelectorElementHeight, SNAP_SCROLL_DURATION); 1580b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov } 1581b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov invalidate(); 1582b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov } else { 1583b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov if (increment) { 1584d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov setValueInternal(mValue + 1, true); 1585b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov } else { 1586d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov setValueInternal(mValue - 1, true); 1587b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov } 1588b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov } 1589b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov } 1590b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov 1591b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov private void initializeSelectorWheel() { 1592b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov initializeSelectorWheelIndices(); 1593b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov int[] selectorIndices = mSelectorIndices; 15949cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov int totalTextHeight = selectorIndices.length * mTextSize; 159501fa0d7aae1a551e1e7cfb90d2aeaf2fcb3978afSvetoslav Ganov float totalTextGapHeight = (mBottom - mTop) - totalTextHeight; 1596d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov float textGapCount = selectorIndices.length; 1597b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov mSelectorTextGapHeight = (int) (totalTextGapHeight / textGapCount + 0.5f); 1598b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov mSelectorElementHeight = mTextSize + mSelectorTextGapHeight; 1599d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov // Ensure that the middle item is positioned the same as the text in 1600d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov // mInputText 1601eeafd4296b7cf4c2ad9c985562f6d70e2a3ffc03Chet Haase int editTextTextPosition = mInputText.getBaseline() + mInputText.getTop(); 1602d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mInitialScrollOffset = editTextTextPosition 1603d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov - (mSelectorElementHeight * SELECTOR_MIDDLE_ITEM_INDEX); 16046a19fcde07527706c2a9175e0b9f2a71549b7ffeSvetoslav Ganov mCurrentScrollOffset = mInitialScrollOffset; 16059cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov updateInputTextView(); 16069cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov } 16079cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov 1608b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov private void initializeFadingEdges() { 1609b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov setVerticalFadingEdgeEnabled(true); 1610b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov setFadingEdgeLength((mBottom - mTop - mTextSize) / 2); 1611b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov } 1612b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov 1613206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 1614206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Callback invoked upon completion of a given <code>scroller</code>. 1615206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 1616206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private void onScrollerFinished(Scroller scroller) { 1617206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (scroller == mFlingScroller) { 1618d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (!ensureScrollWheelAdjusted()) { 1619b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov updateInputTextView(); 1620b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov } 1621d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov onScrollStateChange(OnScrollListener.SCROLL_STATE_IDLE); 16229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 1623d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (mScrollState != OnScrollListener.SCROLL_STATE_TOUCH_SCROLL) { 1624d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov updateInputTextView(); 1625d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 16269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1628fdf6db6748b32f620a7f68b13a67c38b4e59e5edTom Taylor 1629206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 16309cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov * Handles transition to a given <code>scrollState</code> 163150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov */ 16329cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov private void onScrollStateChange(int scrollState) { 16339cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov if (mScrollState == scrollState) { 16349cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov return; 16359cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov } 16369cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov mScrollState = scrollState; 16379cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov if (mOnScrollListener != null) { 16384bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov mOnScrollListener.onScrollStateChange(this, scrollState); 163950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov } 164050f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov } 164150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 164250f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov /** 1643206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Flings the selector with the given <code>velocityY</code>. 1644206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 1645206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private void fling(int velocityY) { 1646206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mPreviousScrollerY = 0; 1647206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 1648234484a9fb53786aa8b7ed2a3df7e24d41817689Svetoslav Ganov if (velocityY > 0) { 1649234484a9fb53786aa8b7ed2a3df7e24d41817689Svetoslav Ganov mFlingScroller.fling(0, 0, 0, velocityY, 0, 0, 0, Integer.MAX_VALUE); 1650206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } else { 1651234484a9fb53786aa8b7ed2a3df7e24d41817689Svetoslav Ganov mFlingScroller.fling(0, Integer.MAX_VALUE, 0, velocityY, 0, 0, 0, Integer.MAX_VALUE); 16529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1653206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 1654206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov invalidate(); 16559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1657206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 1658206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * @return The wrapped index <code>selectorIndex</code> value. 165968f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook */ 1660206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private int getWrappedSelectorIndex(int selectorIndex) { 1661e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov if (selectorIndex > mMaxValue) { 1662e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov return mMinValue + (selectorIndex - mMaxValue) % (mMaxValue - mMinValue) - 1; 1663e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov } else if (selectorIndex < mMinValue) { 1664e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov return mMaxValue - (mMinValue - selectorIndex) % (mMaxValue - mMinValue) + 1; 1665206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1666206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return selectorIndex; 16679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1668fdf6db6748b32f620a7f68b13a67c38b4e59e5edTom Taylor 1669206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 1670206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Increments the <code>selectorIndices</code> whose string representations 1671206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * will be displayed in the selector. 1672206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 1673b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov private void incrementSelectorIndices(int[] selectorIndices) { 1674206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov for (int i = 0; i < selectorIndices.length - 1; i++) { 1675206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov selectorIndices[i] = selectorIndices[i + 1]; 1676206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1677206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov int nextScrollSelectorIndex = selectorIndices[selectorIndices.length - 2] + 1; 1678e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov if (mWrapSelectorWheel && nextScrollSelectorIndex > mMaxValue) { 1679e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov nextScrollSelectorIndex = mMinValue; 1680206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1681206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov selectorIndices[selectorIndices.length - 1] = nextScrollSelectorIndex; 1682206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov ensureCachedScrollSelectorValue(nextScrollSelectorIndex); 1683206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1684fdf6db6748b32f620a7f68b13a67c38b4e59e5edTom Taylor 1685206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 1686206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Decrements the <code>selectorIndices</code> whose string representations 1687206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * will be displayed in the selector. 1688206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 1689206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private void decrementSelectorIndices(int[] selectorIndices) { 1690206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov for (int i = selectorIndices.length - 1; i > 0; i--) { 1691206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov selectorIndices[i] = selectorIndices[i - 1]; 1692206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1693206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov int nextScrollSelectorIndex = selectorIndices[1] - 1; 1694e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov if (mWrapSelectorWheel && nextScrollSelectorIndex < mMinValue) { 1695e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov nextScrollSelectorIndex = mMaxValue; 1696206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1697206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov selectorIndices[0] = nextScrollSelectorIndex; 1698206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov ensureCachedScrollSelectorValue(nextScrollSelectorIndex); 1699206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1700fdf6db6748b32f620a7f68b13a67c38b4e59e5edTom Taylor 1701206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 1702206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Ensures we have a cached string representation of the given <code> 1703d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * selectorIndex</code> to avoid multiple instantiations of the same string. 1704206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 1705206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private void ensureCachedScrollSelectorValue(int selectorIndex) { 1706206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov SparseArray<String> cache = mSelectorIndexToStringCache; 1707206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov String scrollSelectorValue = cache.get(selectorIndex); 1708206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (scrollSelectorValue != null) { 1709206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return; 1710206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1711e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov if (selectorIndex < mMinValue || selectorIndex > mMaxValue) { 1712206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov scrollSelectorValue = ""; 1713206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } else { 1714206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (mDisplayedValues != null) { 1715e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov int displayedValueIndex = selectorIndex - mMinValue; 171650f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov scrollSelectorValue = mDisplayedValues[displayedValueIndex]; 1717206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } else { 1718206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov scrollSelectorValue = formatNumber(selectorIndex); 17199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 17209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1721206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov cache.put(selectorIndex, scrollSelectorValue); 17229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1723fdf6db6748b32f620a7f68b13a67c38b4e59e5edTom Taylor 1724206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private String formatNumber(int value) { 1725d88e3054d08b1f821bb2e27b2647aa16a60d8742Fabrice Di Meglio return (mFormatter != null) ? mFormatter.format(value) : formatNumberWithLocale(value); 1726206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 17279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1728206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private void validateInputTextView(View v) { 1729206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov String str = String.valueOf(((TextView) v).getText()); 1730206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (TextUtils.isEmpty(str)) { 1731206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // Restore to the old value as we don't allow empty values 1732206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov updateInputTextView(); 1733206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } else { 1734206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // Check the new value and ensure it's in range 1735206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov int current = getSelectedPos(str.toString()); 1736d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov setValueInternal(current, true); 17379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1738206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1739fdf6db6748b32f620a7f68b13a67c38b4e59e5edTom Taylor 1740206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 1741206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Updates the view of this NumberPicker. If displayValues were specified in 17429cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov * the string corresponding to the index specified by the current value will 17439cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov * be returned. Otherwise, the formatter specified in {@link #setFormatter} 17449cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov * will be used to format the number. 1745d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * 1746d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * @return Whether the text was updated. 1747206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 1748d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private boolean updateInputTextView() { 1749206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /* 1750206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * If we don't have displayed values then use the current number else 1751206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * find the correct value in the displayed values for the current 1752206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * number. 1753206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 1754d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov String text = (mDisplayedValues == null) ? formatNumber(mValue) 1755d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov : mDisplayedValues[mValue - mMinValue]; 1756d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (!TextUtils.isEmpty(text) && !text.equals(mInputText.getText().toString())) { 1757d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mInputText.setText(text); 1758d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return true; 17599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 17603fec3fe0e3a83c5e0d1264f34bcc55b158537bc6Svetoslav Ganov 1761d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return false; 1762206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1763fdf6db6748b32f620a7f68b13a67c38b4e59e5edTom Taylor 1764206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 1765206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Notifies the listener, if registered, of a change of the value of this 1766206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * NumberPicker. 1767206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 1768206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private void notifyChange(int previous, int current) { 1769cedc446684e94c9971c38c3206f1f224314bda2aSvetoslav Ganov if (mOnValueChangeListener != null) { 1770cedc446684e94c9971c38c3206f1f224314bda2aSvetoslav Ganov mOnValueChangeListener.onValueChange(this, previous, mValue); 1771206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1772206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 17739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1774206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 1775b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov * Posts a command for changing the current value by one. 1776b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov * 1777b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov * @param increment Whether to increment or decrement the value. 1778206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 1779d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private void postChangeCurrentByOneFromLongPress(boolean increment, long delayMillis) { 1780b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov if (mChangeCurrentByOneFromLongPressCommand == null) { 1781b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov mChangeCurrentByOneFromLongPressCommand = new ChangeCurrentByOneFromLongPressCommand(); 1782d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } else { 1783d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov removeCallbacks(mChangeCurrentByOneFromLongPressCommand); 1784d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 1785d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mChangeCurrentByOneFromLongPressCommand.setStep(increment); 1786d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov postDelayed(mChangeCurrentByOneFromLongPressCommand, delayMillis); 1787d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 1788d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 1789d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov /** 1790d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * Removes the command for changing the current value by one. 1791d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov */ 1792d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private void removeChangeCurrentByOneFromLongPress() { 1793d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (mChangeCurrentByOneFromLongPressCommand != null) { 1794d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov removeCallbacks(mChangeCurrentByOneFromLongPressCommand); 1795d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 1796d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 1797d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 1798d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov /** 1799d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * Posts a command for beginning an edit of the current value via IME on 1800d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * long press. 1801d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov */ 1802d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private void postBeginSoftInputOnLongPressCommand() { 1803d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (mBeginSoftInputOnLongPressCommand == null) { 1804d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mBeginSoftInputOnLongPressCommand = new BeginSoftInputOnLongPressCommand(); 1805d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } else { 1806d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov removeCallbacks(mBeginSoftInputOnLongPressCommand); 1807d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 1808d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov postDelayed(mBeginSoftInputOnLongPressCommand, ViewConfiguration.getLongPressTimeout()); 1809d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 1810d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 1811d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov /** 1812d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * Removes the command for beginning an edit of the current value via IME. 1813d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov */ 1814d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private void removeBeginSoftInputCommand() { 1815d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (mBeginSoftInputOnLongPressCommand != null) { 1816d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov removeCallbacks(mBeginSoftInputOnLongPressCommand); 1817206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1818206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 18199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1820206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 1821206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Removes all pending callback from the message queue. 1822206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 1823206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private void removeAllCallbacks() { 1824b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov if (mChangeCurrentByOneFromLongPressCommand != null) { 1825b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov removeCallbacks(mChangeCurrentByOneFromLongPressCommand); 1826206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1827206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (mSetSelectionCommand != null) { 1828206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov removeCallbacks(mSetSelectionCommand); 18299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1830d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (mBeginSoftInputOnLongPressCommand != null) { 1831d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov removeCallbacks(mBeginSoftInputOnLongPressCommand); 1832d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 1833232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov mPressedStateHelper.cancel(); 18349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 18359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1836206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 1837206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * @return The selected index given its displayed <code>value</code>. 1838206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 1839206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private int getSelectedPos(String value) { 18409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mDisplayedValues == null) { 1841aa516beb79693ceffbd81a7c9d14c940e412cccbRomain Guy try { 1842206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return Integer.parseInt(value); 1843aa516beb79693ceffbd81a7c9d14c940e412cccbRomain Guy } catch (NumberFormatException e) { 1844206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // Ignore as if it's not a number we don't care 1845aa516beb79693ceffbd81a7c9d14c940e412cccbRomain Guy } 18469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 18479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < mDisplayedValues.length; i++) { 1848206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // Don't force the user to type in jan when ja will do 1849206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov value = value.toLowerCase(); 1850206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (mDisplayedValues[i].toLowerCase().startsWith(value)) { 1851e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov return mMinValue + i; 18529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 18539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1854fdf6db6748b32f620a7f68b13a67c38b4e59e5edTom Taylor 1855206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /* 1856206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * The user might have typed in a number into the month field i.e. 18579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 10 instead of OCT so support that too. 18589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 18599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 1860206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return Integer.parseInt(value); 18619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (NumberFormatException e) { 1862fdf6db6748b32f620a7f68b13a67c38b4e59e5edTom Taylor 1863206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // Ignore as if it's not a number we don't care 18649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 18659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1866e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov return mMinValue; 18679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 18689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 18699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1870206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Posts an {@link SetSelectionCommand} from the given <code>selectionStart 1871d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * </code> to <code>selectionEnd</code>. 18729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1873206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private void postSetSelectionCommand(int selectionStart, int selectionEnd) { 1874206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (mSetSelectionCommand == null) { 1875206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mSetSelectionCommand = new SetSelectionCommand(); 1876206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } else { 1877206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov removeCallbacks(mSetSelectionCommand); 1878206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1879206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mSetSelectionCommand.mSelectionStart = selectionStart; 1880206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mSetSelectionCommand.mSelectionEnd = selectionEnd; 1881206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov post(mSetSelectionCommand); 18829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 188368f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook 188468f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook /** 1885d88e3054d08b1f821bb2e27b2647aa16a60d8742Fabrice Di Meglio * The numbers accepted by the input text's {@link Filter} 1886d88e3054d08b1f821bb2e27b2647aa16a60d8742Fabrice Di Meglio */ 1887d88e3054d08b1f821bb2e27b2647aa16a60d8742Fabrice Di Meglio private static final char[] DIGIT_CHARACTERS = new char[] { 1888d88e3054d08b1f821bb2e27b2647aa16a60d8742Fabrice Di Meglio // Latin digits are the common case 1889d88e3054d08b1f821bb2e27b2647aa16a60d8742Fabrice Di Meglio '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 1890d88e3054d08b1f821bb2e27b2647aa16a60d8742Fabrice Di Meglio // Arabic-Indic 1891d88e3054d08b1f821bb2e27b2647aa16a60d8742Fabrice Di Meglio '\u0660', '\u0661', '\u0662', '\u0663', '\u0664', '\u0665', '\u0666', '\u0667', '\u0668' 1892d88e3054d08b1f821bb2e27b2647aa16a60d8742Fabrice Di Meglio , '\u0669', 1893d88e3054d08b1f821bb2e27b2647aa16a60d8742Fabrice Di Meglio // Extended Arabic-Indic 1894d88e3054d08b1f821bb2e27b2647aa16a60d8742Fabrice Di Meglio '\u06f0', '\u06f1', '\u06f2', '\u06f3', '\u06f4', '\u06f5', '\u06f6', '\u06f7', '\u06f8' 1895d88e3054d08b1f821bb2e27b2647aa16a60d8742Fabrice Di Meglio , '\u06f9' 1896d88e3054d08b1f821bb2e27b2647aa16a60d8742Fabrice Di Meglio }; 1897d88e3054d08b1f821bb2e27b2647aa16a60d8742Fabrice Di Meglio 1898d88e3054d08b1f821bb2e27b2647aa16a60d8742Fabrice Di Meglio /** 1899206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Filter for accepting only valid indices or prefixes of the string 1900206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * representation of valid indices. 190168f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook */ 1902206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov class InputTextFilter extends NumberKeyListener { 1903206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 1904206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // XXX This doesn't allow for range limits when controlled by a 1905206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // soft input method! 1906206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov public int getInputType() { 1907206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return InputType.TYPE_CLASS_TEXT; 1908206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1909206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 1910206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov @Override 1911206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov protected char[] getAcceptedChars() { 1912206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return DIGIT_CHARACTERS; 1913206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1914206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 1915206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov @Override 1916d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov public CharSequence filter( 1917d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov CharSequence source, int start, int end, Spanned dest, int dstart, int dend) { 1918206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (mDisplayedValues == null) { 1919206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov CharSequence filtered = super.filter(source, start, end, dest, dstart, dend); 1920206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (filtered == null) { 1921206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov filtered = source.subSequence(start, end); 1922206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1923206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 1924206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov String result = String.valueOf(dest.subSequence(0, dstart)) + filtered 1925206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov + dest.subSequence(dend, dest.length()); 1926206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 1927206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if ("".equals(result)) { 1928206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return result; 1929206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1930206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov int val = getSelectedPos(result); 1931206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 1932206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /* 1933206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Ensure the user can't type in a value greater than the max 1934206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * allowed. We have to allow less than min as the user might 1935206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * want to delete some numbers and then type a new number. 1936206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 1937e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov if (val > mMaxValue) { 1938206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return ""; 1939206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } else { 1940206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return filtered; 1941206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1942206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } else { 1943206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov CharSequence filtered = String.valueOf(source.subSequence(start, end)); 1944206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (TextUtils.isEmpty(filtered)) { 1945206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return ""; 1946206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1947206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov String result = String.valueOf(dest.subSequence(0, dstart)) + filtered 1948206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov + dest.subSequence(dend, dest.length()); 1949206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov String str = String.valueOf(result).toLowerCase(); 1950206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov for (String val : mDisplayedValues) { 1951206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov String valLowerCase = val.toLowerCase(); 1952206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (valLowerCase.startsWith(str)) { 1953206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov postSetSelectionCommand(result.length(), val.length()); 1954206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return val.subSequence(dstart, val.length()); 1955206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1956206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1957206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return ""; 1958206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1959206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1960206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1961206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 1962206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 1963d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * Ensures that the scroll wheel is adjusted i.e. there is no offset and the 1964d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * middle element is in the middle of the widget. 1965d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * 1966d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * @return Whether an adjustment has been made. 1967d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov */ 1968d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private boolean ensureScrollWheelAdjusted() { 1969d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov // adjust to the closest value 1970d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov int deltaY = mInitialScrollOffset - mCurrentScrollOffset; 1971d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (deltaY != 0) { 1972d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mPreviousScrollerY = 0; 1973d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (Math.abs(deltaY) > mSelectorElementHeight / 2) { 1974d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov deltaY += (deltaY > 0) ? -mSelectorElementHeight : mSelectorElementHeight; 1975d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 1976d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mAdjustScroller.startScroll(0, 0, 0, deltaY, SELECTOR_ADJUSTMENT_DURATION_MILLIS); 1977d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov invalidate(); 1978d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return true; 1979d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 1980d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return false; 1981d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 1982d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 1983232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov class PressedStateHelper implements Runnable { 1984232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov public static final int BUTTON_INCREMENT = 1; 1985232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov public static final int BUTTON_DECREMENT = 2; 1986232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov 1987232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov private final int MODE_PRESS = 1; 1988232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov private final int MODE_TAPPED = 2; 1989232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov 1990232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov private int mManagedButton; 1991232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov private int mMode; 1992232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov 1993232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov public void cancel() { 1994232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov mMode = 0; 1995232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov mManagedButton = 0; 1996232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov NumberPicker.this.removeCallbacks(this); 1997232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov if (mIncrementVirtualButtonPressed) { 1998232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov mIncrementVirtualButtonPressed = false; 1999232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov invalidate(0, mBottomSelectionDividerBottom, mRight, mBottom); 2000232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov } 2001232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov mDecrementVirtualButtonPressed = false; 2002232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov if (mDecrementVirtualButtonPressed) { 2003232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov invalidate(0, 0, mRight, mTopSelectionDividerTop); 2004fe41ce4ef97e7da585fdbf06988da8047e72b9f6Svetoslav Ganov } 2005fe41ce4ef97e7da585fdbf06988da8047e72b9f6Svetoslav Ganov } 2006fe41ce4ef97e7da585fdbf06988da8047e72b9f6Svetoslav Ganov 2007232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov public void buttonPressDelayed(int button) { 2008232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov cancel(); 2009232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov mMode = MODE_PRESS; 2010232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov mManagedButton = button; 2011232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov NumberPicker.this.postDelayed(this, ViewConfiguration.getTapTimeout()); 2012232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov } 2013232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov 2014232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov public void buttonTapped(int button) { 2015232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov cancel(); 2016232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov mMode = MODE_TAPPED; 2017232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov mManagedButton = button; 2018232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov NumberPicker.this.post(this); 2019232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov } 2020232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov 2021232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov @Override 2022232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov public void run() { 2023232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov switch (mMode) { 2024232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov case MODE_PRESS: { 2025232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov switch (mManagedButton) { 2026232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov case BUTTON_INCREMENT: { 2027232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov mIncrementVirtualButtonPressed = true; 2028232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov invalidate(0, mBottomSelectionDividerBottom, mRight, mBottom); 2029232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov } break; 2030232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov case BUTTON_DECREMENT: { 2031232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov mDecrementVirtualButtonPressed = true; 2032232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov invalidate(0, 0, mRight, mTopSelectionDividerTop); 2033232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov } 2034232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov } 2035232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov } break; 2036232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov case MODE_TAPPED: { 2037232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov switch (mManagedButton) { 2038232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov case BUTTON_INCREMENT: { 2039232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov if (!mIncrementVirtualButtonPressed) { 2040232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov NumberPicker.this.postDelayed(this, 2041232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov ViewConfiguration.getPressedStateDuration()); 2042232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov } 2043232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov mIncrementVirtualButtonPressed ^= true; 2044232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov invalidate(0, mBottomSelectionDividerBottom, mRight, mBottom); 2045232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov } break; 2046232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov case BUTTON_DECREMENT: { 2047232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov if (!mDecrementVirtualButtonPressed) { 2048232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov NumberPicker.this.postDelayed(this, 2049232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov ViewConfiguration.getPressedStateDuration()); 2050232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov } 2051232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov mDecrementVirtualButtonPressed ^= true; 2052232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov invalidate(0, 0, mRight, mTopSelectionDividerTop); 2053232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov } 2054232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov } 2055232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov } break; 2056fe41ce4ef97e7da585fdbf06988da8047e72b9f6Svetoslav Ganov } 2057fe41ce4ef97e7da585fdbf06988da8047e72b9f6Svetoslav Ganov } 2058fe41ce4ef97e7da585fdbf06988da8047e72b9f6Svetoslav Ganov } 2059fe41ce4ef97e7da585fdbf06988da8047e72b9f6Svetoslav Ganov 2060d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov /** 2061206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Command for setting the input text selection. 2062206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 2063206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov class SetSelectionCommand implements Runnable { 2064206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private int mSelectionStart; 2065206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 2066206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private int mSelectionEnd; 2067206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 2068206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov public void run() { 2069206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mInputText.setSelection(mSelectionStart, mSelectionEnd); 2070206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 2071206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 2072206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 2073206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 2074b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov * Command for changing the current value from a long press by one. 2075206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 2076b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov class ChangeCurrentByOneFromLongPressCommand implements Runnable { 2077b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov private boolean mIncrement; 2078206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 2079d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private void setStep(boolean increment) { 2080b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov mIncrement = increment; 2081206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 2082206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 2083d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov @Override 2084206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov public void run() { 2085d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov changeValueByOne(mIncrement); 20864bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov postDelayed(this, mLongPressUpdateInterval); 2087206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 208868f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook } 2089a2b41b438d45570867e4682c0caaf93ace5e712eSvetoslav Ganov 2090a2b41b438d45570867e4682c0caaf93ace5e712eSvetoslav Ganov /** 2091a2b41b438d45570867e4682c0caaf93ace5e712eSvetoslav Ganov * @hide 2092a2b41b438d45570867e4682c0caaf93ace5e712eSvetoslav Ganov */ 2093a2b41b438d45570867e4682c0caaf93ace5e712eSvetoslav Ganov public static class CustomEditText extends EditText { 2094a2b41b438d45570867e4682c0caaf93ace5e712eSvetoslav Ganov 2095a2b41b438d45570867e4682c0caaf93ace5e712eSvetoslav Ganov public CustomEditText(Context context, AttributeSet attrs) { 2096a2b41b438d45570867e4682c0caaf93ace5e712eSvetoslav Ganov super(context, attrs); 2097a2b41b438d45570867e4682c0caaf93ace5e712eSvetoslav Ganov } 2098a2b41b438d45570867e4682c0caaf93ace5e712eSvetoslav Ganov 2099a2b41b438d45570867e4682c0caaf93ace5e712eSvetoslav Ganov @Override 2100a2b41b438d45570867e4682c0caaf93ace5e712eSvetoslav Ganov public void onEditorAction(int actionCode) { 2101a2b41b438d45570867e4682c0caaf93ace5e712eSvetoslav Ganov super.onEditorAction(actionCode); 2102a2b41b438d45570867e4682c0caaf93ace5e712eSvetoslav Ganov if (actionCode == EditorInfo.IME_ACTION_DONE) { 2103a2b41b438d45570867e4682c0caaf93ace5e712eSvetoslav Ganov clearFocus(); 2104a2b41b438d45570867e4682c0caaf93ace5e712eSvetoslav Ganov } 2105a2b41b438d45570867e4682c0caaf93ace5e712eSvetoslav Ganov } 2106a2b41b438d45570867e4682c0caaf93ace5e712eSvetoslav Ganov } 2107d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 2108d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov /** 2109d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * Command for beginning soft input on long press. 2110d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov */ 2111d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov class BeginSoftInputOnLongPressCommand implements Runnable { 2112d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 2113d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov @Override 2114d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov public void run() { 2115d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov showSoftInput(); 2116d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mIngonreMoveEvents = true; 2117d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2118d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2119d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 2120791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov /** 2121791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov * Class for managing virtual view tree rooted at this picker. 2122791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov */ 2123d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov class AccessibilityNodeProviderImpl extends AccessibilityNodeProvider { 2124791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov private static final int UNDEFINED = Integer.MIN_VALUE; 2125791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov 2126d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private static final int VIRTUAL_VIEW_ID_INCREMENT = 1; 2127d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 2128d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private static final int VIRTUAL_VIEW_ID_INPUT = 2; 2129d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 2130d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private static final int VIRTUAL_VIEW_ID_DECREMENT = 3; 2131d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 2132d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private final Rect mTempRect = new Rect(); 2133d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 2134d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private final int[] mTempArray = new int[2]; 2135d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 2136791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov private int mAccessibilityFocusedView = UNDEFINED; 2137791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov 2138d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov @Override 2139d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov public AccessibilityNodeInfo createAccessibilityNodeInfo(int virtualViewId) { 2140d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov switch (virtualViewId) { 2141d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov case View.NO_ID: 2142d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return createAccessibilityNodeInfoForNumberPicker( mScrollX, mScrollY, 2143d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mScrollX + (mRight - mLeft), mScrollY + (mBottom - mTop)); 2144d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov case VIRTUAL_VIEW_ID_DECREMENT: 2145d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return createAccessibilityNodeInfoForVirtualButton(VIRTUAL_VIEW_ID_DECREMENT, 2146d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov getVirtualDecrementButtonText(), mScrollX, mScrollY, 2147d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mScrollX + (mRight - mLeft), 2148d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mTopSelectionDividerTop + mSelectionDividerHeight); 2149d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov case VIRTUAL_VIEW_ID_INPUT: 2150d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return createAccessibiltyNodeInfoForInputText(); 2151d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov case VIRTUAL_VIEW_ID_INCREMENT: 2152d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return createAccessibilityNodeInfoForVirtualButton(VIRTUAL_VIEW_ID_INCREMENT, 2153d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov getVirtualIncrementButtonText(), mScrollX, 2154d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mBottomSelectionDividerBottom - mSelectionDividerHeight, 2155d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mScrollX + (mRight - mLeft), mScrollY + (mBottom - mTop)); 2156d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2157d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return super.createAccessibilityNodeInfo(virtualViewId); 2158d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2159d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 2160d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov @Override 2161d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov public List<AccessibilityNodeInfo> findAccessibilityNodeInfosByText(String searched, 2162d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov int virtualViewId) { 2163d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (TextUtils.isEmpty(searched)) { 2164d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return Collections.emptyList(); 2165d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2166d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov String searchedLowerCase = searched.toLowerCase(); 2167d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov List<AccessibilityNodeInfo> result = new ArrayList<AccessibilityNodeInfo>(); 2168d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov switch (virtualViewId) { 2169d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov case View.NO_ID: { 2170d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov findAccessibilityNodeInfosByTextInChild(searchedLowerCase, 2171d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov VIRTUAL_VIEW_ID_DECREMENT, result); 2172d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov findAccessibilityNodeInfosByTextInChild(searchedLowerCase, 2173d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov VIRTUAL_VIEW_ID_INPUT, result); 2174d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov findAccessibilityNodeInfosByTextInChild(searchedLowerCase, 2175d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov VIRTUAL_VIEW_ID_INCREMENT, result); 2176d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return result; 2177d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2178d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov case VIRTUAL_VIEW_ID_DECREMENT: 2179d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov case VIRTUAL_VIEW_ID_INCREMENT: 2180d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov case VIRTUAL_VIEW_ID_INPUT: { 2181d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov findAccessibilityNodeInfosByTextInChild(searchedLowerCase, virtualViewId, 2182d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov result); 2183d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return result; 2184d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2185d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2186d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return super.findAccessibilityNodeInfosByText(searched, virtualViewId); 2187d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2188d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 2189d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov @Override 2190aa780c110922148a6a4ba06734bb2b0bb8c98f93Svetoslav Ganov public boolean performAction(int virtualViewId, int action, Bundle arguments) { 2191d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov switch (virtualViewId) { 2192791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov case View.NO_ID: { 2193791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov switch (action) { 2194791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov case AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS: { 2195791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov if (mAccessibilityFocusedView != virtualViewId) { 2196791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov mAccessibilityFocusedView = virtualViewId; 2197791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov requestAccessibilityFocus(); 2198791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov return true; 2199791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } 2200791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } return false; 2201791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov case AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS: { 2202791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov if (mAccessibilityFocusedView == virtualViewId) { 2203791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov mAccessibilityFocusedView = UNDEFINED; 2204791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov clearAccessibilityFocus(); 2205791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov return true; 2206791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } 2207791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov return false; 2208791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } 220948d1586f4065fc9ab97a679da1e4f7c327c943f2Svetoslav Ganov case AccessibilityNodeInfo.ACTION_SCROLL_FORWARD: { 2210fb1e80a247221ee7e8f5c5deba04812021d9d07eSvetoslav Ganov if (NumberPicker.this.isEnabled() 2211fb1e80a247221ee7e8f5c5deba04812021d9d07eSvetoslav Ganov && (getWrapSelectorWheel() || getValue() < getMaxValue())) { 221248d1586f4065fc9ab97a679da1e4f7c327c943f2Svetoslav Ganov changeValueByOne(true); 221348d1586f4065fc9ab97a679da1e4f7c327c943f2Svetoslav Ganov return true; 221448d1586f4065fc9ab97a679da1e4f7c327c943f2Svetoslav Ganov } 221548d1586f4065fc9ab97a679da1e4f7c327c943f2Svetoslav Ganov } return false; 221648d1586f4065fc9ab97a679da1e4f7c327c943f2Svetoslav Ganov case AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD: { 2217fb1e80a247221ee7e8f5c5deba04812021d9d07eSvetoslav Ganov if (NumberPicker.this.isEnabled() 2218fb1e80a247221ee7e8f5c5deba04812021d9d07eSvetoslav Ganov && (getWrapSelectorWheel() || getValue() > getMinValue())) { 221948d1586f4065fc9ab97a679da1e4f7c327c943f2Svetoslav Ganov changeValueByOne(false); 222048d1586f4065fc9ab97a679da1e4f7c327c943f2Svetoslav Ganov return true; 222148d1586f4065fc9ab97a679da1e4f7c327c943f2Svetoslav Ganov } 222248d1586f4065fc9ab97a679da1e4f7c327c943f2Svetoslav Ganov } return false; 2223791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } 2224791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } break; 2225d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov case VIRTUAL_VIEW_ID_INPUT: { 2226d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov switch (action) { 2227d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov case AccessibilityNodeInfo.ACTION_FOCUS: { 2228fb1e80a247221ee7e8f5c5deba04812021d9d07eSvetoslav Ganov if (NumberPicker.this.isEnabled() && !mInputText.isFocused()) { 2229d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return mInputText.requestFocus(); 2230d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2231d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } break; 2232d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov case AccessibilityNodeInfo.ACTION_CLEAR_FOCUS: { 2233fb1e80a247221ee7e8f5c5deba04812021d9d07eSvetoslav Ganov if (NumberPicker.this.isEnabled() && mInputText.isFocused()) { 2234d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mInputText.clearFocus(); 2235d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return true; 2236d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2237791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov return false; 2238791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } 2239791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov case AccessibilityNodeInfo.ACTION_CLICK: { 2240fb1e80a247221ee7e8f5c5deba04812021d9d07eSvetoslav Ganov if (NumberPicker.this.isEnabled()) { 2241fb1e80a247221ee7e8f5c5deba04812021d9d07eSvetoslav Ganov showSoftInput(); 2242fb1e80a247221ee7e8f5c5deba04812021d9d07eSvetoslav Ganov return true; 2243fb1e80a247221ee7e8f5c5deba04812021d9d07eSvetoslav Ganov } 2244fb1e80a247221ee7e8f5c5deba04812021d9d07eSvetoslav Ganov return false; 2245791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } 2246791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov case AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS: { 2247791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov if (mAccessibilityFocusedView != virtualViewId) { 2248791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov mAccessibilityFocusedView = virtualViewId; 2249791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov sendAccessibilityEventForVirtualView(virtualViewId, 2250791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED); 2251791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov mInputText.invalidate(); 2252791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov return true; 2253791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } 2254791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } return false; 2255791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov case AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS: { 2256791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov if (mAccessibilityFocusedView == virtualViewId) { 2257791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov mAccessibilityFocusedView = UNDEFINED; 2258791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov sendAccessibilityEventForVirtualView(virtualViewId, 2259791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED); 2260791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov mInputText.invalidate(); 2261791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov return true; 2262791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } 2263791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } return false; 2264791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov default: { 2265791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov return mInputText.performAccessibilityAction(action, arguments); 2266791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } 2267d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2268791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } return false; 2269791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov case VIRTUAL_VIEW_ID_INCREMENT: { 2270791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov switch (action) { 2271791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov case AccessibilityNodeInfo.ACTION_CLICK: { 2272fb1e80a247221ee7e8f5c5deba04812021d9d07eSvetoslav Ganov if (NumberPicker.this.isEnabled()) { 2273fb1e80a247221ee7e8f5c5deba04812021d9d07eSvetoslav Ganov NumberPicker.this.changeValueByOne(true); 2274fb1e80a247221ee7e8f5c5deba04812021d9d07eSvetoslav Ganov sendAccessibilityEventForVirtualView(virtualViewId, 2275fb1e80a247221ee7e8f5c5deba04812021d9d07eSvetoslav Ganov AccessibilityEvent.TYPE_VIEW_CLICKED); 2276fb1e80a247221ee7e8f5c5deba04812021d9d07eSvetoslav Ganov return true; 2277fb1e80a247221ee7e8f5c5deba04812021d9d07eSvetoslav Ganov } 2278fb1e80a247221ee7e8f5c5deba04812021d9d07eSvetoslav Ganov } return false; 2279791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov case AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS: { 2280791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov if (mAccessibilityFocusedView != virtualViewId) { 2281791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov mAccessibilityFocusedView = virtualViewId; 2282791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov sendAccessibilityEventForVirtualView(virtualViewId, 2283791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED); 2284791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov invalidate(0, mBottomSelectionDividerBottom, mRight, mBottom); 2285791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov return true; 2286791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } 2287791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } return false; 2288791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov case AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS: { 2289791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov if (mAccessibilityFocusedView == virtualViewId) { 2290791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov mAccessibilityFocusedView = UNDEFINED; 2291791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov sendAccessibilityEventForVirtualView(virtualViewId, 2292791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED); 2293791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov invalidate(0, mBottomSelectionDividerBottom, mRight, mBottom); 2294791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov return true; 2295791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } 2296791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } return false; 2297791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } 2298791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } return false; 2299791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov case VIRTUAL_VIEW_ID_DECREMENT: { 2300791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov switch (action) { 2301791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov case AccessibilityNodeInfo.ACTION_CLICK: { 2302fb1e80a247221ee7e8f5c5deba04812021d9d07eSvetoslav Ganov if (NumberPicker.this.isEnabled()) { 2303fb1e80a247221ee7e8f5c5deba04812021d9d07eSvetoslav Ganov final boolean increment = (virtualViewId == VIRTUAL_VIEW_ID_INCREMENT); 2304fb1e80a247221ee7e8f5c5deba04812021d9d07eSvetoslav Ganov NumberPicker.this.changeValueByOne(increment); 2305fb1e80a247221ee7e8f5c5deba04812021d9d07eSvetoslav Ganov sendAccessibilityEventForVirtualView(virtualViewId, 2306fb1e80a247221ee7e8f5c5deba04812021d9d07eSvetoslav Ganov AccessibilityEvent.TYPE_VIEW_CLICKED); 2307fb1e80a247221ee7e8f5c5deba04812021d9d07eSvetoslav Ganov return true; 2308fb1e80a247221ee7e8f5c5deba04812021d9d07eSvetoslav Ganov } 2309fb1e80a247221ee7e8f5c5deba04812021d9d07eSvetoslav Ganov } return false; 2310791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov case AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS: { 2311791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov if (mAccessibilityFocusedView != virtualViewId) { 2312791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov mAccessibilityFocusedView = virtualViewId; 2313791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov sendAccessibilityEventForVirtualView(virtualViewId, 2314791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED); 2315791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov invalidate(0, 0, mRight, mTopSelectionDividerTop); 2316791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov return true; 2317791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } 2318791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } return false; 2319791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov case AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS: { 2320791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov if (mAccessibilityFocusedView == virtualViewId) { 2321791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov mAccessibilityFocusedView = UNDEFINED; 2322791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov sendAccessibilityEventForVirtualView(virtualViewId, 2323791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED); 2324791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov invalidate(0, 0, mRight, mTopSelectionDividerTop); 2325791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov return true; 2326791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } 2327791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } return false; 2328791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } 2329791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } return false; 2330d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2331aa780c110922148a6a4ba06734bb2b0bb8c98f93Svetoslav Ganov return super.performAction(virtualViewId, action, arguments); 2332d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2333d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 2334d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov public void sendAccessibilityEventForVirtualView(int virtualViewId, int eventType) { 2335d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov switch (virtualViewId) { 2336d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov case VIRTUAL_VIEW_ID_DECREMENT: { 2337791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov if (hasVirtualDecrementButton()) { 2338791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov sendAccessibilityEventForVirtualButton(virtualViewId, eventType, 2339791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov getVirtualDecrementButtonText()); 2340791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } 2341d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } break; 2342d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov case VIRTUAL_VIEW_ID_INPUT: { 2343d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov sendAccessibilityEventForVirtualText(eventType); 2344d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } break; 2345d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov case VIRTUAL_VIEW_ID_INCREMENT: { 2346791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov if (hasVirtualIncrementButton()) { 2347791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov sendAccessibilityEventForVirtualButton(virtualViewId, eventType, 2348791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov getVirtualIncrementButtonText()); 2349791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } 2350d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } break; 2351d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2352d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2353d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 2354d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private void sendAccessibilityEventForVirtualText(int eventType) { 2355a90927629881f0faf54c1003ebd38c27a730045eSvetoslav Ganov if (AccessibilityManager.getInstance(mContext).isEnabled()) { 2356a90927629881f0faf54c1003ebd38c27a730045eSvetoslav Ganov AccessibilityEvent event = AccessibilityEvent.obtain(eventType); 2357a90927629881f0faf54c1003ebd38c27a730045eSvetoslav Ganov mInputText.onInitializeAccessibilityEvent(event); 2358a90927629881f0faf54c1003ebd38c27a730045eSvetoslav Ganov mInputText.onPopulateAccessibilityEvent(event); 2359a90927629881f0faf54c1003ebd38c27a730045eSvetoslav Ganov event.setSource(NumberPicker.this, VIRTUAL_VIEW_ID_INPUT); 2360a90927629881f0faf54c1003ebd38c27a730045eSvetoslav Ganov requestSendAccessibilityEvent(NumberPicker.this, event); 2361a90927629881f0faf54c1003ebd38c27a730045eSvetoslav Ganov } 2362d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2363d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 2364d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private void sendAccessibilityEventForVirtualButton(int virtualViewId, int eventType, 2365d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov String text) { 2366a90927629881f0faf54c1003ebd38c27a730045eSvetoslav Ganov if (AccessibilityManager.getInstance(mContext).isEnabled()) { 2367a90927629881f0faf54c1003ebd38c27a730045eSvetoslav Ganov AccessibilityEvent event = AccessibilityEvent.obtain(eventType); 2368a90927629881f0faf54c1003ebd38c27a730045eSvetoslav Ganov event.setClassName(Button.class.getName()); 2369a90927629881f0faf54c1003ebd38c27a730045eSvetoslav Ganov event.setPackageName(mContext.getPackageName()); 2370a90927629881f0faf54c1003ebd38c27a730045eSvetoslav Ganov event.getText().add(text); 2371a90927629881f0faf54c1003ebd38c27a730045eSvetoslav Ganov event.setEnabled(NumberPicker.this.isEnabled()); 2372a90927629881f0faf54c1003ebd38c27a730045eSvetoslav Ganov event.setSource(NumberPicker.this, virtualViewId); 2373a90927629881f0faf54c1003ebd38c27a730045eSvetoslav Ganov requestSendAccessibilityEvent(NumberPicker.this, event); 2374a90927629881f0faf54c1003ebd38c27a730045eSvetoslav Ganov } 2375d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2376d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 2377d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private void findAccessibilityNodeInfosByTextInChild(String searchedLowerCase, 2378d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov int virtualViewId, List<AccessibilityNodeInfo> outResult) { 2379d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov switch (virtualViewId) { 2380d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov case VIRTUAL_VIEW_ID_DECREMENT: { 2381d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov String text = getVirtualDecrementButtonText(); 2382d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (!TextUtils.isEmpty(text) 2383d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov && text.toString().toLowerCase().contains(searchedLowerCase)) { 2384d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov outResult.add(createAccessibilityNodeInfo(VIRTUAL_VIEW_ID_DECREMENT)); 2385d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2386d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } return; 2387d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov case VIRTUAL_VIEW_ID_INPUT: { 2388d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov CharSequence text = mInputText.getText(); 2389d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (!TextUtils.isEmpty(text) && 2390d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov text.toString().toLowerCase().contains(searchedLowerCase)) { 2391d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov outResult.add(createAccessibilityNodeInfo(VIRTUAL_VIEW_ID_INPUT)); 2392d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return; 2393d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2394d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov CharSequence contentDesc = mInputText.getText(); 2395d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (!TextUtils.isEmpty(contentDesc) && 2396d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov contentDesc.toString().toLowerCase().contains(searchedLowerCase)) { 2397d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov outResult.add(createAccessibilityNodeInfo(VIRTUAL_VIEW_ID_INPUT)); 2398d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return; 2399d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2400d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } break; 2401d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov case VIRTUAL_VIEW_ID_INCREMENT: { 2402d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov String text = getVirtualIncrementButtonText(); 2403d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (!TextUtils.isEmpty(text) 2404d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov && text.toString().toLowerCase().contains(searchedLowerCase)) { 2405d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov outResult.add(createAccessibilityNodeInfo(VIRTUAL_VIEW_ID_INCREMENT)); 2406d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2407d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } return; 2408d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2409d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2410d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 2411d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private AccessibilityNodeInfo createAccessibiltyNodeInfoForInputText() { 2412d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov AccessibilityNodeInfo info = mInputText.createAccessibilityNodeInfo(); 2413d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov info.setSource(NumberPicker.this, VIRTUAL_VIEW_ID_INPUT); 2414791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov if (mAccessibilityFocusedView != VIRTUAL_VIEW_ID_INPUT) { 2415791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov info.addAction(AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS); 2416791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } 2417791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov if (mAccessibilityFocusedView == VIRTUAL_VIEW_ID_INPUT) { 2418791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov info.addAction(AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS); 2419791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } 2420d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return info; 2421d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2422d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 2423d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private AccessibilityNodeInfo createAccessibilityNodeInfoForVirtualButton(int virtualViewId, 2424d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov String text, int left, int top, int right, int bottom) { 2425d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain(); 2426d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov info.setClassName(Button.class.getName()); 2427d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov info.setPackageName(mContext.getPackageName()); 2428d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov info.setSource(NumberPicker.this, virtualViewId); 2429d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov info.setParent(NumberPicker.this); 2430d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov info.setText(text); 2431d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov info.setClickable(true); 2432d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov info.setLongClickable(true); 2433d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov info.setEnabled(NumberPicker.this.isEnabled()); 2434d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov Rect boundsInParent = mTempRect; 2435d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov boundsInParent.set(left, top, right, bottom); 24360d607fbe546ac943de38dad33ae681b09efec6eaGuang Zhu info.setVisibleToUser(isVisibleToUser(boundsInParent)); 2437d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov info.setBoundsInParent(boundsInParent); 2438d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov Rect boundsInScreen = boundsInParent; 2439d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov int[] locationOnScreen = mTempArray; 2440d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov getLocationOnScreen(locationOnScreen); 2441d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov boundsInScreen.offset(locationOnScreen[0], locationOnScreen[1]); 2442d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov info.setBoundsInScreen(boundsInScreen); 2443791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov 2444791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov if (mAccessibilityFocusedView != virtualViewId) { 2445791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov info.addAction(AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS); 2446791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } 2447791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov if (mAccessibilityFocusedView == virtualViewId) { 2448791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov info.addAction(AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS); 2449791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } 2450fb1e80a247221ee7e8f5c5deba04812021d9d07eSvetoslav Ganov if (NumberPicker.this.isEnabled()) { 2451fb1e80a247221ee7e8f5c5deba04812021d9d07eSvetoslav Ganov info.addAction(AccessibilityNodeInfo.ACTION_CLICK); 2452fb1e80a247221ee7e8f5c5deba04812021d9d07eSvetoslav Ganov } 2453791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov 2454d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return info; 2455d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2456d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 2457d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private AccessibilityNodeInfo createAccessibilityNodeInfoForNumberPicker(int left, int top, 2458d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov int right, int bottom) { 2459d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain(); 24600d607fbe546ac943de38dad33ae681b09efec6eaGuang Zhu info.setClassName(NumberPicker.class.getName()); 2461d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov info.setPackageName(mContext.getPackageName()); 2462d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov info.setSource(NumberPicker.this); 2463791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov 2464791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov if (hasVirtualDecrementButton()) { 2465791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov info.addChild(NumberPicker.this, VIRTUAL_VIEW_ID_DECREMENT); 2466791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } 24670d607fbe546ac943de38dad33ae681b09efec6eaGuang Zhu info.addChild(NumberPicker.this, VIRTUAL_VIEW_ID_INPUT); 2468791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov if (hasVirtualIncrementButton()) { 2469791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov info.addChild(NumberPicker.this, VIRTUAL_VIEW_ID_INCREMENT); 2470791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } 2471791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov 24724528b4e882584745f48263fa6626987e63832a2aSvetoslav Ganov info.setParent((View) getParentForAccessibility()); 2473d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov info.setEnabled(NumberPicker.this.isEnabled()); 2474d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov info.setScrollable(true); 2475983119ab22a18c743e4084dff27f35e3f490dd34Svetoslav Ganov 2476983119ab22a18c743e4084dff27f35e3f490dd34Svetoslav Ganov final float applicationScale = 2477983119ab22a18c743e4084dff27f35e3f490dd34Svetoslav Ganov getContext().getResources().getCompatibilityInfo().applicationScale; 2478983119ab22a18c743e4084dff27f35e3f490dd34Svetoslav Ganov 2479d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov Rect boundsInParent = mTempRect; 2480d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov boundsInParent.set(left, top, right, bottom); 2481983119ab22a18c743e4084dff27f35e3f490dd34Svetoslav Ganov boundsInParent.scale(applicationScale); 2482d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov info.setBoundsInParent(boundsInParent); 2483983119ab22a18c743e4084dff27f35e3f490dd34Svetoslav Ganov 24840d607fbe546ac943de38dad33ae681b09efec6eaGuang Zhu info.setVisibleToUser(isVisibleToUser()); 2485983119ab22a18c743e4084dff27f35e3f490dd34Svetoslav Ganov 2486d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov Rect boundsInScreen = boundsInParent; 2487d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov int[] locationOnScreen = mTempArray; 2488d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov getLocationOnScreen(locationOnScreen); 2489d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov boundsInScreen.offset(locationOnScreen[0], locationOnScreen[1]); 2490983119ab22a18c743e4084dff27f35e3f490dd34Svetoslav Ganov boundsInScreen.scale(applicationScale); 2491d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov info.setBoundsInScreen(boundsInScreen); 2492791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov 2493791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov if (mAccessibilityFocusedView != View.NO_ID) { 2494791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov info.addAction(AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS); 2495791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } 2496791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov if (mAccessibilityFocusedView == View.NO_ID) { 2497791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov info.addAction(AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS); 2498791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } 2499fb1e80a247221ee7e8f5c5deba04812021d9d07eSvetoslav Ganov if (NumberPicker.this.isEnabled()) { 2500fb1e80a247221ee7e8f5c5deba04812021d9d07eSvetoslav Ganov if (getWrapSelectorWheel() || getValue() < getMaxValue()) { 2501fb1e80a247221ee7e8f5c5deba04812021d9d07eSvetoslav Ganov info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD); 2502fb1e80a247221ee7e8f5c5deba04812021d9d07eSvetoslav Ganov } 2503fb1e80a247221ee7e8f5c5deba04812021d9d07eSvetoslav Ganov if (getWrapSelectorWheel() || getValue() > getMinValue()) { 2504fb1e80a247221ee7e8f5c5deba04812021d9d07eSvetoslav Ganov info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD); 2505fb1e80a247221ee7e8f5c5deba04812021d9d07eSvetoslav Ganov } 250648d1586f4065fc9ab97a679da1e4f7c327c943f2Svetoslav Ganov } 2507791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov 2508d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return info; 2509d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2510d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 2511791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov private boolean hasVirtualDecrementButton() { 2512791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov return getWrapSelectorWheel() || getValue() > getMinValue(); 2513791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } 2514791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov 2515791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov private boolean hasVirtualIncrementButton() { 2516791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov return getWrapSelectorWheel() || getValue() < getMaxValue(); 2517791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } 2518791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov 2519d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private String getVirtualDecrementButtonText() { 2520d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov int value = mValue - 1; 2521d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (mWrapSelectorWheel) { 2522d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov value = getWrappedSelectorIndex(value); 2523d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2524d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (value >= mMinValue) { 2525d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return (mDisplayedValues == null) ? formatNumber(value) 2526d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov : mDisplayedValues[value - mMinValue]; 2527d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2528d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return null; 2529d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2530d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 2531d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private String getVirtualIncrementButtonText() { 2532d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov int value = mValue + 1; 2533d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (mWrapSelectorWheel) { 2534d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov value = getWrappedSelectorIndex(value); 2535d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2536d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (value <= mMaxValue) { 2537d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return (mDisplayedValues == null) ? formatNumber(value) 2538d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov : mDisplayedValues[value - mMinValue]; 2539d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2540d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return null; 2541d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2542d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2543d88e3054d08b1f821bb2e27b2647aa16a60d8742Fabrice Di Meglio 2544d88e3054d08b1f821bb2e27b2647aa16a60d8742Fabrice Di Meglio static private String formatNumberWithLocale(int value) { 2545d88e3054d08b1f821bb2e27b2647aa16a60d8742Fabrice Di Meglio return String.format(Locale.getDefault(), "%d", value); 2546d88e3054d08b1f821bb2e27b2647aa16a60d8742Fabrice Di Meglio } 25477762d93621f508f4410fd37b5bbdfec0071b0420Paul Westbrook} 2548