NumberPicker.java revision 4528b4e882584745f48263fa6626987e63832a2a
19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/* 29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2008 The Android Open Source Project 39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License"); 59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License. 69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at 79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0 99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software 119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, 129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and 149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License. 159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1768f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrookpackage android.widget; 189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1968f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrookimport android.annotation.Widget; 209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Context; 21206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganovimport android.content.res.ColorStateList; 22206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganovimport android.content.res.TypedArray; 23206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganovimport android.graphics.Canvas; 24206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganovimport android.graphics.Color; 25206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganovimport android.graphics.Paint; 26e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganovimport android.graphics.Paint.Align; 27b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganovimport android.graphics.Rect; 289cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganovimport android.graphics.drawable.Drawable; 29aa780c110922148a6a4ba06734bb2b0bb8c98f93Svetoslav Ganovimport android.os.Bundle; 309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.text.InputFilter; 319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.text.InputType; 329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.text.Spanned; 33206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganovimport android.text.TextUtils; 349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.text.method.NumberKeyListener; 359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.AttributeSet; 36206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganovimport android.util.SparseArray; 379cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganovimport android.util.TypedValue; 38206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganovimport android.view.KeyEvent; 399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.LayoutInflater; 40b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganovimport android.view.LayoutInflater.Filter; 41206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganovimport android.view.MotionEvent; 42206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganovimport android.view.VelocityTracker; 439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.View; 44206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganovimport android.view.ViewConfiguration; 453fec3fe0e3a83c5e0d1264f34bcc55b158537bc6Svetoslav Ganovimport android.view.accessibility.AccessibilityEvent; 463fec3fe0e3a83c5e0d1264f34bcc55b158537bc6Svetoslav Ganovimport android.view.accessibility.AccessibilityManager; 478a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganovimport android.view.accessibility.AccessibilityNodeInfo; 48d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganovimport android.view.accessibility.AccessibilityNodeProvider; 499cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganovimport android.view.animation.DecelerateInterpolator; 50a2b41b438d45570867e4682c0caaf93ace5e712eSvetoslav Ganovimport android.view.inputmethod.EditorInfo; 51206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganovimport android.view.inputmethod.InputMethodManager; 529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 53b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganovimport com.android.internal.R; 54b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov 55d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganovimport java.util.ArrayList; 56d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganovimport java.util.Collections; 57d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganovimport java.util.List; 58d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 5968f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook/** 604bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * A widget that enables the user to select a number form a predefined range. 61d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * There are two flavors of this widget and which one is presented to the user 62d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * depends on the current theme. 63d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * <ul> 64d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * <li> 65d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * If the current theme is derived from {@link android.R.style#Theme} the widget 66d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * presents the current value as an editable input field with an increment button 67d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * above and a decrement button below. Long pressing the buttons allows for a quick 68d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * change of the current value. Tapping on the input field allows to type in 69d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * a desired value. 70d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * </li> 71d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * <li> 72d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * If the current theme is derived from {@link android.R.style#Theme_Holo} or 73d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * {@link android.R.style#Theme_Holo_Light} the widget presents the current 74d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * value as an editable input field with a lesser value above and a greater 75d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * value below. Tapping on the lesser or greater value selects it by animating 76d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * the number axis up or down to make the chosen value current. Flinging up 77d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * or down allows for multiple increments or decrements of the current value. 78d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * Long pressing on the lesser and greater values also allows for a quick change 79d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * of the current value. Tapping on the current value allows to type in a 80d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * desired value. 81d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * </li> 82d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * </ul> 834bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * <p> 844bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * For an example of using this widget, see {@link android.widget.TimePicker}. 854bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * </p> 8668f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook */ 8768f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook@Widget 8868f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrookpublic class NumberPicker extends LinearLayout { 89fdf6db6748b32f620a7f68b13a67c38b4e59e5edTom Taylor 9068f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook /** 913f9c9eab7b41c409c3c7b503b89ad340e408b6a0Svetoslav Ganov * The number of items show in the selector wheel. 923f9c9eab7b41c409c3c7b503b89ad340e408b6a0Svetoslav Ganov */ 93d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private static final int SELECTOR_WHEEL_ITEM_COUNT = 3; 943f9c9eab7b41c409c3c7b503b89ad340e408b6a0Svetoslav Ganov 953f9c9eab7b41c409c3c7b503b89ad340e408b6a0Svetoslav Ganov /** 96e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * The default update interval during long press. 97e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov */ 98e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov private static final long DEFAULT_LONG_PRESS_UPDATE_INTERVAL = 300; 99e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov 100e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov /** 101206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * The index of the middle selector item. 10268f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook */ 103d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private static final int SELECTOR_MIDDLE_ITEM_INDEX = SELECTOR_WHEEL_ITEM_COUNT / 2; 1049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10568f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook /** 106206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * The coefficient by which to adjust (divide) the max fling velocity. 10768f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook */ 108206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private static final int SELECTOR_MAX_FLING_VELOCITY_ADJUSTMENT = 8; 1099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 110206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 111206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * The the duration for adjusting the selector wheel. 112206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 113206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private static final int SELECTOR_ADJUSTMENT_DURATION_MILLIS = 800; 114fdf6db6748b32f620a7f68b13a67c38b4e59e5edTom Taylor 115206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 1164213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov * The duration of scrolling while snapping to 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 resource id for the default layout. 137b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov */ 138d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private static final int DEFAULT_LAYOUT_RESOURCE_ID = R.layout.number_picker; 1399cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov 1409cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov /** 141206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * The numbers accepted by the input text's {@link Filter} 142206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 143206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private static final char[] DIGIT_CHARACTERS = new char[] { 144206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' 145fe41ce4ef97e7da585fdbf06988da8047e72b9f6Svetoslav Ganov }; 146206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 147206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 1489f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov * Constant for unspecified size. 1499f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov */ 1509f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov private static final int SIZE_UNSPECIFIED = -1; 1519f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov 1529f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov /** 153206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Use a custom NumberPicker formatting callback to use two-digit minutes 154206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * strings like "01". Keeping a static formatter etc. is the most efficient 155206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * way to do this; it avoids creating temporary objects on every call to 156206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * format(). 157e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * 158e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @hide 159206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 160206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov public static final NumberPicker.Formatter TWO_DIGIT_FORMATTER = new NumberPicker.Formatter() { 161206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov final StringBuilder mBuilder = new StringBuilder(); 162206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 163f0ef665299d795df7905897e1c337e37891dafefJean-Baptiste Queru final java.util.Formatter mFmt = new java.util.Formatter(mBuilder, java.util.Locale.US); 164206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 165206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov final Object[] mArgs = new Object[1]; 166206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 167e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov public String format(int value) { 168206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mArgs[0] = value; 169206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mBuilder.delete(0, mBuilder.length()); 170206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mFmt.format("%02d", mArgs); 171206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return mFmt.toString(); 1729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project }; 1749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 175206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 176206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * The increment button. 177206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 178206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private final ImageButton mIncrementButton; 179206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 180206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 181206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * The decrement button. 182206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 183206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private final ImageButton mDecrementButton; 184206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 185206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 186206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * The text for showing the current value. 187206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 188206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private final EditText mInputText; 189206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 190206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 191d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * The distance between the two selection dividers. 192d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov */ 193d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private final int mSelectionDividersDistance; 194d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 195d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov /** 196ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov * The min height of this widget. 197ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov */ 198ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov private final int mMinHeight; 199ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov 200ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov /** 201e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov * The max height of this widget. 202e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov */ 203e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov private final int mMaxHeight; 204e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov 205e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov /** 206e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov * The max width of this widget. 207e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov */ 208ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov private final int mMinWidth; 209ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov 210ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov /** 211ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov * The max width of this widget. 212ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov */ 213ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov private int mMaxWidth; 214ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov 215ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov /** 216ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov * Flag whether to compute the max width. 217ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov */ 218ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov private final boolean mComputeMaxWidth; 219e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov 220e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov /** 221206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * The height of the text. 222206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 223206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private final int mTextSize; 2249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 225206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 226b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov * The height of the gap between text elements if the selector wheel. 227b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov */ 228b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov private int mSelectorTextGapHeight; 229b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov 230b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov /** 231206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * The values to be displayed instead the indices. 232206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 2339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private String[] mDisplayedValues; 23468f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook 23568f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook /** 23668f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook * Lower value of the range of numbers allowed for the NumberPicker 23768f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook */ 238e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov private int mMinValue; 23968f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook 24068f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook /** 24168f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook * Upper value of the range of numbers allowed for the NumberPicker 24268f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook */ 243e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov private int mMaxValue; 24468f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook 24568f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook /** 24668f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook * Current value of this NumberPicker 24768f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook */ 248e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov private int mValue; 24968f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook 25068f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook /** 251206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Listener to be notified upon current value change. 25268f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook */ 253cedc446684e94c9971c38c3206f1f224314bda2aSvetoslav Ganov private OnValueChangeListener mOnValueChangeListener; 25450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 25550f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov /** 25650f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * Listener to be notified upon scroll state change. 25750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov */ 25850f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov private OnScrollListener mOnScrollListener; 259206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 260206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 261206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Formatter for for displaying the current value. 262206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 2639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private Formatter mFormatter; 264fdf6db6748b32f620a7f68b13a67c38b4e59e5edTom Taylor 265206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 266206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * The speed for updating the value form long press. 267206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 268e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov private long mLongPressUpdateInterval = DEFAULT_LONG_PRESS_UPDATE_INTERVAL; 269fdf6db6748b32f620a7f68b13a67c38b4e59e5edTom Taylor 27068f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook /** 271206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Cache for the string representation of selector indices. 272206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 273206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private final SparseArray<String> mSelectorIndexToStringCache = new SparseArray<String>(); 274206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 275206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 276206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * The selector indices whose value are show by the selector. 277206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 278d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private final int[] mSelectorIndices = new int[SELECTOR_WHEEL_ITEM_COUNT]; 279206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 280206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 281206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * The {@link Paint} for drawing the selector. 282206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 283b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov private final Paint mSelectorWheelPaint; 284206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 285206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 286232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov * The {@link Drawable} for pressed virtual (increment/decrement) buttons. 287232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov */ 288232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov private final Drawable mVirtualButtonPressedDrawable; 289232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov 290232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov /** 291206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * The height of a selector element (text + gap). 292206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 293206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private int mSelectorElementHeight; 294206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 295206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 296206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * The initial offset of the scroll selector. 297206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 298206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private int mInitialScrollOffset = Integer.MIN_VALUE; 299206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 300206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 301206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * The current offset of the scroll selector. 302206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 303206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private int mCurrentScrollOffset; 304206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 305206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 306206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * The {@link Scroller} responsible for flinging the selector. 307206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 308206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private final Scroller mFlingScroller; 309206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 310206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 311206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * The {@link Scroller} responsible for adjusting the selector. 312206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 313206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private final Scroller mAdjustScroller; 314206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 315206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 316206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * The previous Y coordinate while scrolling the selector. 317206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 318206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private int mPreviousScrollerY; 319206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 320206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 321206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Handle to the reusable command for setting the input text selection. 322206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 323206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private SetSelectionCommand mSetSelectionCommand; 324206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 325206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 326b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov * Handle to the reusable command for changing the current value from long 327b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov * press by one. 328206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 329b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov private ChangeCurrentByOneFromLongPressCommand mChangeCurrentByOneFromLongPressCommand; 330206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 331206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 332d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * Command for beginning an edit of the current value via IME on long press. 333b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov */ 334d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private BeginSoftInputOnLongPressCommand mBeginSoftInputOnLongPressCommand; 335b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov 336b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov /** 337206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * The Y position of the last down event. 338206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 339206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private float mLastDownEventY; 340206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 341206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 342d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * The time of the last down event. 343206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 344d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private long mLastDownEventTime; 345206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 346206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 347d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * The Y position of the last down or move event. 348206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 349d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private float mLastDownOrMoveEventY; 350206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 351206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 352206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Determines speed during touch scrolling. 353206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 354206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private VelocityTracker mVelocityTracker; 355206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 356206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 357206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * @see ViewConfiguration#getScaledTouchSlop() 358206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 359206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private int mTouchSlop; 360206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 361206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 362206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * @see ViewConfiguration#getScaledMinimumFlingVelocity() 363206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 364206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private int mMinimumFlingVelocity; 365206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 366206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 367206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * @see ViewConfiguration#getScaledMaximumFlingVelocity() 368206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 369206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private int mMaximumFlingVelocity; 370206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 371206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 372206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Flag whether the selector should wrap around. 373206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 374e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov private boolean mWrapSelectorWheel; 375206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 376206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 377206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * The back ground color used to optimize scroller fading. 37868f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook */ 379206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private final int mSolidColor; 380206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 381206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 382d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * Flag whether this widget has a selector wheel. 3834243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov */ 384d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private final boolean mHasSelectorWheel; 3854243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov 3864243dc394d89a93cb207efa36e9755c2424d688bSvetoslav Ganov /** 3879cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov * Divider for showing item to be selected while scrolling 3889cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov */ 3899cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov private final Drawable mSelectionDivider; 3909cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov 3919cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov /** 3929cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov * The height of the selection divider. 3939cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov */ 3949cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov private final int mSelectionDividerHeight; 3959cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov 3969cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov /** 397d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * The current scroll state of the number picker. 398206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 399d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private int mScrollState = OnScrollListener.SCROLL_STATE_IDLE; 400206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 401206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 402d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * Flag whether to ignore move events - we ignore such when we show in IME 403d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * to prevent the content from scrolling. 40450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov */ 405d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private boolean mIngonreMoveEvents; 40650f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 40750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov /** 408d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * Flag whether to show soft input on tap. 4099cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov */ 410d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private boolean mShowSoftInputOnTap; 4119cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov 4129cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov /** 413d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * The top of the top selection divider. 414b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov */ 415d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private int mTopSelectionDividerTop; 416b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov 417b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov /** 418d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * The bottom of the bottom selection divider. 419a2b41b438d45570867e4682c0caaf93ace5e712eSvetoslav Ganov */ 420d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private int mBottomSelectionDividerBottom; 421d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 422d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov /** 423d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * The virtual id of the last hovered child. 424d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov */ 425d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private int mLastHoveredChildVirtualViewId; 426d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 427d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov /** 428232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov * Whether the increment virtual button is pressed. 429232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov */ 430232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov private boolean mIncrementVirtualButtonPressed; 431232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov 432232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov /** 433232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov * Whether the decrement virtual button is pressed. 434232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov */ 435232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov private boolean mDecrementVirtualButtonPressed; 436232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov 437232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav 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 /** 443232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov * Helper class for managing pressed state of the virtual buttons. 444232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov */ 445232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov private final PressedStateHelper mPressedStateHelper; 446232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov 447232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov /** 448e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * Interface to listen for changes of the current value. 449206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 450cedc446684e94c9971c38c3206f1f224314bda2aSvetoslav Ganov public interface OnValueChangeListener { 451e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov 452206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 4534bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * Called upon a change of the current value. 4544bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * 455206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * @param picker The NumberPicker associated with this listener. 456206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * @param oldVal The previous value. 457206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * @param newVal The new value. 458206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 459e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov void onValueChange(NumberPicker picker, int oldVal, int newVal); 460206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 461206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 462206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 463e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * Interface to listen for the picker scroll state. 46450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov */ 46550f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov public interface OnScrollListener { 46650f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 46750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov /** 46850f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * The view is not scrolling. 46950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov */ 47050f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov public static int SCROLL_STATE_IDLE = 0; 47150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 47250f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov /** 473d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * The user is scrolling using touch, and his finger is still on the screen. 47450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov */ 47550f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov public static int SCROLL_STATE_TOUCH_SCROLL = 1; 47650f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 47750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov /** 47850f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * The user had previously been scrolling using touch and performed a fling. 47950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov */ 48050f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov public static int SCROLL_STATE_FLING = 2; 48150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 48250f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov /** 483e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * Callback invoked while the number picker scroll state has changed. 48450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * 485e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @param view The view whose scroll state is being reported. 486e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @param scrollState The current scroll state. One of 487e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * {@link #SCROLL_STATE_IDLE}, 488e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * {@link #SCROLL_STATE_TOUCH_SCROLL} or 489e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * {@link #SCROLL_STATE_IDLE}. 49050f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov */ 4914bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov public void onScrollStateChange(NumberPicker view, int scrollState); 49250f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov } 49350f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 49450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov /** 495e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * Interface used to format current value into a string for presentation. 496206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 497206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov public interface Formatter { 4984bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov 4994bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov /** 500e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * Formats a string representation of the current value. 5014bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * 5024bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * @param value The currently selected value. 5034bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * @return A formatted string representation. 5044bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov */ 505e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov public String format(int value); 5069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 507fdf6db6748b32f620a7f68b13a67c38b4e59e5edTom Taylor 50868f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook /** 5094bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * Create a new number picker. 5104bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * 5114bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * @param context The application environment. 5124bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov */ 5134bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov public NumberPicker(Context context) { 5144bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov this(context, null); 5154bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov } 5164bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov 5174bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov /** 5184bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * Create a new number picker. 519206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * 520206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * @param context The application environment. 521206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * @param attrs A collection of attributes. 52268f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook */ 5239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public NumberPicker(Context context, AttributeSet attrs) { 524206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov this(context, attrs, R.attr.numberPickerStyle); 525206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 526206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 527206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 528206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Create a new number picker 529206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * 530206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * @param context the application environment. 531206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * @param attrs a collection of attributes. 532206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * @param defStyle The default style to apply to this view. 533206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 534206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov public NumberPicker(Context context, AttributeSet attrs, int defStyle) { 535206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov super(context, attrs, defStyle); 536206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 537206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // process style attributes 538d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov TypedArray attributesArray = context.obtainStyledAttributes( 539d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov attrs, R.styleable.NumberPicker, defStyle, 0); 540d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov final int layoutResId = attributesArray.getResourceId( 541d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov R.styleable.NumberPicker_internalLayout, DEFAULT_LAYOUT_RESOURCE_ID); 542d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 543d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mHasSelectorWheel = (layoutResId != DEFAULT_LAYOUT_RESOURCE_ID); 544d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 545206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mSolidColor = attributesArray.getColor(R.styleable.NumberPicker_solidColor, 0); 546d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 5479cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov mSelectionDivider = attributesArray.getDrawable(R.styleable.NumberPicker_selectionDivider); 548d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 549d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov final int defSelectionDividerHeight = (int) TypedValue.applyDimension( 550d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov TypedValue.COMPLEX_UNIT_DIP, UNSCALED_DEFAULT_SELECTION_DIVIDER_HEIGHT, 5519cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov getResources().getDisplayMetrics()); 5529cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov mSelectionDividerHeight = attributesArray.getDimensionPixelSize( 5539cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov R.styleable.NumberPicker_selectionDividerHeight, defSelectionDividerHeight); 554d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 555d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov final int defSelectionDividerDistance = (int) TypedValue.applyDimension( 556d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov TypedValue.COMPLEX_UNIT_DIP, UNSCALED_DEFAULT_SELECTION_DIVIDERS_DISTANCE, 557d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov getResources().getDisplayMetrics()); 558d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mSelectionDividersDistance = attributesArray.getDimensionPixelSize( 559d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov R.styleable.NumberPicker_selectionDividersDistance, defSelectionDividerDistance); 560d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 561e8331bd2e7ad3d62140143cafba3ff69be028557Svetoslav Ganov mMinHeight = attributesArray.getDimensionPixelSize( 562e8331bd2e7ad3d62140143cafba3ff69be028557Svetoslav Ganov R.styleable.NumberPicker_internalMinHeight, SIZE_UNSPECIFIED); 563d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 564e8331bd2e7ad3d62140143cafba3ff69be028557Svetoslav Ganov mMaxHeight = attributesArray.getDimensionPixelSize( 565e8331bd2e7ad3d62140143cafba3ff69be028557Svetoslav Ganov R.styleable.NumberPicker_internalMaxHeight, SIZE_UNSPECIFIED); 5669f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov if (mMinHeight != SIZE_UNSPECIFIED && mMaxHeight != SIZE_UNSPECIFIED 5679f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov && mMinHeight > mMaxHeight) { 568ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov throw new IllegalArgumentException("minHeight > maxHeight"); 569ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov } 570d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 571d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mMinWidth = attributesArray.getDimensionPixelSize( 572d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov R.styleable.NumberPicker_internalMinWidth, SIZE_UNSPECIFIED); 573d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 574d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mMaxWidth = attributesArray.getDimensionPixelSize( 575d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov R.styleable.NumberPicker_internalMaxWidth, SIZE_UNSPECIFIED); 5769f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov if (mMinWidth != SIZE_UNSPECIFIED && mMaxWidth != SIZE_UNSPECIFIED 5779f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov && mMinWidth > mMaxWidth) { 578ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov throw new IllegalArgumentException("minWidth > maxWidth"); 579ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov } 580d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 581f7c83bc4d3e1996b491824902a6a0f98ac69bedeSvetoslav Ganov mComputeMaxWidth = (mMaxWidth == SIZE_UNSPECIFIED); 582206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 583232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov mVirtualButtonPressedDrawable = attributesArray.getDrawable( 584232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov R.styleable.NumberPicker_virtualButtonPressedDrawable); 585232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov 586d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov attributesArray.recycle(); 5879cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov 588232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov mPressedStateHelper = new PressedStateHelper(); 589232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov 590206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // By default Linearlayout that we extend is not drawn. This is 591206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // its draw() method is not called but dispatchDraw() is called 592206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // directly (see ViewGroup.drawChild()). However, this class uses 593206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // the fading edge effect implemented by View and we need our 594206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // draw() method to be called. Therefore, we declare we will draw. 595d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov setWillNotDraw(!mHasSelectorWheel); 596206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 597206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov LayoutInflater inflater = (LayoutInflater) getContext().getSystemService( 598206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov Context.LAYOUT_INFLATER_SERVICE); 599d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov inflater.inflate(layoutResId, this, true); 60068f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook 601206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov OnClickListener onClickListener = new OnClickListener() { 60268f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook public void onClick(View v) { 603b52d9729bfb2ef7ad50d9a5125ebf3a8322429a9Svetoslav Ganov hideSoftInput(); 604206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mInputText.clearFocus(); 605206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (v.getId() == R.id.increment) { 606d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov changeValueByOne(true); 607206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } else { 608d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov changeValueByOne(false); 60968f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook } 61068f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook } 61168f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook }; 61268f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook 613206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov OnLongClickListener onLongClickListener = new OnLongClickListener() { 614206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov public boolean onLongClick(View v) { 615b52d9729bfb2ef7ad50d9a5125ebf3a8322429a9Svetoslav Ganov hideSoftInput(); 616206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mInputText.clearFocus(); 617206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (v.getId() == R.id.increment) { 618d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov postChangeCurrentByOneFromLongPress(true, 0); 619206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } else { 620d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov postChangeCurrentByOneFromLongPress(false, 0); 621206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 622206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return true; 623206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 624206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov }; 62568f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook 626206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // increment button 627d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (!mHasSelectorWheel) { 628d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mIncrementButton = (ImageButton) findViewById(R.id.increment); 629d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mIncrementButton.setOnClickListener(onClickListener); 630d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mIncrementButton.setOnLongClickListener(onLongClickListener); 631d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } else { 632d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mIncrementButton = null; 633d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 634206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 635206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // decrement button 636d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (!mHasSelectorWheel) { 637d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mDecrementButton = (ImageButton) findViewById(R.id.decrement); 638d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mDecrementButton.setOnClickListener(onClickListener); 639d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mDecrementButton.setOnLongClickListener(onLongClickListener); 640d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } else { 641d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mDecrementButton = null; 642d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 643206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 644206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // input text 645012dd5a461f18a2e5dad38c60282fac1c21ff7feSvetoslav Ganov mInputText = (EditText) findViewById(R.id.numberpicker_input); 646206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mInputText.setOnFocusChangeListener(new OnFocusChangeListener() { 647206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov public void onFocusChange(View v, boolean hasFocus) { 648a53efe9923bedab4fe5d578f32eaff308e5b9e76Svetoslav Ganov if (hasFocus) { 649a53efe9923bedab4fe5d578f32eaff308e5b9e76Svetoslav Ganov mInputText.selectAll(); 650a53efe9923bedab4fe5d578f32eaff308e5b9e76Svetoslav Ganov } else { 651a53efe9923bedab4fe5d578f32eaff308e5b9e76Svetoslav Ganov mInputText.setSelection(0, 0); 652206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov validateInputTextView(v); 65368f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook } 65468f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook } 655206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov }); 656206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mInputText.setFilters(new InputFilter[] { 657206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov new InputTextFilter() 658206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov }); 65968f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook 660206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mInputText.setRawInputType(InputType.TYPE_CLASS_NUMBER); 661a2b41b438d45570867e4682c0caaf93ace5e712eSvetoslav Ganov mInputText.setImeOptions(EditorInfo.IME_ACTION_DONE); 662206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 663206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // initialize constants 664206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov ViewConfiguration configuration = ViewConfiguration.get(context); 665206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mTouchSlop = configuration.getScaledTouchSlop(); 666206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mMinimumFlingVelocity = configuration.getScaledMinimumFlingVelocity(); 667206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mMaximumFlingVelocity = configuration.getScaledMaximumFlingVelocity() 668206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov / SELECTOR_MAX_FLING_VELOCITY_ADJUSTMENT; 669206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mTextSize = (int) mInputText.getTextSize(); 670206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 671206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // create the selector wheel paint 672206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov Paint paint = new Paint(); 673206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov paint.setAntiAlias(true); 674206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov paint.setTextAlign(Align.CENTER); 675206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov paint.setTextSize(mTextSize); 676206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov paint.setTypeface(mInputText.getTypeface()); 677206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov ColorStateList colors = mInputText.getTextColors(); 678206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov int color = colors.getColorForState(ENABLED_STATE_SET, Color.WHITE); 679206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov paint.setColor(color); 680b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov mSelectorWheelPaint = paint; 681206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 682206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // create the fling and adjust scrollers 683bf80562d22b2bbe7944d80d0524c69d0238010cbSvetoslav Ganov mFlingScroller = new Scroller(getContext(), null, true); 6849cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov mAdjustScroller = new Scroller(getContext(), new DecelerateInterpolator(2.5f)); 685fdf6db6748b32f620a7f68b13a67c38b4e59e5edTom Taylor 686206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov updateInputTextView(); 6874213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov 6884213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov // If not explicitly specified this view is important for accessibility. 6894213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov if (getImportantForAccessibility() == IMPORTANT_FOR_ACCESSIBILITY_AUTO) { 6904213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES); 6914213804541a8b05cd0587b138a2fd9a3b7fd9350Svetoslav Ganov } 692206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 693206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 694206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov @Override 6959cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov protected void onLayout(boolean changed, int left, int top, int right, int bottom) { 696d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (!mHasSelectorWheel) { 697d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov super.onLayout(changed, left, top, right, bottom); 698d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return; 699d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 700ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov final int msrdWdth = getMeasuredWidth(); 701ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov final int msrdHght = getMeasuredHeight(); 702ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov 703ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov // Input text centered horizontally. 704ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov final int inptTxtMsrdWdth = mInputText.getMeasuredWidth(); 705ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov final int inptTxtMsrdHght = mInputText.getMeasuredHeight(); 706ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov final int inptTxtLeft = (msrdWdth - inptTxtMsrdWdth) / 2; 707ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov final int inptTxtTop = (msrdHght - inptTxtMsrdHght) / 2; 708ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov final int inptTxtRight = inptTxtLeft + inptTxtMsrdWdth; 709ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov final int inptTxtBottom = inptTxtTop + inptTxtMsrdHght; 710ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov mInputText.layout(inptTxtLeft, inptTxtTop, inptTxtRight, inptTxtBottom); 711ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov 712d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (changed) { 713b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov // need to do all this when we know our size 714b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov initializeSelectorWheel(); 715b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov initializeFadingEdges(); 716d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mTopSelectionDividerTop = (getHeight() - mSelectionDividersDistance) / 2 717d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov - mSelectionDividerHeight; 718d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mBottomSelectionDividerBottom = mTopSelectionDividerTop + 2 * mSelectionDividerHeight 719d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov + mSelectionDividersDistance; 720b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov } 721206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 722206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 723206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov @Override 724e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 725d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (!mHasSelectorWheel) { 726d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov super.onMeasure(widthMeasureSpec, heightMeasureSpec); 727d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return; 728d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 729698e1d5d867a7ac653fa1d6f29cef4cfb73fad38Svetoslav Ganov // Try greedily to fit the max width and height. 730698e1d5d867a7ac653fa1d6f29cef4cfb73fad38Svetoslav Ganov final int newWidthMeasureSpec = makeMeasureSpec(widthMeasureSpec, mMaxWidth); 731698e1d5d867a7ac653fa1d6f29cef4cfb73fad38Svetoslav Ganov final int newHeightMeasureSpec = makeMeasureSpec(heightMeasureSpec, mMaxHeight); 732ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov super.onMeasure(newWidthMeasureSpec, newHeightMeasureSpec); 733698e1d5d867a7ac653fa1d6f29cef4cfb73fad38Svetoslav Ganov // Flag if we are measured with width or height less than the respective min. 7349f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov final int widthSize = resolveSizeAndStateRespectingMinSize(mMinWidth, getMeasuredWidth(), 7359f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov widthMeasureSpec); 7369f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov final int heightSize = resolveSizeAndStateRespectingMinSize(mMinHeight, getMeasuredHeight(), 7379f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov heightMeasureSpec); 738698e1d5d867a7ac653fa1d6f29cef4cfb73fad38Svetoslav Ganov setMeasuredDimension(widthSize, heightSize); 739e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov } 740e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov 741d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov /** 742d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * Move to the final position of a scroller. Ensures to force finish the scroller 743d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * and if it is not at its final position a scroll of the selector wheel is 744d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * performed to fast forward to the final position. 745d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * 746d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * @param scroller The scroller to whose final position to get. 747d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * @return True of the a move was performed, i.e. the scroller was not in final position. 748d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov */ 749d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private boolean moveToFinalScrollerPosition(Scroller scroller) { 750d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov scroller.forceFinished(true); 751d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov int amountToScroll = scroller.getFinalY() - scroller.getCurrY(); 752d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov int futureScrollOffset = (mCurrentScrollOffset + amountToScroll) % mSelectorElementHeight; 753d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov int overshootAdjustment = mInitialScrollOffset - futureScrollOffset; 754d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (overshootAdjustment != 0) { 755d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (Math.abs(overshootAdjustment) > mSelectorElementHeight / 2) { 756d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (overshootAdjustment > 0) { 757d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov overshootAdjustment -= mSelectorElementHeight; 758d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } else { 759d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov overshootAdjustment += mSelectorElementHeight; 760d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 761d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 762d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov amountToScroll += overshootAdjustment; 763d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov scrollBy(0, amountToScroll); 764d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return true; 765d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 766d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return false; 767d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 768d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 769e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov @Override 770206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov public boolean onInterceptTouchEvent(MotionEvent event) { 771d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (!mHasSelectorWheel || !isEnabled()) { 77251c52edad7d40697d7fb2a091f850506fa897643Svetoslav Ganov return false; 77351c52edad7d40697d7fb2a091f850506fa897643Svetoslav Ganov } 774d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov final int action = event.getActionMasked(); 775d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov switch (action) { 776d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov case MotionEvent.ACTION_DOWN: { 777206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov removeAllCallbacks(); 778d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mInputText.setVisibility(View.INVISIBLE); 779d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mLastDownOrMoveEventY = mLastDownEventY = event.getY(); 780d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mLastDownEventTime = event.getEventTime(); 781d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mIngonreMoveEvents = false; 782d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mShowSoftInputOnTap = false; 783232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov // Handle pressed state before any state change. 784232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov if (mLastDownEventY < mTopSelectionDividerTop) { 785232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov if (mScrollState == OnScrollListener.SCROLL_STATE_IDLE) { 786232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov mPressedStateHelper.buttonPressDelayed( 787232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov PressedStateHelper.BUTTON_DECREMENT); 788232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov } 789232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov } else if (mLastDownEventY > mBottomSelectionDividerBottom) { 790232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov if (mScrollState == OnScrollListener.SCROLL_STATE_IDLE) { 791232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov mPressedStateHelper.buttonPressDelayed( 792232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov PressedStateHelper.BUTTON_INCREMENT); 793232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov } 794232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov } 795232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov // Make sure we support flinging inside scrollables. 79683dc45c65988e9b86e156d59f59ede48195ed1d5Svetoslav Ganov getParent().requestDisallowInterceptTouchEvent(true); 797d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (!mFlingScroller.isFinished()) { 798d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mFlingScroller.forceFinished(true); 799d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mAdjustScroller.forceFinished(true); 800d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov onScrollStateChange(OnScrollListener.SCROLL_STATE_IDLE); 801d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } else if (!mAdjustScroller.isFinished()) { 802d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mFlingScroller.forceFinished(true); 803d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mAdjustScroller.forceFinished(true); 804d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } else if (mLastDownEventY < mTopSelectionDividerTop) { 805b52d9729bfb2ef7ad50d9a5125ebf3a8322429a9Svetoslav Ganov hideSoftInput(); 806d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov postChangeCurrentByOneFromLongPress( 807d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov false, ViewConfiguration.getLongPressTimeout()); 808d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } else if (mLastDownEventY > mBottomSelectionDividerBottom) { 809b52d9729bfb2ef7ad50d9a5125ebf3a8322429a9Svetoslav Ganov hideSoftInput(); 810d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov postChangeCurrentByOneFromLongPress( 811d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov true, ViewConfiguration.getLongPressTimeout()); 812d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } else { 813d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mShowSoftInputOnTap = true; 814d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov postBeginSoftInputOnLongPressCommand(); 815206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 816d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return true; 817d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 818206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 819206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return false; 820206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 821206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 822206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov @Override 823d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov public boolean onTouchEvent(MotionEvent event) { 824d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (!isEnabled() || !mHasSelectorWheel) { 82551c52edad7d40697d7fb2a091f850506fa897643Svetoslav Ganov return false; 82651c52edad7d40697d7fb2a091f850506fa897643Svetoslav Ganov } 827206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (mVelocityTracker == null) { 828206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mVelocityTracker = VelocityTracker.obtain(); 829206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 830d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mVelocityTracker.addMovement(event); 831d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov int action = event.getActionMasked(); 832206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov switch (action) { 833d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov case MotionEvent.ACTION_MOVE: { 834d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (mIngonreMoveEvents) { 835d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov break; 836d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 837d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov float currentMoveY = event.getY(); 838d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (mScrollState != OnScrollListener.SCROLL_STATE_TOUCH_SCROLL) { 839206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov int deltaDownY = (int) Math.abs(currentMoveY - mLastDownEventY); 840206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (deltaDownY > mTouchSlop) { 841d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov removeAllCallbacks(); 8429cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov onScrollStateChange(OnScrollListener.SCROLL_STATE_TOUCH_SCROLL); 843206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 844d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } else { 845232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov int deltaMoveY = (int) ((currentMoveY - mLastDownOrMoveEventY)); 846d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov scrollBy(0, deltaMoveY); 847d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov invalidate(); 848206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 849d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mLastDownOrMoveEventY = currentMoveY; 850d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } break; 851d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov case MotionEvent.ACTION_UP: { 852d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov removeBeginSoftInputCommand(); 853d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov removeChangeCurrentByOneFromLongPress(); 854232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov mPressedStateHelper.cancel(); 855206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov VelocityTracker velocityTracker = mVelocityTracker; 856206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov velocityTracker.computeCurrentVelocity(1000, mMaximumFlingVelocity); 857206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov int initialVelocity = (int) velocityTracker.getYVelocity(); 858206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (Math.abs(initialVelocity) > mMinimumFlingVelocity) { 859232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov fling(initialVelocity); 8609cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov onScrollStateChange(OnScrollListener.SCROLL_STATE_FLING); 861206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } else { 862d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov int eventY = (int) event.getY(); 863d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov int deltaMoveY = (int) Math.abs(eventY - mLastDownEventY); 864d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov long deltaTime = event.getEventTime() - mLastDownEventTime; 865d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (deltaMoveY <= mTouchSlop && deltaTime < ViewConfiguration.getTapTimeout()) { 866d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (mShowSoftInputOnTap) { 867d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mShowSoftInputOnTap = false; 868d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov showSoftInput(); 869d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } else { 870d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov int selectorIndexOffset = (eventY / mSelectorElementHeight) 871d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov - SELECTOR_MIDDLE_ITEM_INDEX; 872d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (selectorIndexOffset > 0) { 873d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov changeValueByOne(true); 874232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov mPressedStateHelper.buttonTapped( 875232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov PressedStateHelper.BUTTON_INCREMENT); 876d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } else if (selectorIndexOffset < 0) { 877d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov changeValueByOne(false); 878232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov mPressedStateHelper.buttonTapped( 879232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov PressedStateHelper.BUTTON_DECREMENT); 880d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 881206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 882206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } else { 883d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov ensureScrollWheelAdjusted(); 884206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 885d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov onScrollStateChange(OnScrollListener.SCROLL_STATE_IDLE); 886206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 887206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mVelocityTracker.recycle(); 888206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mVelocityTracker = null; 889d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } break; 890206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 891206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return true; 892206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 893206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 894206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov @Override 895206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov public boolean dispatchTouchEvent(MotionEvent event) { 896b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov final int action = event.getActionMasked(); 897b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov switch (action) { 898b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov case MotionEvent.ACTION_CANCEL: 899b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov case MotionEvent.ACTION_UP: 900b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov removeAllCallbacks(); 901b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov break; 902206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 903206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return super.dispatchTouchEvent(event); 904206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 905206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 906206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov @Override 907206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov public boolean dispatchKeyEvent(KeyEvent event) { 908d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov final int keyCode = event.getKeyCode(); 909d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov switch (keyCode) { 910d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov case KeyEvent.KEYCODE_DPAD_CENTER: 911d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov case KeyEvent.KEYCODE_ENTER: 912d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov removeAllCallbacks(); 913d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov break; 914206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 915206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return super.dispatchKeyEvent(event); 916206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 917206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 918206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov @Override 919206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov public boolean dispatchTrackballEvent(MotionEvent event) { 920d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov final int action = event.getActionMasked(); 921d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov switch (action) { 922d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov case MotionEvent.ACTION_CANCEL: 923d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov case MotionEvent.ACTION_UP: 924d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov removeAllCallbacks(); 925d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov break; 926206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 927206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return super.dispatchTrackballEvent(event); 928206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 9299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 930206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov @Override 931d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov protected boolean dispatchHoverEvent(MotionEvent event) { 932d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (!mHasSelectorWheel) { 933d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return super.dispatchHoverEvent(event); 934d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 935d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (AccessibilityManager.getInstance(mContext).isEnabled()) { 936d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov final int eventY = (int) event.getY(); 937d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov final int hoveredVirtualViewId; 938d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (eventY < mTopSelectionDividerTop) { 939d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov hoveredVirtualViewId = AccessibilityNodeProviderImpl.VIRTUAL_VIEW_ID_DECREMENT; 940d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } else if (eventY > mBottomSelectionDividerBottom) { 941d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov hoveredVirtualViewId = AccessibilityNodeProviderImpl.VIRTUAL_VIEW_ID_INCREMENT; 942d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } else { 943d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov hoveredVirtualViewId = AccessibilityNodeProviderImpl.VIRTUAL_VIEW_ID_INPUT; 944d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 945d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov final int action = event.getActionMasked(); 946d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov AccessibilityNodeProviderImpl provider = 947d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov (AccessibilityNodeProviderImpl) getAccessibilityNodeProvider(); 948d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov switch (action) { 949d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov case MotionEvent.ACTION_HOVER_ENTER: { 950d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov provider.sendAccessibilityEventForVirtualView(hoveredVirtualViewId, 951d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov AccessibilityEvent.TYPE_VIEW_HOVER_ENTER); 952d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mLastHoveredChildVirtualViewId = hoveredVirtualViewId; 953791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov provider.performAction(hoveredVirtualViewId, 954791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS, null); 955d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } break; 956d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov case MotionEvent.ACTION_HOVER_MOVE: { 957d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (mLastHoveredChildVirtualViewId != hoveredVirtualViewId 958d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov && mLastHoveredChildVirtualViewId != View.NO_ID) { 959d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov provider.sendAccessibilityEventForVirtualView( 960d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mLastHoveredChildVirtualViewId, 961d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov AccessibilityEvent.TYPE_VIEW_HOVER_EXIT); 962d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov provider.sendAccessibilityEventForVirtualView(hoveredVirtualViewId, 963d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov AccessibilityEvent.TYPE_VIEW_HOVER_ENTER); 964d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mLastHoveredChildVirtualViewId = hoveredVirtualViewId; 965791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov provider.performAction(hoveredVirtualViewId, 966791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS, null); 967d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 968d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } break; 969d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov case MotionEvent.ACTION_HOVER_EXIT: { 970d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov provider.sendAccessibilityEventForVirtualView(hoveredVirtualViewId, 971d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov AccessibilityEvent.TYPE_VIEW_HOVER_EXIT); 972d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mLastHoveredChildVirtualViewId = View.NO_ID; 973d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } break; 974d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 975206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 976d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return false; 977d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 978d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 979d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov @Override 980d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov public void computeScroll() { 981206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov Scroller scroller = mFlingScroller; 982206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (scroller.isFinished()) { 983206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov scroller = mAdjustScroller; 984206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (scroller.isFinished()) { 985206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return; 986206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 987206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 988206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov scroller.computeScrollOffset(); 989206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov int currentScrollerY = scroller.getCurrY(); 990206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (mPreviousScrollerY == 0) { 991206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mPreviousScrollerY = scroller.getStartY(); 992206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 993206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov scrollBy(0, currentScrollerY - mPreviousScrollerY); 994206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mPreviousScrollerY = currentScrollerY; 995206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (scroller.isFinished()) { 996206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov onScrollerFinished(scroller); 997206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } else { 998206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov invalidate(); 9999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1001fdf6db6748b32f620a7f68b13a67c38b4e59e5edTom Taylor 10029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 10039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void setEnabled(boolean enabled) { 10049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project super.setEnabled(enabled); 1005d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (!mHasSelectorWheel) { 1006d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mIncrementButton.setEnabled(enabled); 1007d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 1008d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (!mHasSelectorWheel) { 1009d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mDecrementButton.setEnabled(enabled); 1010d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 1011206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mInputText.setEnabled(enabled); 1012206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1013206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 1014206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov @Override 1015206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov public void scrollBy(int x, int y) { 1016b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov int[] selectorIndices = mSelectorIndices; 101734c0688ceafbeef2648bd2287b3b3c3801679448Svetoslav Ganov if (!mWrapSelectorWheel && y > 0 101834c0688ceafbeef2648bd2287b3b3c3801679448Svetoslav Ganov && selectorIndices[SELECTOR_MIDDLE_ITEM_INDEX] <= mMinValue) { 1019206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mCurrentScrollOffset = mInitialScrollOffset; 1020206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return; 1021206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 102234c0688ceafbeef2648bd2287b3b3c3801679448Svetoslav Ganov if (!mWrapSelectorWheel && y < 0 102334c0688ceafbeef2648bd2287b3b3c3801679448Svetoslav Ganov && selectorIndices[SELECTOR_MIDDLE_ITEM_INDEX] >= mMaxValue) { 1024206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mCurrentScrollOffset = mInitialScrollOffset; 1025206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return; 1026206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1027206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mCurrentScrollOffset += y; 1028b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov while (mCurrentScrollOffset - mInitialScrollOffset > mSelectorTextGapHeight) { 1029206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mCurrentScrollOffset -= mSelectorElementHeight; 1030206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov decrementSelectorIndices(selectorIndices); 1031d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov setValueInternal(selectorIndices[SELECTOR_MIDDLE_ITEM_INDEX], true); 1032b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov if (!mWrapSelectorWheel && selectorIndices[SELECTOR_MIDDLE_ITEM_INDEX] <= mMinValue) { 1033206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mCurrentScrollOffset = mInitialScrollOffset; 1034206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1035206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1036b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov while (mCurrentScrollOffset - mInitialScrollOffset < -mSelectorTextGapHeight) { 1037206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mCurrentScrollOffset += mSelectorElementHeight; 1038b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov incrementSelectorIndices(selectorIndices); 1039d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov setValueInternal(selectorIndices[SELECTOR_MIDDLE_ITEM_INDEX], true); 1040b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov if (!mWrapSelectorWheel && selectorIndices[SELECTOR_MIDDLE_ITEM_INDEX] >= mMaxValue) { 1041206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mCurrentScrollOffset = mInitialScrollOffset; 1042206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1043206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 10449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1045fdf6db6748b32f620a7f68b13a67c38b4e59e5edTom Taylor 10464bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov @Override 10474bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov public int getSolidColor() { 10484bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov return mSolidColor; 10494bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov } 10504bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov 105168f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook /** 10524bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * Sets the listener to be notified on change of the current value. 1053206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * 1054e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @param onValueChangedListener The listener. 105568f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook */ 1056cedc446684e94c9971c38c3206f1f224314bda2aSvetoslav Ganov public void setOnValueChangedListener(OnValueChangeListener onValueChangedListener) { 1057cedc446684e94c9971c38c3206f1f224314bda2aSvetoslav Ganov mOnValueChangeListener = onValueChangedListener; 105850f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov } 105950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 106050f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov /** 10614bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * Set listener to be notified for scroll state changes. 106250f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * 1063e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @param onScrollListener The listener. 106450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov */ 106550f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov public void setOnScrollListener(OnScrollListener onScrollListener) { 106650f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov mOnScrollListener = onScrollListener; 10679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1068fdf6db6748b32f620a7f68b13a67c38b4e59e5edTom Taylor 106968f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook /** 10704bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * Set the formatter to be used for formatting the current value. 10714bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * <p> 1072e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * Note: If you have provided alternative values for the values this 1073e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * formatter is never invoked. 10744bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * </p> 1075206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * 1076e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @param formatter The formatter object. If formatter is <code>null</code>, 1077e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * {@link String#valueOf(int)} will be used. 1078d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov *@see #setDisplayedValues(String[]) 107968f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook */ 10809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void setFormatter(Formatter formatter) { 1081e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov if (formatter == mFormatter) { 1082e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov return; 1083e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov } 10849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mFormatter = formatter; 1085b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov initializeSelectorWheelIndices(); 10869cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov updateInputTextView(); 1087206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1088206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 1089206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 1090e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * Set the current value for the number picker. 10914bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * <p> 1092e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * If the argument is less than the {@link NumberPicker#getMinValue()} and 1093e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * {@link NumberPicker#getWrapSelectorWheel()} is <code>false</code> the 1094e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * current value is set to the {@link NumberPicker#getMinValue()} value. 1095e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * </p> 1096e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * <p> 1097e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * If the argument is less than the {@link NumberPicker#getMinValue()} and 1098e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * {@link NumberPicker#getWrapSelectorWheel()} is <code>true</code> the 1099e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * current value is set to the {@link NumberPicker#getMaxValue()} value. 1100e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * </p> 1101e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * <p> 1102e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * If the argument is less than the {@link NumberPicker#getMaxValue()} and 1103e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * {@link NumberPicker#getWrapSelectorWheel()} is <code>false</code> the 1104e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * current value is set to the {@link NumberPicker#getMaxValue()} value. 1105e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * </p> 1106e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * <p> 1107e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * If the argument is less than the {@link NumberPicker#getMaxValue()} and 1108e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * {@link NumberPicker#getWrapSelectorWheel()} is <code>true</code> the 1109e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * current value is set to the {@link NumberPicker#getMinValue()} value. 11104bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * </p> 1111206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * 1112e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @param value The current value. 11134bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * @see #setWrapSelectorWheel(boolean) 1114e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @see #setMinValue(int) 1115e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @see #setMaxValue(int) 1116206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 1117e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov public void setValue(int value) { 1118d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov setValueInternal(value, false); 11199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1120fdf6db6748b32f620a7f68b13a67c38b4e59e5edTom Taylor 112168f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook /** 1122d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * Shows the soft input for its input text. 1123d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov */ 1124d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private void showSoftInput() { 1125d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov InputMethodManager inputMethodManager = InputMethodManager.peekInstance(); 1126d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (inputMethodManager != null) { 1127d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (mHasSelectorWheel) { 1128d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mInputText.setVisibility(View.VISIBLE); 1129d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 1130d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mInputText.requestFocus(); 1131d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov inputMethodManager.showSoftInput(mInputText, 0); 1132d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 1133d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 1134d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 1135d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov /** 1136d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * Hides the soft input if it is active for the input text. 1137b52d9729bfb2ef7ad50d9a5125ebf3a8322429a9Svetoslav Ganov */ 1138b52d9729bfb2ef7ad50d9a5125ebf3a8322429a9Svetoslav Ganov private void hideSoftInput() { 1139b52d9729bfb2ef7ad50d9a5125ebf3a8322429a9Svetoslav Ganov InputMethodManager inputMethodManager = InputMethodManager.peekInstance(); 1140b52d9729bfb2ef7ad50d9a5125ebf3a8322429a9Svetoslav Ganov if (inputMethodManager != null && inputMethodManager.isActive(mInputText)) { 1141b52d9729bfb2ef7ad50d9a5125ebf3a8322429a9Svetoslav Ganov inputMethodManager.hideSoftInputFromWindow(getWindowToken(), 0); 1142d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (mHasSelectorWheel) { 1143d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mInputText.setVisibility(View.INVISIBLE); 1144d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 1145b52d9729bfb2ef7ad50d9a5125ebf3a8322429a9Svetoslav Ganov } 1146b52d9729bfb2ef7ad50d9a5125ebf3a8322429a9Svetoslav Ganov } 1147b52d9729bfb2ef7ad50d9a5125ebf3a8322429a9Svetoslav Ganov 1148b52d9729bfb2ef7ad50d9a5125ebf3a8322429a9Svetoslav Ganov /** 1149ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov * Computes the max width if no such specified as an attribute. 1150ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov */ 1151ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov private void tryComputeMaxWidth() { 1152ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov if (!mComputeMaxWidth) { 1153ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov return; 1154ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov } 1155ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov int maxTextWidth = 0; 1156ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov if (mDisplayedValues == null) { 1157ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov float maxDigitWidth = 0; 1158ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov for (int i = 0; i <= 9; i++) { 1159ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov final float digitWidth = mSelectorWheelPaint.measureText(String.valueOf(i)); 1160ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov if (digitWidth > maxDigitWidth) { 1161ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov maxDigitWidth = digitWidth; 1162ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov } 1163ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov } 1164ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov int numberOfDigits = 0; 1165ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov int current = mMaxValue; 1166ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov while (current > 0) { 1167ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov numberOfDigits++; 1168ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov current = current / 10; 1169ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov } 1170ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov maxTextWidth = (int) (numberOfDigits * maxDigitWidth); 1171ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov } else { 1172ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov final int valueCount = mDisplayedValues.length; 1173ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov for (int i = 0; i < valueCount; i++) { 1174ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov final float textWidth = mSelectorWheelPaint.measureText(mDisplayedValues[i]); 1175ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov if (textWidth > maxTextWidth) { 1176ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov maxTextWidth = (int) textWidth; 1177ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov } 1178ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov } 1179ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov } 1180ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov maxTextWidth += mInputText.getPaddingLeft() + mInputText.getPaddingRight(); 1181ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov if (mMaxWidth != maxTextWidth) { 1182ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov if (maxTextWidth > mMinWidth) { 1183ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov mMaxWidth = maxTextWidth; 1184ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov } else { 1185ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov mMaxWidth = mMinWidth; 1186ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov } 1187ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov invalidate(); 1188ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov } 1189ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov } 1190ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov 1191ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov /** 1192e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * Gets whether the selector wheel wraps when reaching the min/max value. 119368f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook * 1194e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @return True if the selector wheel wraps. 11954bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * 1196e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @see #getMinValue() 1197e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @see #getMaxValue() 119868f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook */ 1199e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov public boolean getWrapSelectorWheel() { 1200e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov return mWrapSelectorWheel; 1201206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1202206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 1203206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 1204e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * Sets whether the selector wheel shown during flinging/scrolling should 1205e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * wrap around the {@link NumberPicker#getMinValue()} and 1206e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * {@link NumberPicker#getMaxValue()} values. 1207e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * <p> 1208d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * By default if the range (max - min) is more than the number of items shown 1209d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * on the selector wheel the selector wheel wrapping is enabled. 1210e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * </p> 12113f9c9eab7b41c409c3c7b503b89ad340e408b6a0Svetoslav Ganov * <p> 1212d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * <strong>Note:</strong> If the number of items, i.e. the range ( 1213d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * {@link #getMaxValue()} - {@link #getMinValue()}) is less than 1214d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * the number of items shown on the selector wheel, the selector wheel will 1215d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * not wrap. Hence, in such a case calling this method is a NOP. 12163f9c9eab7b41c409c3c7b503b89ad340e408b6a0Svetoslav Ganov * </p> 1217d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * 12186304b0d58e74509a9f21b67b5227b2fee2f1b60fSvetoslav Ganov * @param wrapSelectorWheel Whether to wrap. 1219206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 12206304b0d58e74509a9f21b67b5227b2fee2f1b60fSvetoslav Ganov public void setWrapSelectorWheel(boolean wrapSelectorWheel) { 12213f9c9eab7b41c409c3c7b503b89ad340e408b6a0Svetoslav Ganov final boolean wrappingAllowed = (mMaxValue - mMinValue) >= mSelectorIndices.length; 12223f9c9eab7b41c409c3c7b503b89ad340e408b6a0Svetoslav Ganov if ((!wrapSelectorWheel || wrappingAllowed) && wrapSelectorWheel != mWrapSelectorWheel) { 12236304b0d58e74509a9f21b67b5227b2fee2f1b60fSvetoslav Ganov mWrapSelectorWheel = wrapSelectorWheel; 1224206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 12259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 12284bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * Sets the speed at which the numbers be incremented and decremented when 12294bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * the up and down buttons are long pressed respectively. 1230e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * <p> 1231e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * The default value is 300 ms. 1232e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * </p> 123368f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook * 12344bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * @param intervalMillis The speed (in milliseconds) at which the numbers 1235e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * will be incremented and decremented. 12369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 12374bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov public void setOnLongPressUpdateInterval(long intervalMillis) { 12384bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov mLongPressUpdateInterval = intervalMillis; 12399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1240fdf6db6748b32f620a7f68b13a67c38b4e59e5edTom Taylor 1241206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 1242e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * Returns the value of the picker. 1243e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * 1244e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @return The value. 1245e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov */ 1246e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov public int getValue() { 1247e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov return mValue; 1248e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov } 1249e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov 1250e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov /** 1251e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * Returns the min value of the picker. 1252e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * 1253e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @return The min value 1254e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov */ 1255e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov public int getMinValue() { 1256e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov return mMinValue; 1257e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov } 1258e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov 1259e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov /** 1260e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * Sets the min value of the picker. 1261206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * 1262e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @param minValue The min value. 1263206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 1264e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov public void setMinValue(int minValue) { 1265e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov if (mMinValue == minValue) { 1266e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov return; 1267e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov } 1268e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov if (minValue < 0) { 1269e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov throw new IllegalArgumentException("minValue must be >= 0"); 1270e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov } 1271e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov mMinValue = minValue; 1272e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov if (mMinValue > mValue) { 1273e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov mValue = mMinValue; 1274e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov } 1275e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov boolean wrapSelectorWheel = mMaxValue - mMinValue > mSelectorIndices.length; 1276e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov setWrapSelectorWheel(wrapSelectorWheel); 1277b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov initializeSelectorWheelIndices(); 1278e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov updateInputTextView(); 1279ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov tryComputeMaxWidth(); 1280d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov invalidate(); 1281206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1282206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 12834bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov /** 1284e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * Returns the max value of the picker. 12854bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * 1286e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @return The max value. 12874bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov */ 1288e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov public int getMaxValue() { 1289e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov return mMaxValue; 12904bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov } 12914bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov 12924bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov /** 1293e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * Sets the max value of the picker. 12944bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov * 1295e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @param maxValue The max value. 12964bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov */ 1297e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov public void setMaxValue(int maxValue) { 1298e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov if (mMaxValue == maxValue) { 1299e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov return; 1300e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov } 1301e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov if (maxValue < 0) { 1302e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov throw new IllegalArgumentException("maxValue must be >= 0"); 1303e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov } 1304e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov mMaxValue = maxValue; 1305e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov if (mMaxValue < mValue) { 1306e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov mValue = mMaxValue; 1307e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov } 1308e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov boolean wrapSelectorWheel = mMaxValue - mMinValue > mSelectorIndices.length; 1309e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov setWrapSelectorWheel(wrapSelectorWheel); 1310b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov initializeSelectorWheelIndices(); 1311e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov updateInputTextView(); 1312ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov tryComputeMaxWidth(); 1313d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov invalidate(); 1314e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov } 1315e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov 1316e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov /** 1317e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * Gets the values to be displayed instead of string values. 1318e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * 1319e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @return The displayed values. 1320e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov */ 1321e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov public String[] getDisplayedValues() { 1322e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov return mDisplayedValues; 1323e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov } 1324e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov 1325e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov /** 1326e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * Sets the values to be displayed. 1327e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * 1328e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @param displayedValues The displayed values. 1329e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov */ 1330e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov public void setDisplayedValues(String[] displayedValues) { 1331e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov if (mDisplayedValues == displayedValues) { 1332e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov return; 1333e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov } 1334e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov mDisplayedValues = displayedValues; 1335e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov if (mDisplayedValues != null) { 1336e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov // Allow text entry rather than strictly numeric entry. 1337e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov mInputText.setRawInputType(InputType.TYPE_CLASS_TEXT 1338e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov | InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS); 1339e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov } else { 1340e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov mInputText.setRawInputType(InputType.TYPE_CLASS_NUMBER); 1341e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov } 1342e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov updateInputTextView(); 1343b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov initializeSelectorWheelIndices(); 13449f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov tryComputeMaxWidth(); 1345206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1346206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 1347206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov @Override 1348206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov protected float getTopFadingEdgeStrength() { 1349206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return TOP_AND_BOTTOM_FADING_EDGE_STRENGTH; 1350206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1351206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 1352206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov @Override 1353206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov protected float getBottomFadingEdgeStrength() { 1354206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return TOP_AND_BOTTOM_FADING_EDGE_STRENGTH; 1355206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1356206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 1357206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov @Override 1358206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov protected void onDetachedFromWindow() { 1359206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov removeAllCallbacks(); 1360206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1361206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 1362206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov @Override 1363206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov protected void onDraw(Canvas canvas) { 1364d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (!mHasSelectorWheel) { 1365d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov super.onDraw(canvas); 1366206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return; 1367206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1368206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov float x = (mRight - mLeft) / 2; 1369206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov float y = mCurrentScrollOffset; 1370206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 1371232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov // draw the virtual buttons pressed state if needed 1372232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov if (mVirtualButtonPressedDrawable != null 1373232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov && mScrollState == OnScrollListener.SCROLL_STATE_IDLE) { 1374232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov if (mDecrementVirtualButtonPressed) { 1375232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov mVirtualButtonPressedDrawable.setState(PRESSED_STATE_SET); 1376232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov mVirtualButtonPressedDrawable.setBounds(0, 0, mRight, mTopSelectionDividerTop); 1377232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov mVirtualButtonPressedDrawable.draw(canvas); 1378232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov } 1379232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov if (mIncrementVirtualButtonPressed) { 1380232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov mVirtualButtonPressedDrawable.setState(PRESSED_STATE_SET); 1381232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov mVirtualButtonPressedDrawable.setBounds(0, mBottomSelectionDividerBottom, mRight, 1382232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov mBottom); 1383232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov mVirtualButtonPressedDrawable.draw(canvas); 1384232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov } 1385232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov } 1386232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov 13879cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov // draw the selector wheel 1388b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov int[] selectorIndices = mSelectorIndices; 1389206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov for (int i = 0; i < selectorIndices.length; i++) { 1390206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov int selectorIndex = selectorIndices[i]; 1391206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov String scrollSelectorValue = mSelectorIndexToStringCache.get(selectorIndex); 1392d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov // Do not draw the middle item if input is visible since the input 1393d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov // is shown only if the wheel is static and it covers the middle 1394d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov // item. Otherwise, if the user starts editing the text via the 1395d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov // IME he may see a dimmed version of the old value intermixed 1396d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov // with the new one. 13976304b0d58e74509a9f21b67b5227b2fee2f1b60fSvetoslav Ganov if (i != SELECTOR_MIDDLE_ITEM_INDEX || mInputText.getVisibility() != VISIBLE) { 13986304b0d58e74509a9f21b67b5227b2fee2f1b60fSvetoslav Ganov canvas.drawText(scrollSelectorValue, x, y, mSelectorWheelPaint); 13996304b0d58e74509a9f21b67b5227b2fee2f1b60fSvetoslav Ganov } 1400206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov y += mSelectorElementHeight; 1401206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 14029cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov 1403d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov // draw the selection dividers 14049cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov if (mSelectionDivider != null) { 14059cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov // draw the top divider 1406d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov int topOfTopDivider = mTopSelectionDividerTop; 14079cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov int bottomOfTopDivider = topOfTopDivider + mSelectionDividerHeight; 14089cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov mSelectionDivider.setBounds(0, topOfTopDivider, mRight, bottomOfTopDivider); 14099cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov mSelectionDivider.draw(canvas); 14109cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov 14119cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov // draw the bottom divider 1412d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov int bottomOfBottomDivider = mBottomSelectionDividerBottom; 1413d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov int topOfBottomDivider = bottomOfBottomDivider - mSelectionDividerHeight; 14149cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov mSelectionDivider.setBounds(0, topOfBottomDivider, mRight, bottomOfBottomDivider); 14159cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov mSelectionDivider.draw(canvas); 14169cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov } 14179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1418fdf6db6748b32f620a7f68b13a67c38b4e59e5edTom Taylor 14193fec3fe0e3a83c5e0d1264f34bcc55b158537bc6Svetoslav Ganov @Override 1420791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov public void addFocusables(ArrayList<View> views, int direction, int focusableMode) { 1421791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov // We do not want the real descendant to be considered focus search 1422791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov // since it is managed by the accessibility node provider. 1423791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov if ((focusableMode & FOCUSABLES_ACCESSIBILITY) == FOCUSABLES_ACCESSIBILITY) { 1424791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov if (canTakeAccessibilityFocusFromHover() || getAccessibilityNodeProvider() != null) { 1425791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov views.add(this); 1426791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov return; 1427791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } 1428791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } 1429791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov super.addFocusables(views, direction, focusableMode); 14303fec3fe0e3a83c5e0d1264f34bcc55b158537bc6Svetoslav Ganov } 14313fec3fe0e3a83c5e0d1264f34bcc55b158537bc6Svetoslav Ganov 14328a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov @Override 14338a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov public void onInitializeAccessibilityEvent(AccessibilityEvent event) { 14348a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov super.onInitializeAccessibilityEvent(event); 14358a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov event.setClassName(NumberPicker.class.getName()); 1436d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov event.setScrollable(true); 1437d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov event.setScrollY((mMinValue + mValue) * mSelectorElementHeight); 1438d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov event.setMaxScrollY((mMaxValue - mMinValue) * mSelectorElementHeight); 14398a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov } 14408a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov 14418a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov @Override 1442d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov public AccessibilityNodeProvider getAccessibilityNodeProvider() { 1443d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (!mHasSelectorWheel) { 1444d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return super.getAccessibilityNodeProvider(); 1445d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 1446d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (mAccessibilityNodeProvider == null) { 1447d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mAccessibilityNodeProvider = new AccessibilityNodeProviderImpl(); 1448d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 1449d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return mAccessibilityNodeProvider; 14508a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov } 14518a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov 145268f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook /** 1453ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov * Makes a measure spec that tries greedily to use the max value. 1454e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov * 1455e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov * @param measureSpec The measure spec. 1456698e1d5d867a7ac653fa1d6f29cef4cfb73fad38Svetoslav Ganov * @param maxSize The max value for the size. 1457ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov * @return A measure spec greedily imposing the max size. 1458e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov */ 1459698e1d5d867a7ac653fa1d6f29cef4cfb73fad38Svetoslav Ganov private int makeMeasureSpec(int measureSpec, int maxSize) { 14609f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov if (maxSize == SIZE_UNSPECIFIED) { 14619f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov return measureSpec; 14629f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov } 1463ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov final int size = MeasureSpec.getSize(measureSpec); 1464e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov final int mode = MeasureSpec.getMode(measureSpec); 1465e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov switch (mode) { 1466e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov case MeasureSpec.EXACTLY: 1467ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov return measureSpec; 1468e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov case MeasureSpec.AT_MOST: 1469698e1d5d867a7ac653fa1d6f29cef4cfb73fad38Svetoslav Ganov return MeasureSpec.makeMeasureSpec(Math.min(size, maxSize), MeasureSpec.EXACTLY); 1470e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov case MeasureSpec.UNSPECIFIED: 1471698e1d5d867a7ac653fa1d6f29cef4cfb73fad38Svetoslav Ganov return MeasureSpec.makeMeasureSpec(maxSize, MeasureSpec.EXACTLY); 1472e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov default: 1473ec1e06a00d26a783fb948e739ad8157c03e55302Svetoslav Ganov throw new IllegalArgumentException("Unknown measure mode: " + mode); 1474e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov } 1475e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov } 1476e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov 1477e0c8ab5aaa02d7b9b01fe68fb893af4d78482f6cSvetoslav Ganov /** 1478d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * Utility to reconcile a desired size and state, with constraints imposed 1479d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * by a MeasureSpec. Tries to respect the min size, unless a different size 1480d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * is imposed by the constraints. 14819f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov * 14829f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov * @param minSize The minimal desired size. 14839f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov * @param measuredSize The currently measured size. 14849f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov * @param measureSpec The current measure spec. 14859f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov * @return The resolved size and state. 14869f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov */ 1487d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private int resolveSizeAndStateRespectingMinSize( 1488d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov int minSize, int measuredSize, int measureSpec) { 14899f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov if (minSize != SIZE_UNSPECIFIED) { 14909f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov final int desiredWidth = Math.max(minSize, measuredSize); 14919f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov return resolveSizeAndState(desiredWidth, measureSpec, 0); 14929f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov } else { 14939f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov return measuredSize; 14949f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov } 14959f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov } 14969f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov 14979f086d812ff04703de4b14e02a7702ba7c8acb33Svetoslav Ganov /** 1498d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * Resets the selector indices and clear the cached string representation of 1499d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * these indices. 1500a911d4a2b1be7e9ea909a579167826e4a5bac1a3Svetoslav Ganov */ 1501b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov private void initializeSelectorWheelIndices() { 1502a911d4a2b1be7e9ea909a579167826e4a5bac1a3Svetoslav Ganov mSelectorIndexToStringCache.clear(); 1503232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov int[] selectorIndices = mSelectorIndices; 1504b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov int current = getValue(); 1505b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov for (int i = 0; i < mSelectorIndices.length; i++) { 1506b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov int selectorIndex = current + (i - SELECTOR_MIDDLE_ITEM_INDEX); 1507b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov if (mWrapSelectorWheel) { 1508b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov selectorIndex = getWrappedSelectorIndex(selectorIndex); 1509b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov } 1510232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov selectorIndices[i] = selectorIndex; 1511232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov ensureCachedScrollSelectorValue(selectorIndices[i]); 1512a911d4a2b1be7e9ea909a579167826e4a5bac1a3Svetoslav Ganov } 1513a911d4a2b1be7e9ea909a579167826e4a5bac1a3Svetoslav Ganov } 1514a911d4a2b1be7e9ea909a579167826e4a5bac1a3Svetoslav Ganov 1515a911d4a2b1be7e9ea909a579167826e4a5bac1a3Svetoslav Ganov /** 1516d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * Sets the current value of this NumberPicker. 151768f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook * 1518d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * @param current The new value of the NumberPicker. 1519d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * @param notifyChange Whether to notify if the current value changed. 152068f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook */ 1521d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private void setValueInternal(int current, boolean notifyChange) { 1522e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov if (mValue == current) { 1523206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return; 1524206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 15259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Wrap around the values if we go past the start or end 1526e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov if (mWrapSelectorWheel) { 1527206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov current = getWrappedSelectorIndex(current); 1528d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } else { 1529d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov current = Math.max(current, mMinValue); 1530d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov current = Math.min(current, mMaxValue); 15319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1532e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov int previous = mValue; 1533d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mValue = current; 1534d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov updateInputTextView(); 1535d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (notifyChange) { 1536d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov notifyChange(previous, current); 1537d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 1538fac14f9731ce7fc765de582c983af751aab697deSvetoslav Ganov initializeSelectorWheelIndices(); 1539fac14f9731ce7fc765de582c983af751aab697deSvetoslav Ganov invalidate(); 15409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1541fdf6db6748b32f620a7f68b13a67c38b4e59e5edTom Taylor 154268f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook /** 1543b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov * Changes the current value by one which is increment or 1544b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov * decrement based on the passes argument. 1545d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * decrement the current value. 1546b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov * 1547b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov * @param increment True to increment, false to decrement. 1548b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov */ 1549d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private void changeValueByOne(boolean increment) { 1550d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (mHasSelectorWheel) { 1551b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov mInputText.setVisibility(View.INVISIBLE); 1552d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (!moveToFinalScrollerPosition(mFlingScroller)) { 1553d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov moveToFinalScrollerPosition(mAdjustScroller); 1554d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 1555b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov mPreviousScrollerY = 0; 1556b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov if (increment) { 1557fe41ce4ef97e7da585fdbf06988da8047e72b9f6Svetoslav Ganov mFlingScroller.startScroll(0, 0, 0, -mSelectorElementHeight, SNAP_SCROLL_DURATION); 1558b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov } else { 1559fe41ce4ef97e7da585fdbf06988da8047e72b9f6Svetoslav Ganov mFlingScroller.startScroll(0, 0, 0, mSelectorElementHeight, SNAP_SCROLL_DURATION); 1560b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov } 1561b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov invalidate(); 1562b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov } else { 1563b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov if (increment) { 1564d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov setValueInternal(mValue + 1, true); 1565b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov } else { 1566d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov setValueInternal(mValue - 1, true); 1567b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov } 1568b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov } 1569b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov } 1570b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov 1571b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov private void initializeSelectorWheel() { 1572b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov initializeSelectorWheelIndices(); 1573b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov int[] selectorIndices = mSelectorIndices; 15749cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov int totalTextHeight = selectorIndices.length * mTextSize; 157501fa0d7aae1a551e1e7cfb90d2aeaf2fcb3978afSvetoslav Ganov float totalTextGapHeight = (mBottom - mTop) - totalTextHeight; 1576d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov float textGapCount = selectorIndices.length; 1577b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov mSelectorTextGapHeight = (int) (totalTextGapHeight / textGapCount + 0.5f); 1578b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov mSelectorElementHeight = mTextSize + mSelectorTextGapHeight; 1579d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov // Ensure that the middle item is positioned the same as the text in 1580d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov // mInputText 1581eeafd4296b7cf4c2ad9c985562f6d70e2a3ffc03Chet Haase int editTextTextPosition = mInputText.getBaseline() + mInputText.getTop(); 1582d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mInitialScrollOffset = editTextTextPosition 1583d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov - (mSelectorElementHeight * SELECTOR_MIDDLE_ITEM_INDEX); 15846a19fcde07527706c2a9175e0b9f2a71549b7ffeSvetoslav Ganov mCurrentScrollOffset = mInitialScrollOffset; 15859cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov updateInputTextView(); 15869cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov } 15879cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov 1588b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov private void initializeFadingEdges() { 1589b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov setVerticalFadingEdgeEnabled(true); 1590b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov setFadingEdgeLength((mBottom - mTop - mTextSize) / 2); 1591b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov } 1592b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov 1593206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 1594206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Callback invoked upon completion of a given <code>scroller</code>. 1595206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 1596206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private void onScrollerFinished(Scroller scroller) { 1597206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (scroller == mFlingScroller) { 1598d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (!ensureScrollWheelAdjusted()) { 1599b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov updateInputTextView(); 1600b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov } 1601d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov onScrollStateChange(OnScrollListener.SCROLL_STATE_IDLE); 16029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 1603d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (mScrollState != OnScrollListener.SCROLL_STATE_TOUCH_SCROLL) { 1604d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov updateInputTextView(); 1605d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 16069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1608fdf6db6748b32f620a7f68b13a67c38b4e59e5edTom Taylor 1609206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 16109cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov * Handles transition to a given <code>scrollState</code> 161150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov */ 16129cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov private void onScrollStateChange(int scrollState) { 16139cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov if (mScrollState == scrollState) { 16149cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov return; 16159cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov } 16169cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov mScrollState = scrollState; 16179cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov if (mOnScrollListener != null) { 16184bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov mOnScrollListener.onScrollStateChange(this, scrollState); 161950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov } 162050f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov } 162150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 162250f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov /** 1623206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Flings the selector with the given <code>velocityY</code>. 1624206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 1625206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private void fling(int velocityY) { 1626206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mPreviousScrollerY = 0; 1627206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 1628234484a9fb53786aa8b7ed2a3df7e24d41817689Svetoslav Ganov if (velocityY > 0) { 1629234484a9fb53786aa8b7ed2a3df7e24d41817689Svetoslav Ganov mFlingScroller.fling(0, 0, 0, velocityY, 0, 0, 0, Integer.MAX_VALUE); 1630206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } else { 1631234484a9fb53786aa8b7ed2a3df7e24d41817689Svetoslav Ganov mFlingScroller.fling(0, Integer.MAX_VALUE, 0, velocityY, 0, 0, 0, Integer.MAX_VALUE); 16329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1633206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 1634206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov invalidate(); 16359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1637206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 1638206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * @return The wrapped index <code>selectorIndex</code> value. 163968f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook */ 1640206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private int getWrappedSelectorIndex(int selectorIndex) { 1641e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov if (selectorIndex > mMaxValue) { 1642e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov return mMinValue + (selectorIndex - mMaxValue) % (mMaxValue - mMinValue) - 1; 1643e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov } else if (selectorIndex < mMinValue) { 1644e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov return mMaxValue - (mMinValue - selectorIndex) % (mMaxValue - mMinValue) + 1; 1645206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1646206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return selectorIndex; 16479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1648fdf6db6748b32f620a7f68b13a67c38b4e59e5edTom Taylor 1649206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 1650206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Increments the <code>selectorIndices</code> whose string representations 1651206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * will be displayed in the selector. 1652206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 1653b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov private void incrementSelectorIndices(int[] selectorIndices) { 1654206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov for (int i = 0; i < selectorIndices.length - 1; i++) { 1655206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov selectorIndices[i] = selectorIndices[i + 1]; 1656206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1657206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov int nextScrollSelectorIndex = selectorIndices[selectorIndices.length - 2] + 1; 1658e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov if (mWrapSelectorWheel && nextScrollSelectorIndex > mMaxValue) { 1659e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov nextScrollSelectorIndex = mMinValue; 1660206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1661206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov selectorIndices[selectorIndices.length - 1] = nextScrollSelectorIndex; 1662206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov ensureCachedScrollSelectorValue(nextScrollSelectorIndex); 1663206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1664fdf6db6748b32f620a7f68b13a67c38b4e59e5edTom Taylor 1665206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 1666206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Decrements the <code>selectorIndices</code> whose string representations 1667206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * will be displayed in the selector. 1668206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 1669206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private void decrementSelectorIndices(int[] selectorIndices) { 1670206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov for (int i = selectorIndices.length - 1; i > 0; i--) { 1671206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov selectorIndices[i] = selectorIndices[i - 1]; 1672206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1673206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov int nextScrollSelectorIndex = selectorIndices[1] - 1; 1674e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov if (mWrapSelectorWheel && nextScrollSelectorIndex < mMinValue) { 1675e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov nextScrollSelectorIndex = mMaxValue; 1676206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1677206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov selectorIndices[0] = nextScrollSelectorIndex; 1678206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov ensureCachedScrollSelectorValue(nextScrollSelectorIndex); 1679206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1680fdf6db6748b32f620a7f68b13a67c38b4e59e5edTom Taylor 1681206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 1682206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Ensures we have a cached string representation of the given <code> 1683d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * selectorIndex</code> to avoid multiple instantiations of the same string. 1684206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 1685206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private void ensureCachedScrollSelectorValue(int selectorIndex) { 1686206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov SparseArray<String> cache = mSelectorIndexToStringCache; 1687206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov String scrollSelectorValue = cache.get(selectorIndex); 1688206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (scrollSelectorValue != null) { 1689206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return; 1690206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1691e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov if (selectorIndex < mMinValue || selectorIndex > mMaxValue) { 1692206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov scrollSelectorValue = ""; 1693206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } else { 1694206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (mDisplayedValues != null) { 1695e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov int displayedValueIndex = selectorIndex - mMinValue; 169650f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov scrollSelectorValue = mDisplayedValues[displayedValueIndex]; 1697206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } else { 1698206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov scrollSelectorValue = formatNumber(selectorIndex); 16999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 17009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1701206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov cache.put(selectorIndex, scrollSelectorValue); 17029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1703fdf6db6748b32f620a7f68b13a67c38b4e59e5edTom Taylor 1704206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private String formatNumber(int value) { 1705e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov return (mFormatter != null) ? mFormatter.format(value) : String.valueOf(value); 1706206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 17079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1708206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private void validateInputTextView(View v) { 1709206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov String str = String.valueOf(((TextView) v).getText()); 1710206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (TextUtils.isEmpty(str)) { 1711206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // Restore to the old value as we don't allow empty values 1712206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov updateInputTextView(); 1713206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } else { 1714206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // Check the new value and ensure it's in range 1715206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov int current = getSelectedPos(str.toString()); 1716d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov setValueInternal(current, true); 17179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1718206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1719fdf6db6748b32f620a7f68b13a67c38b4e59e5edTom Taylor 1720206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 1721206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Updates the view of this NumberPicker. If displayValues were specified in 17229cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov * the string corresponding to the index specified by the current value will 17239cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov * be returned. Otherwise, the formatter specified in {@link #setFormatter} 17249cd5fb2f46e219ec8250383fb201b94cb2ee8c0aSvetoslav Ganov * will be used to format the number. 1725d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * 1726d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * @return Whether the text was updated. 1727206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 1728d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private boolean updateInputTextView() { 1729206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /* 1730206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * If we don't have displayed values then use the current number else 1731206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * find the correct value in the displayed values for the current 1732206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * number. 1733206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 1734d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov String text = (mDisplayedValues == null) ? formatNumber(mValue) 1735d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov : mDisplayedValues[mValue - mMinValue]; 1736d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (!TextUtils.isEmpty(text) && !text.equals(mInputText.getText().toString())) { 1737d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mInputText.setText(text); 1738d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return true; 17399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 17403fec3fe0e3a83c5e0d1264f34bcc55b158537bc6Svetoslav Ganov 1741d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return false; 1742206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1743fdf6db6748b32f620a7f68b13a67c38b4e59e5edTom Taylor 1744206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 1745206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Notifies the listener, if registered, of a change of the value of this 1746206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * NumberPicker. 1747206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 1748206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private void notifyChange(int previous, int current) { 1749cedc446684e94c9971c38c3206f1f224314bda2aSvetoslav Ganov if (mOnValueChangeListener != null) { 1750cedc446684e94c9971c38c3206f1f224314bda2aSvetoslav Ganov mOnValueChangeListener.onValueChange(this, previous, mValue); 1751206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1752206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 17539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1754206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 1755b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov * Posts a command for changing the current value by one. 1756b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov * 1757b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov * @param increment Whether to increment or decrement the value. 1758206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 1759d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private void postChangeCurrentByOneFromLongPress(boolean increment, long delayMillis) { 1760b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov if (mChangeCurrentByOneFromLongPressCommand == null) { 1761b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov mChangeCurrentByOneFromLongPressCommand = new ChangeCurrentByOneFromLongPressCommand(); 1762d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } else { 1763d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov removeCallbacks(mChangeCurrentByOneFromLongPressCommand); 1764d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 1765d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mChangeCurrentByOneFromLongPressCommand.setStep(increment); 1766d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov postDelayed(mChangeCurrentByOneFromLongPressCommand, delayMillis); 1767d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 1768d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 1769d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov /** 1770d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * Removes the command for changing the current value by one. 1771d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov */ 1772d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private void removeChangeCurrentByOneFromLongPress() { 1773d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (mChangeCurrentByOneFromLongPressCommand != null) { 1774d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov removeCallbacks(mChangeCurrentByOneFromLongPressCommand); 1775d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 1776d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 1777d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 1778d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov /** 1779d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * Posts a command for beginning an edit of the current value via IME on 1780d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * long press. 1781d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov */ 1782d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private void postBeginSoftInputOnLongPressCommand() { 1783d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (mBeginSoftInputOnLongPressCommand == null) { 1784d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mBeginSoftInputOnLongPressCommand = new BeginSoftInputOnLongPressCommand(); 1785d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } else { 1786d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov removeCallbacks(mBeginSoftInputOnLongPressCommand); 1787d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 1788d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov postDelayed(mBeginSoftInputOnLongPressCommand, ViewConfiguration.getLongPressTimeout()); 1789d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 1790d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 1791d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov /** 1792d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * Removes the command for beginning an edit of the current value via IME. 1793d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov */ 1794d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private void removeBeginSoftInputCommand() { 1795d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (mBeginSoftInputOnLongPressCommand != null) { 1796d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov removeCallbacks(mBeginSoftInputOnLongPressCommand); 1797206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1798206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 17999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1800206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 1801206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Removes all pending callback from the message queue. 1802206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 1803206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private void removeAllCallbacks() { 1804b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov if (mChangeCurrentByOneFromLongPressCommand != null) { 1805b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov removeCallbacks(mChangeCurrentByOneFromLongPressCommand); 1806206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1807206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (mSetSelectionCommand != null) { 1808206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov removeCallbacks(mSetSelectionCommand); 18099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1810d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (mBeginSoftInputOnLongPressCommand != null) { 1811d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov removeCallbacks(mBeginSoftInputOnLongPressCommand); 1812d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 1813232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov mPressedStateHelper.cancel(); 18149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 18159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1816206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 1817206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * @return The selected index given its displayed <code>value</code>. 1818206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 1819206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private int getSelectedPos(String value) { 18209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mDisplayedValues == null) { 1821aa516beb79693ceffbd81a7c9d14c940e412cccbRomain Guy try { 1822206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return Integer.parseInt(value); 1823aa516beb79693ceffbd81a7c9d14c940e412cccbRomain Guy } catch (NumberFormatException e) { 1824206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // Ignore as if it's not a number we don't care 1825aa516beb79693ceffbd81a7c9d14c940e412cccbRomain Guy } 18269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 18279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < mDisplayedValues.length; i++) { 1828206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // Don't force the user to type in jan when ja will do 1829206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov value = value.toLowerCase(); 1830206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (mDisplayedValues[i].toLowerCase().startsWith(value)) { 1831e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov return mMinValue + i; 18329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 18339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1834fdf6db6748b32f620a7f68b13a67c38b4e59e5edTom Taylor 1835206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /* 1836206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * The user might have typed in a number into the month field i.e. 18379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 10 instead of OCT so support that too. 18389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 18399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 1840206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return Integer.parseInt(value); 18419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (NumberFormatException e) { 1842fdf6db6748b32f620a7f68b13a67c38b4e59e5edTom Taylor 1843206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // Ignore as if it's not a number we don't care 18449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 18459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1846e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov return mMinValue; 18479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 18489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 18499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1850206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Posts an {@link SetSelectionCommand} from the given <code>selectionStart 1851d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * </code> to <code>selectionEnd</code>. 18529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1853206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private void postSetSelectionCommand(int selectionStart, int selectionEnd) { 1854206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (mSetSelectionCommand == null) { 1855206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mSetSelectionCommand = new SetSelectionCommand(); 1856206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } else { 1857206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov removeCallbacks(mSetSelectionCommand); 1858206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1859206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mSetSelectionCommand.mSelectionStart = selectionStart; 1860206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mSetSelectionCommand.mSelectionEnd = selectionEnd; 1861206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov post(mSetSelectionCommand); 18629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 186368f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook 186468f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook /** 1865206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Filter for accepting only valid indices or prefixes of the string 1866206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * representation of valid indices. 186768f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook */ 1868206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov class InputTextFilter extends NumberKeyListener { 1869206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 1870206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // XXX This doesn't allow for range limits when controlled by a 1871206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov // soft input method! 1872206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov public int getInputType() { 1873206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return InputType.TYPE_CLASS_TEXT; 1874206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1875206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 1876206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov @Override 1877206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov protected char[] getAcceptedChars() { 1878206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return DIGIT_CHARACTERS; 1879206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1880206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 1881206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov @Override 1882d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov public CharSequence filter( 1883d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov CharSequence source, int start, int end, Spanned dest, int dstart, int dend) { 1884206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (mDisplayedValues == null) { 1885206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov CharSequence filtered = super.filter(source, start, end, dest, dstart, dend); 1886206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (filtered == null) { 1887206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov filtered = source.subSequence(start, end); 1888206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1889206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 1890206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov String result = String.valueOf(dest.subSequence(0, dstart)) + filtered 1891206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov + dest.subSequence(dend, dest.length()); 1892206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 1893206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if ("".equals(result)) { 1894206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return result; 1895206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1896206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov int val = getSelectedPos(result); 1897206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 1898206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /* 1899206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Ensure the user can't type in a value greater than the max 1900206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * allowed. We have to allow less than min as the user might 1901206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * want to delete some numbers and then type a new number. 1902206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 1903e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov if (val > mMaxValue) { 1904206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return ""; 1905206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } else { 1906206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return filtered; 1907206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1908206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } else { 1909206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov CharSequence filtered = String.valueOf(source.subSequence(start, end)); 1910206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (TextUtils.isEmpty(filtered)) { 1911206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return ""; 1912206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1913206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov String result = String.valueOf(dest.subSequence(0, dstart)) + filtered 1914206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov + dest.subSequence(dend, dest.length()); 1915206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov String str = String.valueOf(result).toLowerCase(); 1916206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov for (String val : mDisplayedValues) { 1917206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov String valLowerCase = val.toLowerCase(); 1918206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov if (valLowerCase.startsWith(str)) { 1919206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov postSetSelectionCommand(result.length(), val.length()); 1920206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return val.subSequence(dstart, val.length()); 1921206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1922206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1923206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov return ""; 1924206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1925206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1926206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 1927206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 1928206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 1929d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * Ensures that the scroll wheel is adjusted i.e. there is no offset and the 1930d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * middle element is in the middle of the widget. 1931d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * 1932d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * @return Whether an adjustment has been made. 1933d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov */ 1934d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private boolean ensureScrollWheelAdjusted() { 1935d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov // adjust to the closest value 1936d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov int deltaY = mInitialScrollOffset - mCurrentScrollOffset; 1937d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (deltaY != 0) { 1938d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mPreviousScrollerY = 0; 1939d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (Math.abs(deltaY) > mSelectorElementHeight / 2) { 1940d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov deltaY += (deltaY > 0) ? -mSelectorElementHeight : mSelectorElementHeight; 1941d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 1942d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mAdjustScroller.startScroll(0, 0, 0, deltaY, SELECTOR_ADJUSTMENT_DURATION_MILLIS); 1943d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov invalidate(); 1944d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return true; 1945d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 1946d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return false; 1947d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 1948d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 1949232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov class PressedStateHelper implements Runnable { 1950232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov public static final int BUTTON_INCREMENT = 1; 1951232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov public static final int BUTTON_DECREMENT = 2; 1952232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov 1953232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov private final int MODE_PRESS = 1; 1954232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov private final int MODE_TAPPED = 2; 1955232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov 1956232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov private int mManagedButton; 1957232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov private int mMode; 1958232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov 1959232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov public void cancel() { 1960232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov mMode = 0; 1961232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov mManagedButton = 0; 1962232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov NumberPicker.this.removeCallbacks(this); 1963232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov if (mIncrementVirtualButtonPressed) { 1964232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov mIncrementVirtualButtonPressed = false; 1965232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov invalidate(0, mBottomSelectionDividerBottom, mRight, mBottom); 1966232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov } 1967232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov mDecrementVirtualButtonPressed = false; 1968232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov if (mDecrementVirtualButtonPressed) { 1969232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov invalidate(0, 0, mRight, mTopSelectionDividerTop); 1970fe41ce4ef97e7da585fdbf06988da8047e72b9f6Svetoslav Ganov } 1971fe41ce4ef97e7da585fdbf06988da8047e72b9f6Svetoslav Ganov } 1972fe41ce4ef97e7da585fdbf06988da8047e72b9f6Svetoslav Ganov 1973232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov public void buttonPressDelayed(int button) { 1974232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov cancel(); 1975232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov mMode = MODE_PRESS; 1976232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov mManagedButton = button; 1977232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov NumberPicker.this.postDelayed(this, ViewConfiguration.getTapTimeout()); 1978232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov } 1979232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov 1980232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov public void buttonTapped(int button) { 1981232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov cancel(); 1982232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov mMode = MODE_TAPPED; 1983232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov mManagedButton = button; 1984232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov NumberPicker.this.post(this); 1985232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov } 1986232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov 1987232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov @Override 1988232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov public void run() { 1989232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov switch (mMode) { 1990232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov case MODE_PRESS: { 1991232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov switch (mManagedButton) { 1992232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov case BUTTON_INCREMENT: { 1993232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov mIncrementVirtualButtonPressed = true; 1994232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov invalidate(0, mBottomSelectionDividerBottom, mRight, mBottom); 1995232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov } break; 1996232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov case BUTTON_DECREMENT: { 1997232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov mDecrementVirtualButtonPressed = true; 1998232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov invalidate(0, 0, mRight, mTopSelectionDividerTop); 1999232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov } 2000232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov } 2001232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov } break; 2002232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov case MODE_TAPPED: { 2003232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov switch (mManagedButton) { 2004232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov case BUTTON_INCREMENT: { 2005232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov if (!mIncrementVirtualButtonPressed) { 2006232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov NumberPicker.this.postDelayed(this, 2007232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov ViewConfiguration.getPressedStateDuration()); 2008232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov } 2009232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov mIncrementVirtualButtonPressed ^= true; 2010232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov invalidate(0, mBottomSelectionDividerBottom, mRight, mBottom); 2011232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov } break; 2012232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov case BUTTON_DECREMENT: { 2013232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov if (!mDecrementVirtualButtonPressed) { 2014232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov NumberPicker.this.postDelayed(this, 2015232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov ViewConfiguration.getPressedStateDuration()); 2016232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov } 2017232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov mDecrementVirtualButtonPressed ^= true; 2018232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov invalidate(0, 0, mRight, mTopSelectionDividerTop); 2019232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov } 2020232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov } 2021232dd3f335b8995cd9ab220f7b3fad77076de42bSvetoslav Ganov } break; 2022fe41ce4ef97e7da585fdbf06988da8047e72b9f6Svetoslav Ganov } 2023fe41ce4ef97e7da585fdbf06988da8047e72b9f6Svetoslav Ganov } 2024fe41ce4ef97e7da585fdbf06988da8047e72b9f6Svetoslav Ganov } 2025fe41ce4ef97e7da585fdbf06988da8047e72b9f6Svetoslav Ganov 2026d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov /** 2027206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov * Command for setting the input text selection. 2028206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 2029206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov class SetSelectionCommand implements Runnable { 2030206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private int mSelectionStart; 2031206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 2032206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov private int mSelectionEnd; 2033206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 2034206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov public void run() { 2035206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov mInputText.setSelection(mSelectionStart, mSelectionEnd); 2036206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 2037206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 2038206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 2039206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov /** 2040b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov * Command for changing the current value from a long press by one. 2041206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov */ 2042b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov class ChangeCurrentByOneFromLongPressCommand implements Runnable { 2043b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov private boolean mIncrement; 2044206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 2045d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private void setStep(boolean increment) { 2046b80a3fcad1776c1b9abe3662899660b4f88ac2abSvetoslav Ganov mIncrement = increment; 2047206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 2048206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov 2049d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov @Override 2050206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov public void run() { 2051d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov changeValueByOne(mIncrement); 20524bfd794475e6fb34c9dfa83d4302e9db365a3709Svetoslav Ganov postDelayed(this, mLongPressUpdateInterval); 2053206316a61f904ea0a6b106137dd7715a2c246d4cSvetoslav Ganov } 205468f2f547f56f239b60d13b2b62a08a65874f6662Paul Westbrook } 2055a2b41b438d45570867e4682c0caaf93ace5e712eSvetoslav Ganov 2056a2b41b438d45570867e4682c0caaf93ace5e712eSvetoslav Ganov /** 2057a2b41b438d45570867e4682c0caaf93ace5e712eSvetoslav Ganov * @hide 2058a2b41b438d45570867e4682c0caaf93ace5e712eSvetoslav Ganov */ 2059a2b41b438d45570867e4682c0caaf93ace5e712eSvetoslav Ganov public static class CustomEditText extends EditText { 2060a2b41b438d45570867e4682c0caaf93ace5e712eSvetoslav Ganov 2061a2b41b438d45570867e4682c0caaf93ace5e712eSvetoslav Ganov public CustomEditText(Context context, AttributeSet attrs) { 2062a2b41b438d45570867e4682c0caaf93ace5e712eSvetoslav Ganov super(context, attrs); 2063a2b41b438d45570867e4682c0caaf93ace5e712eSvetoslav Ganov } 2064a2b41b438d45570867e4682c0caaf93ace5e712eSvetoslav Ganov 2065a2b41b438d45570867e4682c0caaf93ace5e712eSvetoslav Ganov @Override 2066a2b41b438d45570867e4682c0caaf93ace5e712eSvetoslav Ganov public void onEditorAction(int actionCode) { 2067a2b41b438d45570867e4682c0caaf93ace5e712eSvetoslav Ganov super.onEditorAction(actionCode); 2068a2b41b438d45570867e4682c0caaf93ace5e712eSvetoslav Ganov if (actionCode == EditorInfo.IME_ACTION_DONE) { 2069a2b41b438d45570867e4682c0caaf93ace5e712eSvetoslav Ganov clearFocus(); 2070a2b41b438d45570867e4682c0caaf93ace5e712eSvetoslav Ganov } 2071a2b41b438d45570867e4682c0caaf93ace5e712eSvetoslav Ganov } 2072a2b41b438d45570867e4682c0caaf93ace5e712eSvetoslav Ganov } 2073d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 2074d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov /** 2075d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov * Command for beginning soft input on long press. 2076d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov */ 2077d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov class BeginSoftInputOnLongPressCommand implements Runnable { 2078d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 2079d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov @Override 2080d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov public void run() { 2081d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov showSoftInput(); 2082d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mIngonreMoveEvents = true; 2083d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2084d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2085d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 2086791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov /** 2087791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov * Class for managing virtual view tree rooted at this picker. 2088791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov */ 2089d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov class AccessibilityNodeProviderImpl extends AccessibilityNodeProvider { 2090791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov private static final int UNDEFINED = Integer.MIN_VALUE; 2091791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov 2092d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private static final int VIRTUAL_VIEW_ID_INCREMENT = 1; 2093d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 2094d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private static final int VIRTUAL_VIEW_ID_INPUT = 2; 2095d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 2096d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private static final int VIRTUAL_VIEW_ID_DECREMENT = 3; 2097d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 2098d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private final Rect mTempRect = new Rect(); 2099d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 2100d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private final int[] mTempArray = new int[2]; 2101d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 2102791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov private int mAccessibilityFocusedView = UNDEFINED; 2103791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov 2104d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov @Override 2105d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov public AccessibilityNodeInfo createAccessibilityNodeInfo(int virtualViewId) { 2106d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov switch (virtualViewId) { 2107d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov case View.NO_ID: 2108d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return createAccessibilityNodeInfoForNumberPicker( mScrollX, mScrollY, 2109d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mScrollX + (mRight - mLeft), mScrollY + (mBottom - mTop)); 2110d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov case VIRTUAL_VIEW_ID_DECREMENT: 2111d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return createAccessibilityNodeInfoForVirtualButton(VIRTUAL_VIEW_ID_DECREMENT, 2112d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov getVirtualDecrementButtonText(), mScrollX, mScrollY, 2113d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mScrollX + (mRight - mLeft), 2114d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mTopSelectionDividerTop + mSelectionDividerHeight); 2115d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov case VIRTUAL_VIEW_ID_INPUT: 2116d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return createAccessibiltyNodeInfoForInputText(); 2117d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov case VIRTUAL_VIEW_ID_INCREMENT: 2118d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return createAccessibilityNodeInfoForVirtualButton(VIRTUAL_VIEW_ID_INCREMENT, 2119d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov getVirtualIncrementButtonText(), mScrollX, 2120d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mBottomSelectionDividerBottom - mSelectionDividerHeight, 2121d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mScrollX + (mRight - mLeft), mScrollY + (mBottom - mTop)); 2122d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2123d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return super.createAccessibilityNodeInfo(virtualViewId); 2124d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2125d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 2126d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov @Override 2127d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov public List<AccessibilityNodeInfo> findAccessibilityNodeInfosByText(String searched, 2128d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov int virtualViewId) { 2129d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (TextUtils.isEmpty(searched)) { 2130d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return Collections.emptyList(); 2131d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2132d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov String searchedLowerCase = searched.toLowerCase(); 2133d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov List<AccessibilityNodeInfo> result = new ArrayList<AccessibilityNodeInfo>(); 2134d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov switch (virtualViewId) { 2135d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov case View.NO_ID: { 2136d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov findAccessibilityNodeInfosByTextInChild(searchedLowerCase, 2137d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov VIRTUAL_VIEW_ID_DECREMENT, result); 2138d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov findAccessibilityNodeInfosByTextInChild(searchedLowerCase, 2139d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov VIRTUAL_VIEW_ID_INPUT, result); 2140d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov findAccessibilityNodeInfosByTextInChild(searchedLowerCase, 2141d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov VIRTUAL_VIEW_ID_INCREMENT, result); 2142d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return result; 2143d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2144d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov case VIRTUAL_VIEW_ID_DECREMENT: 2145d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov case VIRTUAL_VIEW_ID_INCREMENT: 2146d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov case VIRTUAL_VIEW_ID_INPUT: { 2147d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov findAccessibilityNodeInfosByTextInChild(searchedLowerCase, virtualViewId, 2148d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov result); 2149d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return result; 2150d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2151d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2152d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return super.findAccessibilityNodeInfosByText(searched, virtualViewId); 2153d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2154d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 2155d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov @Override 2156aa780c110922148a6a4ba06734bb2b0bb8c98f93Svetoslav Ganov public boolean performAction(int virtualViewId, int action, Bundle arguments) { 2157d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov switch (virtualViewId) { 2158791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov case View.NO_ID: { 2159791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov switch (action) { 2160791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov case AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS: { 2161791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov if (mAccessibilityFocusedView != virtualViewId) { 2162791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov mAccessibilityFocusedView = virtualViewId; 2163791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov requestAccessibilityFocus(); 2164791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov return true; 2165791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } 2166791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } return false; 2167791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov case AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS: { 2168791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov if (mAccessibilityFocusedView == virtualViewId) { 2169791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov mAccessibilityFocusedView = UNDEFINED; 2170791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov clearAccessibilityFocus(); 2171791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov return true; 2172791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } 2173791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov return false; 2174791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } 217548d1586f4065fc9ab97a679da1e4f7c327c943f2Svetoslav Ganov case AccessibilityNodeInfo.ACTION_SCROLL_FORWARD: { 217648d1586f4065fc9ab97a679da1e4f7c327c943f2Svetoslav Ganov if (getWrapSelectorWheel() || getValue() < getMaxValue()) { 217748d1586f4065fc9ab97a679da1e4f7c327c943f2Svetoslav Ganov changeValueByOne(true); 217848d1586f4065fc9ab97a679da1e4f7c327c943f2Svetoslav Ganov return true; 217948d1586f4065fc9ab97a679da1e4f7c327c943f2Svetoslav Ganov } 218048d1586f4065fc9ab97a679da1e4f7c327c943f2Svetoslav Ganov } return false; 218148d1586f4065fc9ab97a679da1e4f7c327c943f2Svetoslav Ganov case AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD: { 218248d1586f4065fc9ab97a679da1e4f7c327c943f2Svetoslav Ganov if (getWrapSelectorWheel() || getValue() > getMinValue()) { 218348d1586f4065fc9ab97a679da1e4f7c327c943f2Svetoslav Ganov changeValueByOne(false); 218448d1586f4065fc9ab97a679da1e4f7c327c943f2Svetoslav Ganov return true; 218548d1586f4065fc9ab97a679da1e4f7c327c943f2Svetoslav Ganov } 218648d1586f4065fc9ab97a679da1e4f7c327c943f2Svetoslav Ganov } return false; 2187791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } 2188791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } break; 2189d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov case VIRTUAL_VIEW_ID_INPUT: { 2190d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov switch (action) { 2191d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov case AccessibilityNodeInfo.ACTION_FOCUS: { 2192d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (!mInputText.isFocused()) { 2193d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return mInputText.requestFocus(); 2194d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2195d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } break; 2196d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov case AccessibilityNodeInfo.ACTION_CLEAR_FOCUS: { 2197d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (mInputText.isFocused()) { 2198d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mInputText.clearFocus(); 2199d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return true; 2200d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2201791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov return false; 2202791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } 2203791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov case AccessibilityNodeInfo.ACTION_CLICK: { 2204791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov showSoftInput(); 2205791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov return true; 2206791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } 2207791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov case AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS: { 2208791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov if (mAccessibilityFocusedView != virtualViewId) { 2209791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov mAccessibilityFocusedView = virtualViewId; 2210791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov sendAccessibilityEventForVirtualView(virtualViewId, 2211791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED); 2212791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov mInputText.invalidate(); 2213791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov return true; 2214791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } 2215791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } return false; 2216791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov case AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS: { 2217791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov if (mAccessibilityFocusedView == virtualViewId) { 2218791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov mAccessibilityFocusedView = UNDEFINED; 2219791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov sendAccessibilityEventForVirtualView(virtualViewId, 2220791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED); 2221791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov mInputText.invalidate(); 2222791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov return true; 2223791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } 2224791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } return false; 2225791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov default: { 2226791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov return mInputText.performAccessibilityAction(action, arguments); 2227791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } 2228d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2229791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } return false; 2230791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov case VIRTUAL_VIEW_ID_INCREMENT: { 2231791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov switch (action) { 2232791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov case AccessibilityNodeInfo.ACTION_CLICK: { 2233791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov NumberPicker.this.changeValueByOne(true); 2234791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov sendAccessibilityEventForVirtualView(virtualViewId, 2235791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov AccessibilityEvent.TYPE_VIEW_CLICKED); 2236791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } return true; 2237791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov case AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS: { 2238791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov if (mAccessibilityFocusedView != virtualViewId) { 2239791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov mAccessibilityFocusedView = virtualViewId; 2240791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov sendAccessibilityEventForVirtualView(virtualViewId, 2241791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED); 2242791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov invalidate(0, mBottomSelectionDividerBottom, mRight, mBottom); 2243791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov return true; 2244791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } 2245791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } return false; 2246791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov case AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS: { 2247791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov if (mAccessibilityFocusedView == virtualViewId) { 2248791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov mAccessibilityFocusedView = UNDEFINED; 2249791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov sendAccessibilityEventForVirtualView(virtualViewId, 2250791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED); 2251791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov invalidate(0, mBottomSelectionDividerBottom, mRight, mBottom); 2252791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov return true; 2253791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } 2254791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } return false; 2255791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } 2256791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } return false; 2257791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov case VIRTUAL_VIEW_ID_DECREMENT: { 2258791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov switch (action) { 2259791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov case AccessibilityNodeInfo.ACTION_CLICK: { 2260791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov final boolean increment = (virtualViewId == VIRTUAL_VIEW_ID_INCREMENT); 2261791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov NumberPicker.this.changeValueByOne(increment); 2262791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov sendAccessibilityEventForVirtualView(virtualViewId, 2263791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov AccessibilityEvent.TYPE_VIEW_CLICKED); 2264791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } return true; 2265791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov case AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS: { 2266791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov if (mAccessibilityFocusedView != virtualViewId) { 2267791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov mAccessibilityFocusedView = virtualViewId; 2268791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov sendAccessibilityEventForVirtualView(virtualViewId, 2269791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED); 2270791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov invalidate(0, 0, mRight, mTopSelectionDividerTop); 2271791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov return true; 2272791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } 2273791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } return false; 2274791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov case AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS: { 2275791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov if (mAccessibilityFocusedView == virtualViewId) { 2276791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov mAccessibilityFocusedView = UNDEFINED; 2277791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov sendAccessibilityEventForVirtualView(virtualViewId, 2278791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED); 2279791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov invalidate(0, 0, mRight, mTopSelectionDividerTop); 2280791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov return true; 2281791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } 2282791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } return false; 2283791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } 2284791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } return false; 2285d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2286aa780c110922148a6a4ba06734bb2b0bb8c98f93Svetoslav Ganov return super.performAction(virtualViewId, action, arguments); 2287d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2288d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 2289791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov @Override 2290791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov public AccessibilityNodeInfo findAccessibilityFocus(int virtualViewId) { 2291791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov return createAccessibilityNodeInfo(mAccessibilityFocusedView); 2292791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } 2293791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov 2294791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov @Override 2295791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov public AccessibilityNodeInfo accessibilityFocusSearch(int direction, int virtualViewId) { 2296791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov switch (direction) { 2297791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov case View.ACCESSIBILITY_FOCUS_DOWN: 2298791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov case View.ACCESSIBILITY_FOCUS_FORWARD: { 2299791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov switch (mAccessibilityFocusedView) { 2300791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov case UNDEFINED: { 2301791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov return createAccessibilityNodeInfo(View.NO_ID); 2302791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } 2303791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov case View.NO_ID: { 2304791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov if (hasVirtualDecrementButton()) { 2305791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov return createAccessibilityNodeInfo(VIRTUAL_VIEW_ID_DECREMENT); 2306791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } 2307791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } 2308791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov //$FALL-THROUGH$ 2309791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov case VIRTUAL_VIEW_ID_DECREMENT: { 2310791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov return createAccessibilityNodeInfo(VIRTUAL_VIEW_ID_INPUT); 2311791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } 2312791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov case VIRTUAL_VIEW_ID_INPUT: { 2313791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov if (hasVirtualIncrementButton()) { 2314791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov return createAccessibilityNodeInfo(VIRTUAL_VIEW_ID_INCREMENT); 2315791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } 2316791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } 2317791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov //$FALL-THROUGH$ 2318791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov case VIRTUAL_VIEW_ID_INCREMENT: { 2319791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov View nextFocus = NumberPicker.this.focusSearch(direction); 2320791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov if (nextFocus != null) { 2321791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov return nextFocus.createAccessibilityNodeInfo(); 2322791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } 2323791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov return null; 2324791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } 2325791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } 2326791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } break; 2327791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov case View.ACCESSIBILITY_FOCUS_UP: 2328791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov case View.ACCESSIBILITY_FOCUS_BACKWARD: { 2329791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov switch (mAccessibilityFocusedView) { 2330791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov case UNDEFINED: { 2331791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov return createAccessibilityNodeInfo(View.NO_ID); 2332791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } 2333791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov case View.NO_ID: { 2334791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov if (hasVirtualIncrementButton()) { 2335791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov return createAccessibilityNodeInfo(VIRTUAL_VIEW_ID_INCREMENT); 2336791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } 2337791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } 2338791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov //$FALL-THROUGH$ 2339791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov case VIRTUAL_VIEW_ID_INCREMENT: { 2340791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov return createAccessibilityNodeInfo(VIRTUAL_VIEW_ID_INPUT); 2341791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } 2342791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov case VIRTUAL_VIEW_ID_INPUT: { 2343791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov if (hasVirtualDecrementButton()) { 2344791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov return createAccessibilityNodeInfo(VIRTUAL_VIEW_ID_DECREMENT); 2345791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } 2346791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } 2347791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov //$FALL-THROUGH$ 2348791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov case VIRTUAL_VIEW_ID_DECREMENT: { 2349791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov View nextFocus = NumberPicker.this.focusSearch(direction); 2350791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov if (nextFocus != null) { 2351791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov return nextFocus.createAccessibilityNodeInfo(); 2352791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } 2353791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov return null; 2354791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } 2355791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } 2356791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } break; 2357791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } 2358791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov return null; 2359791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } 2360791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov 2361d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov public void sendAccessibilityEventForVirtualView(int virtualViewId, int eventType) { 2362d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov switch (virtualViewId) { 2363d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov case VIRTUAL_VIEW_ID_DECREMENT: { 2364791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov if (hasVirtualDecrementButton()) { 2365791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov sendAccessibilityEventForVirtualButton(virtualViewId, eventType, 2366791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov getVirtualDecrementButtonText()); 2367791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } 2368d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } break; 2369d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov case VIRTUAL_VIEW_ID_INPUT: { 2370d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov sendAccessibilityEventForVirtualText(eventType); 2371d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } break; 2372d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov case VIRTUAL_VIEW_ID_INCREMENT: { 2373791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov if (hasVirtualIncrementButton()) { 2374791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov sendAccessibilityEventForVirtualButton(virtualViewId, eventType, 2375791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov getVirtualIncrementButtonText()); 2376791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } 2377d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } break; 2378d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2379d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2380d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 2381d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private void sendAccessibilityEventForVirtualText(int eventType) { 2382d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov AccessibilityEvent event = AccessibilityEvent.obtain(eventType); 2383d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mInputText.onInitializeAccessibilityEvent(event); 2384d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov mInputText.onPopulateAccessibilityEvent(event); 2385d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov event.setSource(NumberPicker.this, VIRTUAL_VIEW_ID_INPUT); 2386d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov requestSendAccessibilityEvent(NumberPicker.this, event); 2387d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2388d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 2389d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private void sendAccessibilityEventForVirtualButton(int virtualViewId, int eventType, 2390d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov String text) { 2391d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov AccessibilityEvent event = AccessibilityEvent.obtain(eventType); 2392d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov event.setClassName(Button.class.getName()); 2393d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov event.setPackageName(mContext.getPackageName()); 2394d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov event.getText().add(text); 2395d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov event.setEnabled(NumberPicker.this.isEnabled()); 2396d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov event.setSource(NumberPicker.this, virtualViewId); 2397d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov requestSendAccessibilityEvent(NumberPicker.this, event); 2398d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2399d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 2400d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private void findAccessibilityNodeInfosByTextInChild(String searchedLowerCase, 2401d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov int virtualViewId, List<AccessibilityNodeInfo> outResult) { 2402d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov switch (virtualViewId) { 2403d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov case VIRTUAL_VIEW_ID_DECREMENT: { 2404d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov String text = getVirtualDecrementButtonText(); 2405d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (!TextUtils.isEmpty(text) 2406d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov && text.toString().toLowerCase().contains(searchedLowerCase)) { 2407d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov outResult.add(createAccessibilityNodeInfo(VIRTUAL_VIEW_ID_DECREMENT)); 2408d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2409d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } return; 2410d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov case VIRTUAL_VIEW_ID_INPUT: { 2411d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov CharSequence text = mInputText.getText(); 2412d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (!TextUtils.isEmpty(text) && 2413d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov text.toString().toLowerCase().contains(searchedLowerCase)) { 2414d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov outResult.add(createAccessibilityNodeInfo(VIRTUAL_VIEW_ID_INPUT)); 2415d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return; 2416d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2417d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov CharSequence contentDesc = mInputText.getText(); 2418d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (!TextUtils.isEmpty(contentDesc) && 2419d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov contentDesc.toString().toLowerCase().contains(searchedLowerCase)) { 2420d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov outResult.add(createAccessibilityNodeInfo(VIRTUAL_VIEW_ID_INPUT)); 2421d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return; 2422d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2423d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } break; 2424d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov case VIRTUAL_VIEW_ID_INCREMENT: { 2425d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov String text = getVirtualIncrementButtonText(); 2426d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (!TextUtils.isEmpty(text) 2427d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov && text.toString().toLowerCase().contains(searchedLowerCase)) { 2428d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov outResult.add(createAccessibilityNodeInfo(VIRTUAL_VIEW_ID_INCREMENT)); 2429d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2430d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } return; 2431d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2432d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2433d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 2434d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private AccessibilityNodeInfo createAccessibiltyNodeInfoForInputText() { 2435d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov AccessibilityNodeInfo info = mInputText.createAccessibilityNodeInfo(); 2436d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov info.setSource(NumberPicker.this, VIRTUAL_VIEW_ID_INPUT); 2437791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov if (mAccessibilityFocusedView != VIRTUAL_VIEW_ID_INPUT) { 2438791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov info.addAction(AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS); 2439791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } 2440791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov if (mAccessibilityFocusedView == VIRTUAL_VIEW_ID_INPUT) { 2441791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov info.addAction(AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS); 2442791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } 2443d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return info; 2444d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2445d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 2446d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private AccessibilityNodeInfo createAccessibilityNodeInfoForVirtualButton(int virtualViewId, 2447d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov String text, int left, int top, int right, int bottom) { 2448d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain(); 2449d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov info.setClassName(Button.class.getName()); 2450d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov info.setPackageName(mContext.getPackageName()); 2451d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov info.setSource(NumberPicker.this, virtualViewId); 2452d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov info.setParent(NumberPicker.this); 2453d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov info.setText(text); 2454d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov info.setClickable(true); 2455d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov info.setLongClickable(true); 2456d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov info.setEnabled(NumberPicker.this.isEnabled()); 2457d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov Rect boundsInParent = mTempRect; 2458d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov boundsInParent.set(left, top, right, bottom); 24590d607fbe546ac943de38dad33ae681b09efec6eaGuang Zhu info.setVisibleToUser(isVisibleToUser(boundsInParent)); 2460d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov info.setBoundsInParent(boundsInParent); 2461d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov Rect boundsInScreen = boundsInParent; 2462d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov int[] locationOnScreen = mTempArray; 2463d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov getLocationOnScreen(locationOnScreen); 2464d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov boundsInScreen.offset(locationOnScreen[0], locationOnScreen[1]); 2465d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov info.setBoundsInScreen(boundsInScreen); 2466791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov 2467791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov if (mAccessibilityFocusedView != virtualViewId) { 2468791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov info.addAction(AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS); 2469791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } 2470791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov if (mAccessibilityFocusedView == virtualViewId) { 2471791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov info.addAction(AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS); 2472791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } 2473791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov info.addAction(AccessibilityNodeInfo.ACTION_CLICK); 2474791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov 2475d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return info; 2476d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2477d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 2478d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private AccessibilityNodeInfo createAccessibilityNodeInfoForNumberPicker(int left, int top, 2479d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov int right, int bottom) { 2480d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain(); 24810d607fbe546ac943de38dad33ae681b09efec6eaGuang Zhu info.setClassName(NumberPicker.class.getName()); 2482d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov info.setPackageName(mContext.getPackageName()); 2483d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov info.setSource(NumberPicker.this); 2484791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov 2485791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov if (hasVirtualDecrementButton()) { 2486791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov info.addChild(NumberPicker.this, VIRTUAL_VIEW_ID_DECREMENT); 2487791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } 24880d607fbe546ac943de38dad33ae681b09efec6eaGuang Zhu info.addChild(NumberPicker.this, VIRTUAL_VIEW_ID_INPUT); 2489791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov if (hasVirtualIncrementButton()) { 2490791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov info.addChild(NumberPicker.this, VIRTUAL_VIEW_ID_INCREMENT); 2491791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } 2492791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov 24934528b4e882584745f48263fa6626987e63832a2aSvetoslav Ganov info.setParent((View) getParentForAccessibility()); 2494d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov info.setEnabled(NumberPicker.this.isEnabled()); 2495d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov info.setScrollable(true); 2496d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov Rect boundsInParent = mTempRect; 2497d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov boundsInParent.set(left, top, right, bottom); 2498d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov info.setBoundsInParent(boundsInParent); 24990d607fbe546ac943de38dad33ae681b09efec6eaGuang Zhu info.setVisibleToUser(isVisibleToUser()); 2500d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov Rect boundsInScreen = boundsInParent; 2501d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov int[] locationOnScreen = mTempArray; 2502d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov getLocationOnScreen(locationOnScreen); 2503d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov boundsInScreen.offset(locationOnScreen[0], locationOnScreen[1]); 2504d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov info.setBoundsInScreen(boundsInScreen); 2505791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov 2506791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov if (mAccessibilityFocusedView != View.NO_ID) { 2507791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov info.addAction(AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS); 2508791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } 2509791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov if (mAccessibilityFocusedView == View.NO_ID) { 2510791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov info.addAction(AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS); 2511791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } 251248d1586f4065fc9ab97a679da1e4f7c327c943f2Svetoslav Ganov if (getWrapSelectorWheel() || getValue() < getMaxValue()) { 251348d1586f4065fc9ab97a679da1e4f7c327c943f2Svetoslav Ganov info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD); 251448d1586f4065fc9ab97a679da1e4f7c327c943f2Svetoslav Ganov } 251548d1586f4065fc9ab97a679da1e4f7c327c943f2Svetoslav Ganov if (getWrapSelectorWheel() || getValue() > getMinValue()) { 251648d1586f4065fc9ab97a679da1e4f7c327c943f2Svetoslav Ganov info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD); 251748d1586f4065fc9ab97a679da1e4f7c327c943f2Svetoslav Ganov } 2518791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov 2519d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return info; 2520d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2521d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 2522791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov private boolean hasVirtualDecrementButton() { 2523791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov return getWrapSelectorWheel() || getValue() > getMinValue(); 2524791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } 2525791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov 2526791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov private boolean hasVirtualIncrementButton() { 2527791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov return getWrapSelectorWheel() || getValue() < getMaxValue(); 2528791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov } 2529791fd31a68c59395952005886ba799169f80a29aSvetoslav Ganov 2530d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private String getVirtualDecrementButtonText() { 2531d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov int value = mValue - 1; 2532d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (mWrapSelectorWheel) { 2533d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov value = getWrappedSelectorIndex(value); 2534d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2535d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (value >= mMinValue) { 2536d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return (mDisplayedValues == null) ? formatNumber(value) 2537d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov : mDisplayedValues[value - mMinValue]; 2538d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2539d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return null; 2540d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2541d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov 2542d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov private String getVirtualIncrementButtonText() { 2543d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov int value = mValue + 1; 2544d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (mWrapSelectorWheel) { 2545d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov value = getWrappedSelectorIndex(value); 2546d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2547d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov if (value <= mMaxValue) { 2548d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return (mDisplayedValues == null) ? formatNumber(value) 2549d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov : mDisplayedValues[value - mMinValue]; 2550d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2551d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov return null; 2552d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 2553d11e6151fe88314505fa7adca6278de2e772b11cSvetoslav Ganov } 25547762d93621f508f4410fd37b5bbdfec0071b0420Paul Westbrook} 2555