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