summaryrefslogtreecommitdiffstats
path: root/core/java/android/widget
diff options
context:
space:
mode:
authorSvetoslav Ganov <svetoslavganov@google.com>2012-03-19 20:03:45 -0700
committerAndroid (Google) Code Review <android-gerrit@google.com>2012-03-19 20:03:45 -0700
commit52c10554628079e38cde2e9b13bde5099deeca35 (patch)
tree1abc4e4e799460feb870299867ce4197c9242eb6 /core/java/android/widget
parent485932f6afa1541caa9429835ef44a928e7ddfb1 (diff)
parentefd1c6777929e5a81a030fc51145cd3064d3e979 (diff)
downloadframeworks_base-52c10554628079e38cde2e9b13bde5099deeca35.zip
frameworks_base-52c10554628079e38cde2e9b13bde5099deeca35.tar.gz
frameworks_base-52c10554628079e38cde2e9b13bde5099deeca35.tar.bz2
Merge "Revert "Revamp of the NumberPicker widget.""
Diffstat (limited to 'core/java/android/widget')
-rw-r--r--core/java/android/widget/DatePicker.java37
-rw-r--r--core/java/android/widget/NumberPicker.java1300
-rw-r--r--core/java/android/widget/TimePicker.java31
3 files changed, 605 insertions, 763 deletions
diff --git a/core/java/android/widget/DatePicker.java b/core/java/android/widget/DatePicker.java
index c5066b6..fd93980 100644
--- a/core/java/android/widget/DatePicker.java
+++ b/core/java/android/widget/DatePicker.java
@@ -29,8 +29,8 @@ import android.util.AttributeSet;
import android.util.Log;
import android.util.SparseArray;
import android.view.LayoutInflater;
-import android.view.View;
import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.AccessibilityNodeInfo;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodManager;
@@ -280,7 +280,9 @@ public class DatePicker extends FrameLayout {
reorderSpinners();
// set content descriptions
- setContentDescriptions();
+ if (AccessibilityManager.getInstance(mContext).isEnabled()) {
+ setContentDescriptions();
+ }
}
/**
@@ -715,27 +717,20 @@ public class DatePicker extends FrameLayout {
private void setContentDescriptions() {
// Day
- trySetContentDescription(mDaySpinner, R.id.increment,
- R.string.date_picker_increment_day_button);
- trySetContentDescription(mDaySpinner, R.id.decrement,
- R.string.date_picker_decrement_day_button);
+ String text = mContext.getString(R.string.date_picker_increment_day_button);
+ mDaySpinner.findViewById(R.id.increment).setContentDescription(text);
+ text = mContext.getString(R.string.date_picker_decrement_day_button);
+ mDaySpinner.findViewById(R.id.decrement).setContentDescription(text);
// Month
- trySetContentDescription(mMonthSpinner, R.id.increment,
- R.string.date_picker_increment_month_button);
- trySetContentDescription(mMonthSpinner, R.id.decrement,
- R.string.date_picker_decrement_month_button);
+ text = mContext.getString(R.string.date_picker_increment_month_button);
+ mMonthSpinner.findViewById(R.id.increment).setContentDescription(text);
+ text = mContext.getString(R.string.date_picker_decrement_month_button);
+ mMonthSpinner.findViewById(R.id.decrement).setContentDescription(text);
// Year
- trySetContentDescription(mYearSpinner, R.id.increment,
- R.string.date_picker_increment_year_button);
- trySetContentDescription(mYearSpinner, R.id.decrement,
- R.string.date_picker_decrement_year_button);
- }
-
- private void trySetContentDescription(View root, int viewId, int contDescResId) {
- View target = root.findViewById(viewId);
- if (target != null) {
- target.setContentDescription(mContext.getString(contDescResId));
- }
+ text = mContext.getString(R.string.date_picker_increment_year_button);
+ mYearSpinner.findViewById(R.id.increment).setContentDescription(text);
+ text = mContext.getString(R.string.date_picker_decrement_year_button);
+ mYearSpinner.findViewById(R.id.decrement).setContentDescription(text);
}
private void updateInputState() {
diff --git a/core/java/android/widget/NumberPicker.java b/core/java/android/widget/NumberPicker.java
index 506b0c0..3335da0 100644
--- a/core/java/android/widget/NumberPicker.java
+++ b/core/java/android/widget/NumberPicker.java
@@ -16,6 +16,10 @@
package android.widget;
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
import android.annotation.Widget;
import android.content.Context;
import android.content.res.ColorStateList;
@@ -44,41 +48,22 @@ import android.view.ViewConfiguration;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.AccessibilityNodeInfo;
-import android.view.accessibility.AccessibilityNodeProvider;
import android.view.animation.DecelerateInterpolator;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodManager;
import com.android.internal.R;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
/**
* A widget that enables the user to select a number form a predefined range.
- * There are two flavors of this widget and which one is presented to the user
- * depends on the current theme.
- * <ul>
- * <li>
- * If the current theme is derived from {@link android.R.style#Theme} the widget
- * presents the current value as an editable input field with an increment button
- * above and a decrement button below. Long pressing the buttons allows for a quick
- * change of the current value. Tapping on the input field allows to type in
- * a desired value.
- * </li>
- * <li>
- * If the current theme is derived from {@link android.R.style#Theme_Holo} or
- * {@link android.R.style#Theme_Holo_Light} the widget presents the current
- * value as an editable input field with a lesser value above and a greater
- * value below. Tapping on the lesser or greater value selects it by animating
- * the number axis up or down to make the chosen value current. Flinging up
- * or down allows for multiple increments or decrements of the current value.
- * Long pressing on the lesser and greater values also allows for a quick change
- * of the current value. Tapping on the current value allows to type in a
- * desired value.
- * </li>
- * </ul>
+ * The widget presents an input field and up and down buttons for selecting the
+ * current value. Pressing/long-pressing the up and down buttons increments and
+ * decrements the current value respectively. Touching the input field shows a
+ * scroll wheel, which when touched allows direct edit
+ * of the current value. Sliding gestures up or down hide the buttons and the
+ * input filed, show and rotate the scroll wheel. Flinging is
+ * also supported. The widget enables mapping from positions to strings such
+ * that, instead of the position index, the corresponding string is displayed.
* <p>
* For an example of using this widget, see {@link android.widget.TimePicker}.
* </p>
@@ -89,7 +74,7 @@ public class NumberPicker extends LinearLayout {
/**
* The number of items show in the selector wheel.
*/
- private static final int SELECTOR_WHEEL_ITEM_COUNT = 3;
+ public static final int SELECTOR_WHEEL_ITEM_COUNT = 5;
/**
* The default update interval during long press.
@@ -99,7 +84,7 @@ public class NumberPicker extends LinearLayout {
/**
* The index of the middle selector item.
*/
- private static final int SELECTOR_MIDDLE_ITEM_INDEX = SELECTOR_WHEEL_ITEM_COUNT / 2;
+ private static final int SELECTOR_MIDDLE_ITEM_INDEX = 2;
/**
* The coefficient by which to adjust (divide) the max fling velocity.
@@ -112,12 +97,19 @@ public class NumberPicker extends LinearLayout {
private static final int SELECTOR_ADJUSTMENT_DURATION_MILLIS = 800;
/**
- * The duration of scrolling to the next/previous value while changing the
- * current value by one, i.e. increment or decrement.
+ * The duration of scrolling to the next/previous value while changing
+ * the current value by one, i.e. increment or decrement.
*/
private static final int CHANGE_CURRENT_BY_ONE_SCROLL_DURATION = 300;
/**
+ * The the delay for showing the input controls after a single tap on the
+ * input text.
+ */
+ private static final int SHOW_INPUT_CONTROLS_DELAY_MILLIS = ViewConfiguration
+ .getDoubleTapTimeout();
+
+ /**
* The strength of fading in the top and bottom while drawing the selector.
*/
private static final float TOP_AND_BOTTOM_FADING_EDGE_STRENGTH = 0.9f;
@@ -128,31 +120,56 @@ public class NumberPicker extends LinearLayout {
private static final int UNSCALED_DEFAULT_SELECTION_DIVIDER_HEIGHT = 2;
/**
- * The default unscaled distance between the selection dividers.
+ * In this state the selector wheel is not shown.
+ */
+ private static final int SELECTOR_WHEEL_STATE_NONE = 0;
+
+ /**
+ * In this state the selector wheel is small.
+ */
+ private static final int SELECTOR_WHEEL_STATE_SMALL = 1;
+
+ /**
+ * In this state the selector wheel is large.
+ */
+ private static final int SELECTOR_WHEEL_STATE_LARGE = 2;
+
+ /**
+ * The alpha of the selector wheel when it is bright.
+ */
+ private static final int SELECTOR_WHEEL_BRIGHT_ALPHA = 255;
+
+ /**
+ * The alpha of the selector wheel when it is dimmed.
*/
- private static final int UNSCALED_DEFAULT_SELECTION_DIVIDERS_DISTANCE = 48;
+ private static final int SELECTOR_WHEEL_DIM_ALPHA = 60;
/**
- * The default unscaled minimal distance for a swipe to be considered a fling.
+ * The alpha for the increment/decrement button when it is transparent.
*/
- private static final int UNSCALED_DEFAULT_MIN_FLING_DISTANCE = 150;
+ private static final int BUTTON_ALPHA_TRANSPARENT = 0;
/**
- * Coefficient for adjusting touch scroll distance.
+ * The alpha for the increment/decrement button when it is opaque.
*/
- private static final float TOUCH_SCROLL_DECELERATION_COEFFICIENT = 2.5f;
+ private static final int BUTTON_ALPHA_OPAQUE = 1;
/**
- * The resource id for the default layout.
+ * The property for setting the selector paint.
*/
- private static final int DEFAULT_LAYOUT_RESOURCE_ID = R.layout.number_picker;
+ private static final String PROPERTY_SELECTOR_PAINT_ALPHA = "selectorPaintAlpha";
+
+ /**
+ * The property for setting the increment/decrement button alpha.
+ */
+ private static final String PROPERTY_BUTTON_ALPHA = "alpha";
/**
* The numbers accepted by the input text's {@link Filter}
*/
private static final char[] DIGIT_CHARACTERS = new char[] {
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'
- };
+ };
/**
* Constant for unspecified size.
@@ -198,11 +215,6 @@ public class NumberPicker extends LinearLayout {
private final EditText mInputText;
/**
- * The distance between the two selection dividers.
- */
- private final int mSelectionDividersDistance;
-
- /**
* The min height of this widget.
*/
private final int mMinHeight;
@@ -233,11 +245,6 @@ public class NumberPicker extends LinearLayout {
private final int mTextSize;
/**
- * The minimal distance for a swipe to be considered a fling.
- */
- private final int mMinFlingDistance;
-
- /**
* The height of the gap between text elements if the selector wheel.
*/
private int mSelectorTextGapHeight;
@@ -290,7 +297,10 @@ public class NumberPicker extends LinearLayout {
/**
* The selector indices whose value are show by the selector.
*/
- private final int[] mSelectorIndices = new int[SELECTOR_WHEEL_ITEM_COUNT];
+ private final int[] mSelectorIndices = new int[] {
+ Integer.MIN_VALUE, Integer.MIN_VALUE, Integer.MIN_VALUE, Integer.MIN_VALUE,
+ Integer.MIN_VALUE
+ };
/**
* The {@link Paint} for drawing the selector.
@@ -333,15 +343,25 @@ public class NumberPicker extends LinearLayout {
private SetSelectionCommand mSetSelectionCommand;
/**
+ * Handle to the reusable command for adjusting the scroller.
+ */
+ private AdjustScrollerCommand mAdjustScrollerCommand;
+
+ /**
* Handle to the reusable command for changing the current value from long
* press by one.
*/
private ChangeCurrentByOneFromLongPressCommand mChangeCurrentByOneFromLongPressCommand;
/**
- * Command for beginning an edit of the current value via IME on long press.
+ * {@link Animator} for showing the up/down arrows.
+ */
+ private final AnimatorSet mShowInputControlsAnimator;
+
+ /**
+ * {@link Animator} for dimming the selector wheel.
*/
- private BeginSoftInputOnLongPressCommand mBeginSoftInputOnLongPressCommand;
+ private final Animator mDimSelectorWheelAnimator;
/**
* The Y position of the last down event.
@@ -349,14 +369,24 @@ public class NumberPicker extends LinearLayout {
private float mLastDownEventY;
/**
- * The time of the last down event.
+ * The Y position of the last motion event.
*/
- private long mLastDownEventTime;
+ private float mLastMotionEventY;
/**
- * The Y position of the last down or move event.
+ * Flag if to check for double tap and potentially start edit.
*/
- private float mLastDownOrMoveEventY;
+ private boolean mCheckBeginEditOnUpEvent;
+
+ /**
+ * Flag if to adjust the selector wheel on next up event.
+ */
+ private boolean mAdjustScrollerOnUpEvent;
+
+ /**
+ * The state of the selector wheel.
+ */
+ private int mSelectorWheelState;
/**
* Determines speed during touch scrolling.
@@ -389,9 +419,9 @@ public class NumberPicker extends LinearLayout {
private final int mSolidColor;
/**
- * Flag whether this widget has a selector wheel.
+ * Flag indicating if this widget supports flinging.
*/
- private final boolean mHasSelectorWheel;
+ private final boolean mFlingable;
/**
* Divider for showing item to be selected while scrolling
@@ -404,40 +434,29 @@ public class NumberPicker extends LinearLayout {
private final int mSelectionDividerHeight;
/**
- * The current scroll state of the number picker.
- */
- private int mScrollState = OnScrollListener.SCROLL_STATE_IDLE;
-
- /**
- * Flag whether to ignore move events - we ignore such when we show in IME
- * to prevent the content from scrolling.
- */
- private boolean mIngonreMoveEvents;
-
- /**
- * Flag whether to show soft input on tap.
+ * Reusable {@link Rect} instance.
*/
- private boolean mShowSoftInputOnTap;
+ private final Rect mTempRect = new Rect();
/**
- * The top of the top selection divider.
+ * The current scroll state of the number picker.
*/
- private int mTopSelectionDividerTop;
+ private int mScrollState = OnScrollListener.SCROLL_STATE_IDLE;
/**
- * The bottom of the bottom selection divider.
+ * The duration of the animation for showing the input controls.
*/
- private int mBottomSelectionDividerBottom;
+ private final long mShowInputControlsAnimimationDuration;
/**
- * The virtual id of the last hovered child.
+ * Flag whether the scoll wheel and the fading edges have been initialized.
*/
- private int mLastHoveredChildVirtualViewId;
+ private boolean mScrollWheelAndFadingEdgesInitialized;
/**
- * Provider to report to clients the semantic structure of this widget.
+ * The time of the last up event.
*/
- private AccessibilityNodeProviderImpl mAccessibilityNodeProvider;
+ private long mLastUpEventTimeMillis;
/**
* Interface to listen for changes of the current value.
@@ -465,7 +484,7 @@ public class NumberPicker extends LinearLayout {
public static int SCROLL_STATE_IDLE = 0;
/**
- * The user is scrolling using touch, and his finger is still on the screen.
+ * The user is scrolling using touch, and their finger is still on the screen.
*/
public static int SCROLL_STATE_TOUCH_SCROLL = 1;
@@ -530,78 +549,58 @@ public class NumberPicker extends LinearLayout {
super(context, attrs, defStyle);
// process style attributes
- TypedArray attributesArray = context.obtainStyledAttributes(
- attrs, R.styleable.NumberPicker, defStyle, 0);
- final int layoutResId = attributesArray.getResourceId(
- R.styleable.NumberPicker_internalLayout, DEFAULT_LAYOUT_RESOURCE_ID);
-
- mHasSelectorWheel = (layoutResId != DEFAULT_LAYOUT_RESOURCE_ID);
-
+ TypedArray attributesArray = context.obtainStyledAttributes(attrs,
+ R.styleable.NumberPicker, defStyle, 0);
mSolidColor = attributesArray.getColor(R.styleable.NumberPicker_solidColor, 0);
-
+ mFlingable = attributesArray.getBoolean(R.styleable.NumberPicker_flingable, true);
mSelectionDivider = attributesArray.getDrawable(R.styleable.NumberPicker_selectionDivider);
-
- final int defSelectionDividerHeight = (int) TypedValue.applyDimension(
- TypedValue.COMPLEX_UNIT_DIP, UNSCALED_DEFAULT_SELECTION_DIVIDER_HEIGHT,
+ int defSelectionDividerHeight = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
+ UNSCALED_DEFAULT_SELECTION_DIVIDER_HEIGHT,
getResources().getDisplayMetrics());
mSelectionDividerHeight = attributesArray.getDimensionPixelSize(
R.styleable.NumberPicker_selectionDividerHeight, defSelectionDividerHeight);
-
- final int defSelectionDividerDistance = (int) TypedValue.applyDimension(
- TypedValue.COMPLEX_UNIT_DIP, UNSCALED_DEFAULT_SELECTION_DIVIDERS_DISTANCE,
- getResources().getDisplayMetrics());
- mSelectionDividersDistance = attributesArray.getDimensionPixelSize(
- R.styleable.NumberPicker_selectionDividersDistance, defSelectionDividerDistance);
-
- final int defMinFlingDistance = (int) TypedValue.applyDimension(
- TypedValue.COMPLEX_UNIT_DIP, UNSCALED_DEFAULT_MIN_FLING_DISTANCE,
- getResources().getDisplayMetrics());
- mMinFlingDistance = attributesArray.getDimensionPixelSize(
- R.styleable.NumberPicker_minFlingDistance, defMinFlingDistance);
-
mMinHeight = attributesArray.getDimensionPixelSize(
R.styleable.NumberPicker_internalMinHeight, SIZE_UNSPECIFIED);
-
mMaxHeight = attributesArray.getDimensionPixelSize(
R.styleable.NumberPicker_internalMaxHeight, SIZE_UNSPECIFIED);
if (mMinHeight != SIZE_UNSPECIFIED && mMaxHeight != SIZE_UNSPECIFIED
&& mMinHeight > mMaxHeight) {
throw new IllegalArgumentException("minHeight > maxHeight");
}
-
- mMinWidth = attributesArray.getDimensionPixelSize(
- R.styleable.NumberPicker_internalMinWidth, SIZE_UNSPECIFIED);
-
- mMaxWidth = attributesArray.getDimensionPixelSize(
- R.styleable.NumberPicker_internalMaxWidth, SIZE_UNSPECIFIED);
+ mMinWidth = attributesArray.getDimensionPixelSize(R.styleable.NumberPicker_internalMinWidth,
+ SIZE_UNSPECIFIED);
+ mMaxWidth = attributesArray.getDimensionPixelSize(R.styleable.NumberPicker_internalMaxWidth,
+ SIZE_UNSPECIFIED);
if (mMinWidth != SIZE_UNSPECIFIED && mMaxWidth != SIZE_UNSPECIFIED
&& mMinWidth > mMaxWidth) {
throw new IllegalArgumentException("minWidth > maxWidth");
}
-
mComputeMaxWidth = (mMaxWidth == Integer.MAX_VALUE);
-
attributesArray.recycle();
+ mShowInputControlsAnimimationDuration = getResources().getInteger(
+ R.integer.config_longAnimTime);
+
// By default Linearlayout that we extend is not drawn. This is
// its draw() method is not called but dispatchDraw() is called
// directly (see ViewGroup.drawChild()). However, this class uses
// the fading edge effect implemented by View and we need our
// draw() method to be called. Therefore, we declare we will draw.
- setWillNotDraw(!mHasSelectorWheel);
+ setWillNotDraw(false);
+ setSelectorWheelState(SELECTOR_WHEEL_STATE_NONE);
LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(
Context.LAYOUT_INFLATER_SERVICE);
- inflater.inflate(layoutResId, this, true);
+ inflater.inflate(R.layout.number_picker, this, true);
OnClickListener onClickListener = new OnClickListener() {
public void onClick(View v) {
hideSoftInput();
mInputText.clearFocus();
if (v.getId() == R.id.increment) {
- changeValueByOne(true);
+ changeCurrentByOne(true);
} else {
- changeValueByOne(false);
+ changeCurrentByOne(false);
}
}
};
@@ -611,31 +610,23 @@ public class NumberPicker extends LinearLayout {
hideSoftInput();
mInputText.clearFocus();
if (v.getId() == R.id.increment) {
- postChangeCurrentByOneFromLongPress(true, 0);
+ postChangeCurrentByOneFromLongPress(true);
} else {
- postChangeCurrentByOneFromLongPress(false, 0);
+ postChangeCurrentByOneFromLongPress(false);
}
return true;
}
};
// increment button
- if (!mHasSelectorWheel) {
- mIncrementButton = (ImageButton) findViewById(R.id.increment);
- mIncrementButton.setOnClickListener(onClickListener);
- mIncrementButton.setOnLongClickListener(onLongClickListener);
- } else {
- mIncrementButton = null;
- }
+ mIncrementButton = (ImageButton) findViewById(R.id.increment);
+ mIncrementButton.setOnClickListener(onClickListener);
+ mIncrementButton.setOnLongClickListener(onLongClickListener);
// decrement button
- if (!mHasSelectorWheel) {
- mDecrementButton = (ImageButton) findViewById(R.id.decrement);
- mDecrementButton.setOnClickListener(onClickListener);
- mDecrementButton.setOnLongClickListener(onLongClickListener);
- } else {
- mDecrementButton = null;
- }
+ mDecrementButton = (ImageButton) findViewById(R.id.decrement);
+ mDecrementButton.setOnClickListener(onClickListener);
+ mDecrementButton.setOnLongClickListener(onLongClickListener);
// input text
mInputText = (EditText) findViewById(R.id.numberpicker_input);
@@ -657,6 +648,7 @@ public class NumberPicker extends LinearLayout {
mInputText.setImeOptions(EditorInfo.IME_ACTION_DONE);
// initialize constants
+ mTouchSlop = ViewConfiguration.getTapTimeout();
ViewConfiguration configuration = ViewConfiguration.get(context);
mTouchSlop = configuration.getScaledTouchSlop();
mMinimumFlingVelocity = configuration.getScaledMinimumFlingVelocity();
@@ -675,22 +667,69 @@ public class NumberPicker extends LinearLayout {
paint.setColor(color);
mSelectorWheelPaint = paint;
+ // create the animator for showing the input controls
+ mDimSelectorWheelAnimator = ObjectAnimator.ofInt(this, PROPERTY_SELECTOR_PAINT_ALPHA,
+ SELECTOR_WHEEL_BRIGHT_ALPHA, SELECTOR_WHEEL_DIM_ALPHA);
+ final ObjectAnimator showIncrementButton = ObjectAnimator.ofFloat(mIncrementButton,
+ PROPERTY_BUTTON_ALPHA, BUTTON_ALPHA_TRANSPARENT, BUTTON_ALPHA_OPAQUE);
+ final ObjectAnimator showDecrementButton = ObjectAnimator.ofFloat(mDecrementButton,
+ PROPERTY_BUTTON_ALPHA, BUTTON_ALPHA_TRANSPARENT, BUTTON_ALPHA_OPAQUE);
+ mShowInputControlsAnimator = new AnimatorSet();
+ mShowInputControlsAnimator.playTogether(mDimSelectorWheelAnimator, showIncrementButton,
+ showDecrementButton);
+ mShowInputControlsAnimator.addListener(new AnimatorListenerAdapter() {
+ private boolean mCanceled = false;
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ if (!mCanceled) {
+ // if canceled => we still want the wheel drawn
+ setSelectorWheelState(SELECTOR_WHEEL_STATE_SMALL);
+ }
+ mCanceled = false;
+ }
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ if (mShowInputControlsAnimator.isRunning()) {
+ mCanceled = true;
+ }
+ }
+ });
+
// create the fling and adjust scrollers
mFlingScroller = new Scroller(getContext(), null, true);
mAdjustScroller = new Scroller(getContext(), new DecelerateInterpolator(2.5f));
updateInputTextView();
+ updateIncrementAndDecrementButtonsVisibilityState();
+
+ if (mFlingable) {
+ if (isInEditMode()) {
+ setSelectorWheelState(SELECTOR_WHEEL_STATE_SMALL);
+ } else {
+ // Start with shown selector wheel and hidden controls. When made
+ // visible hide the selector and fade-in the controls to suggest
+ // fling interaction.
+ setSelectorWheelState(SELECTOR_WHEEL_STATE_LARGE);
+ hideInputControls();
+ }
+ }
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
- if (!mHasSelectorWheel) {
- super.onLayout(changed, left, top, right, bottom);
- return;
- }
final int msrdWdth = getMeasuredWidth();
final int msrdHght = getMeasuredHeight();
+ // Increment button at the top.
+ final int inctBtnMsrdWdth = mIncrementButton.getMeasuredWidth();
+ final int incrBtnLeft = (msrdWdth - inctBtnMsrdWdth) / 2;
+ final int incrBtnTop = 0;
+ final int incrBtnRight = incrBtnLeft + inctBtnMsrdWdth;
+ final int incrBtnBottom = incrBtnTop + mIncrementButton.getMeasuredHeight();
+ mIncrementButton.layout(incrBtnLeft, incrBtnTop, incrBtnRight, incrBtnBottom);
+
// Input text centered horizontally.
final int inptTxtMsrdWdth = mInputText.getMeasuredWidth();
final int inptTxtMsrdHght = mInputText.getMeasuredHeight();
@@ -700,23 +739,24 @@ public class NumberPicker extends LinearLayout {
final int inptTxtBottom = inptTxtTop + inptTxtMsrdHght;
mInputText.layout(inptTxtLeft, inptTxtTop, inptTxtRight, inptTxtBottom);
- if (changed) {
+ // Decrement button at the top.
+ final int decrBtnMsrdWdth = mIncrementButton.getMeasuredWidth();
+ final int decrBtnLeft = (msrdWdth - decrBtnMsrdWdth) / 2;
+ final int decrBtnTop = msrdHght - mDecrementButton.getMeasuredHeight();
+ final int decrBtnRight = decrBtnLeft + decrBtnMsrdWdth;
+ final int decrBtnBottom = msrdHght;
+ mDecrementButton.layout(decrBtnLeft, decrBtnTop, decrBtnRight, decrBtnBottom);
+
+ if (!mScrollWheelAndFadingEdgesInitialized) {
+ mScrollWheelAndFadingEdgesInitialized = true;
// need to do all this when we know our size
initializeSelectorWheel();
initializeFadingEdges();
- mTopSelectionDividerTop = (getHeight() - mSelectionDividersDistance) / 2
- - mSelectionDividerHeight;
- mBottomSelectionDividerBottom = mTopSelectionDividerTop + 2 * mSelectionDividerHeight
- + mSelectionDividersDistance;
}
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- if (!mHasSelectorWheel) {
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
- return;
- }
// Try greedily to fit the max width and height.
final int newWidthMeasureSpec = makeMeasureSpec(widthMeasureSpec, mMaxWidth);
final int newHeightMeasureSpec = makeMeasureSpec(heightMeasureSpec, mMaxHeight);
@@ -729,143 +769,120 @@ public class NumberPicker extends LinearLayout {
setMeasuredDimension(widthSize, heightSize);
}
- /**
- * Move to the final position of a scroller. Ensures to force finish the scroller
- * and if it is not at its final position a scroll of the selector wheel is
- * performed to fast forward to the final position.
- *
- * @param scroller The scroller to whose final position to get.
- * @return True of the a move was performed, i.e. the scroller was not in final position.
- */
- private boolean moveToFinalScrollerPosition(Scroller scroller) {
- scroller.forceFinished(true);
- int amountToScroll = scroller.getFinalY() - scroller.getCurrY();
- int futureScrollOffset = (mCurrentScrollOffset + amountToScroll) % mSelectorElementHeight;
- int overshootAdjustment = mInitialScrollOffset - futureScrollOffset;
- if (overshootAdjustment != 0) {
- if (Math.abs(overshootAdjustment) > mSelectorElementHeight / 2) {
- if (overshootAdjustment > 0) {
- overshootAdjustment -= mSelectorElementHeight;
- } else {
- overshootAdjustment += mSelectorElementHeight;
- }
- }
- amountToScroll += overshootAdjustment;
- scrollBy(0, amountToScroll);
- return true;
- }
- return false;
- }
-
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
- if (!mHasSelectorWheel || !isEnabled()) {
+ if (!isEnabled() || !mFlingable) {
return false;
}
- final int action = event.getActionMasked();
- switch (action) {
- case MotionEvent.ACTION_DOWN: {
+ switch (event.getActionMasked()) {
+ case MotionEvent.ACTION_DOWN:
+ mLastMotionEventY = mLastDownEventY = event.getY();
removeAllCallbacks();
- mInputText.setVisibility(View.INVISIBLE);
- mLastDownOrMoveEventY = mLastDownEventY = event.getY();
- mLastDownEventTime = event.getEventTime();
- mIngonreMoveEvents = false;
- mShowSoftInputOnTap = false;
- if (!mFlingScroller.isFinished()) {
- mFlingScroller.forceFinished(true);
- mAdjustScroller.forceFinished(true);
- onScrollStateChange(OnScrollListener.SCROLL_STATE_IDLE);
- } else if (!mAdjustScroller.isFinished()) {
- mFlingScroller.forceFinished(true);
- mAdjustScroller.forceFinished(true);
- } else if (mLastDownEventY < mTopSelectionDividerTop) {
- hideSoftInput();
- postChangeCurrentByOneFromLongPress(
- false, ViewConfiguration.getLongPressTimeout());
- } else if (mLastDownEventY > mBottomSelectionDividerBottom) {
+ mShowInputControlsAnimator.cancel();
+ mDimSelectorWheelAnimator.cancel();
+ mCheckBeginEditOnUpEvent = false;
+ mAdjustScrollerOnUpEvent = true;
+ if (mSelectorWheelState == SELECTOR_WHEEL_STATE_LARGE) {
+ mSelectorWheelPaint.setAlpha(SELECTOR_WHEEL_BRIGHT_ALPHA);
+ boolean scrollersFinished = mFlingScroller.isFinished()
+ && mAdjustScroller.isFinished();
+ if (!scrollersFinished) {
+ mFlingScroller.forceFinished(true);
+ mAdjustScroller.forceFinished(true);
+ onScrollStateChange(OnScrollListener.SCROLL_STATE_IDLE);
+ }
+ mCheckBeginEditOnUpEvent = scrollersFinished;
+ mAdjustScrollerOnUpEvent = true;
hideSoftInput();
- postChangeCurrentByOneFromLongPress(
- true, ViewConfiguration.getLongPressTimeout());
- } else {
- mShowSoftInputOnTap = true;
- postBeginSoftInputOnLongPressCommand();
+ hideInputControls();
+ return true;
}
+ if (isEventInVisibleViewHitRect(event, mIncrementButton)
+ || isEventInVisibleViewHitRect(event, mDecrementButton)) {
+ return false;
+ }
+ mAdjustScrollerOnUpEvent = false;
+ setSelectorWheelState(SELECTOR_WHEEL_STATE_LARGE);
+ hideSoftInput();
+ hideInputControls();
return true;
- }
+ case MotionEvent.ACTION_MOVE:
+ float currentMoveY = event.getY();
+ int deltaDownY = (int) Math.abs(currentMoveY - mLastDownEventY);
+ if (deltaDownY > mTouchSlop) {
+ mCheckBeginEditOnUpEvent = false;
+ onScrollStateChange(OnScrollListener.SCROLL_STATE_TOUCH_SCROLL);
+ setSelectorWheelState(SELECTOR_WHEEL_STATE_LARGE);
+ hideSoftInput();
+ hideInputControls();
+ return true;
+ }
+ break;
}
return false;
}
@Override
- public boolean onTouchEvent(MotionEvent event) {
- if (!isEnabled() || !mHasSelectorWheel) {
+ public boolean onTouchEvent(MotionEvent ev) {
+ if (!isEnabled()) {
return false;
}
if (mVelocityTracker == null) {
mVelocityTracker = VelocityTracker.obtain();
}
- mVelocityTracker.addMovement(event);
- int action = event.getActionMasked();
+ mVelocityTracker.addMovement(ev);
+ int action = ev.getActionMasked();
switch (action) {
- case MotionEvent.ACTION_MOVE: {
- if (mIngonreMoveEvents) {
- break;
- }
- float currentMoveY = event.getY();
- if (mScrollState != OnScrollListener.SCROLL_STATE_TOUCH_SCROLL) {
+ case MotionEvent.ACTION_MOVE:
+ float currentMoveY = ev.getY();
+ if (mCheckBeginEditOnUpEvent
+ || mScrollState != OnScrollListener.SCROLL_STATE_TOUCH_SCROLL) {
int deltaDownY = (int) Math.abs(currentMoveY - mLastDownEventY);
if (deltaDownY > mTouchSlop) {
- removeAllCallbacks();
+ mCheckBeginEditOnUpEvent = false;
onScrollStateChange(OnScrollListener.SCROLL_STATE_TOUCH_SCROLL);
}
- } else {
- int deltaMoveY = (int) ((currentMoveY - mLastDownOrMoveEventY)
- / TOUCH_SCROLL_DECELERATION_COEFFICIENT);
- scrollBy(0, deltaMoveY);
- invalidate();
}
- mLastDownOrMoveEventY = currentMoveY;
- } break;
- case MotionEvent.ACTION_UP: {
- removeBeginSoftInputCommand();
- removeChangeCurrentByOneFromLongPress();
+ int deltaMoveY = (int) (currentMoveY - mLastMotionEventY);
+ scrollBy(0, deltaMoveY);
+ invalidate();
+ mLastMotionEventY = currentMoveY;
+ break;
+ case MotionEvent.ACTION_UP:
+ if (mCheckBeginEditOnUpEvent) {
+ mCheckBeginEditOnUpEvent = false;
+ final long deltaTapTimeMillis = ev.getEventTime() - mLastUpEventTimeMillis;
+ if (deltaTapTimeMillis < ViewConfiguration.getDoubleTapTimeout()) {
+ setSelectorWheelState(SELECTOR_WHEEL_STATE_SMALL);
+ showInputControls(mShowInputControlsAnimimationDuration);
+ mInputText.requestFocus();
+ InputMethodManager inputMethodManager = InputMethodManager.peekInstance();
+ if (inputMethodManager != null) {
+ inputMethodManager.showSoftInput(mInputText, 0);
+ }
+ mLastUpEventTimeMillis = ev.getEventTime();
+ return true;
+ }
+ }
VelocityTracker velocityTracker = mVelocityTracker;
velocityTracker.computeCurrentVelocity(1000, mMaximumFlingVelocity);
int initialVelocity = (int) velocityTracker.getYVelocity();
if (Math.abs(initialVelocity) > mMinimumFlingVelocity) {
- int deltaMove = (int) (event.getY() - mLastDownEventY);
- int absDeltaMoveY = Math.abs(deltaMove);
- if (absDeltaMoveY > mMinFlingDistance) {
- fling(initialVelocity);
- } else {
- changeValueByOne(deltaMove < 0);
- }
+ fling(initialVelocity);
onScrollStateChange(OnScrollListener.SCROLL_STATE_FLING);
} else {
- int eventY = (int) event.getY();
- int deltaMoveY = (int) Math.abs(eventY - mLastDownEventY);
- long deltaTime = event.getEventTime() - mLastDownEventTime;
- if (deltaMoveY <= mTouchSlop && deltaTime < ViewConfiguration.getTapTimeout()) {
- if (mShowSoftInputOnTap) {
- mShowSoftInputOnTap = false;
- showSoftInput();
- } else {
- int selectorIndexOffset = (eventY / mSelectorElementHeight)
- - SELECTOR_MIDDLE_ITEM_INDEX;
- if (selectorIndexOffset > 0) {
- changeValueByOne(true);
- } else if (selectorIndexOffset < 0) {
- changeValueByOne(false);
- }
+ if (mAdjustScrollerOnUpEvent) {
+ if (mFlingScroller.isFinished() && mAdjustScroller.isFinished()) {
+ postAdjustScrollerCommand(0);
}
} else {
- ensureScrollWheelAdjusted();
+ postAdjustScrollerCommand(SHOW_INPUT_CONTROLS_DELAY_MILLIS);
}
- onScrollStateChange(OnScrollListener.SCROLL_STATE_IDLE);
}
mVelocityTracker.recycle();
mVelocityTracker = null;
- } break;
+ mLastUpEventTimeMillis = ev.getEventTime();
+ break;
}
return true;
}
@@ -874,6 +891,12 @@ public class NumberPicker extends LinearLayout {
public boolean dispatchTouchEvent(MotionEvent event) {
final int action = event.getActionMasked();
switch (action) {
+ case MotionEvent.ACTION_MOVE:
+ if (mSelectorWheelState == SELECTOR_WHEEL_STATE_LARGE) {
+ removeAllCallbacks();
+ forceCompleteChangeCurrentByOneViaScroll();
+ }
+ break;
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
removeAllCallbacks();
@@ -884,75 +907,27 @@ public class NumberPicker extends LinearLayout {
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
- final int keyCode = event.getKeyCode();
- switch (keyCode) {
- case KeyEvent.KEYCODE_DPAD_CENTER:
- case KeyEvent.KEYCODE_ENTER:
- removeAllCallbacks();
- break;
+ int keyCode = event.getKeyCode();
+ if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER || keyCode == KeyEvent.KEYCODE_ENTER) {
+ removeAllCallbacks();
}
return super.dispatchKeyEvent(event);
}
@Override
public boolean dispatchTrackballEvent(MotionEvent event) {
- final int action = event.getActionMasked();
- switch (action) {
- case MotionEvent.ACTION_CANCEL:
- case MotionEvent.ACTION_UP:
- removeAllCallbacks();
- break;
+ int action = event.getActionMasked();
+ if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) {
+ removeAllCallbacks();
}
return super.dispatchTrackballEvent(event);
}
@Override
- protected boolean dispatchHoverEvent(MotionEvent event) {
- if (!mHasSelectorWheel) {
- return super.dispatchHoverEvent(event);
- }
- if (AccessibilityManager.getInstance(mContext).isEnabled()) {
- final int eventY = (int) event.getY();
- final int hoveredVirtualViewId;
- if (eventY < mTopSelectionDividerTop) {
- hoveredVirtualViewId = AccessibilityNodeProviderImpl.VIRTUAL_VIEW_ID_DECREMENT;
- } else if (eventY > mBottomSelectionDividerBottom) {
- hoveredVirtualViewId = AccessibilityNodeProviderImpl.VIRTUAL_VIEW_ID_INCREMENT;
- } else {
- hoveredVirtualViewId = AccessibilityNodeProviderImpl.VIRTUAL_VIEW_ID_INPUT;
- }
- final int action = event.getActionMasked();
- AccessibilityNodeProviderImpl provider =
- (AccessibilityNodeProviderImpl) getAccessibilityNodeProvider();
- switch (action) {
- case MotionEvent.ACTION_HOVER_ENTER: {
- provider.sendAccessibilityEventForVirtualView(hoveredVirtualViewId,
- AccessibilityEvent.TYPE_VIEW_HOVER_ENTER);
- mLastHoveredChildVirtualViewId = hoveredVirtualViewId;
- } break;
- case MotionEvent.ACTION_HOVER_MOVE: {
- if (mLastHoveredChildVirtualViewId != hoveredVirtualViewId
- && mLastHoveredChildVirtualViewId != View.NO_ID) {
- provider.sendAccessibilityEventForVirtualView(
- mLastHoveredChildVirtualViewId,
- AccessibilityEvent.TYPE_VIEW_HOVER_EXIT);
- provider.sendAccessibilityEventForVirtualView(hoveredVirtualViewId,
- AccessibilityEvent.TYPE_VIEW_HOVER_ENTER);
- mLastHoveredChildVirtualViewId = hoveredVirtualViewId;
- }
- } break;
- case MotionEvent.ACTION_HOVER_EXIT: {
- provider.sendAccessibilityEventForVirtualView(hoveredVirtualViewId,
- AccessibilityEvent.TYPE_VIEW_HOVER_EXIT);
- mLastHoveredChildVirtualViewId = View.NO_ID;
- } break;
- }
- }
- return false;
- }
-
- @Override
public void computeScroll() {
+ if (mSelectorWheelState == SELECTOR_WHEEL_STATE_NONE) {
+ return;
+ }
Scroller scroller = mFlingScroller;
if (scroller.isFinished()) {
scroller = mAdjustScroller;
@@ -977,17 +952,16 @@ public class NumberPicker extends LinearLayout {
@Override
public void setEnabled(boolean enabled) {
super.setEnabled(enabled);
- if (!mHasSelectorWheel) {
- mIncrementButton.setEnabled(enabled);
- }
- if (!mHasSelectorWheel) {
- mDecrementButton.setEnabled(enabled);
- }
+ mIncrementButton.setEnabled(enabled);
+ mDecrementButton.setEnabled(enabled);
mInputText.setEnabled(enabled);
}
@Override
public void scrollBy(int x, int y) {
+ if (mSelectorWheelState == SELECTOR_WHEEL_STATE_NONE) {
+ return;
+ }
int[] selectorIndices = mSelectorIndices;
if (!mWrapSelectorWheel && y > 0
&& selectorIndices[SELECTOR_MIDDLE_ITEM_INDEX] <= mMinValue) {
@@ -1003,7 +977,7 @@ public class NumberPicker extends LinearLayout {
while (mCurrentScrollOffset - mInitialScrollOffset > mSelectorTextGapHeight) {
mCurrentScrollOffset -= mSelectorElementHeight;
decrementSelectorIndices(selectorIndices);
- setValueInternal(selectorIndices[SELECTOR_MIDDLE_ITEM_INDEX], true);
+ changeCurrent(selectorIndices[SELECTOR_MIDDLE_ITEM_INDEX]);
if (!mWrapSelectorWheel && selectorIndices[SELECTOR_MIDDLE_ITEM_INDEX] <= mMinValue) {
mCurrentScrollOffset = mInitialScrollOffset;
}
@@ -1011,7 +985,7 @@ public class NumberPicker extends LinearLayout {
while (mCurrentScrollOffset - mInitialScrollOffset < -mSelectorTextGapHeight) {
mCurrentScrollOffset += mSelectorElementHeight;
incrementSelectorIndices(selectorIndices);
- setValueInternal(selectorIndices[SELECTOR_MIDDLE_ITEM_INDEX], true);
+ changeCurrent(selectorIndices[SELECTOR_MIDDLE_ITEM_INDEX]);
if (!mWrapSelectorWheel && selectorIndices[SELECTOR_MIDDLE_ITEM_INDEX] >= mMaxValue) {
mCurrentScrollOffset = mInitialScrollOffset;
}
@@ -1050,7 +1024,8 @@ public class NumberPicker extends LinearLayout {
*
* @param formatter The formatter object. If formatter is <code>null</code>,
* {@link String#valueOf(int)} will be used.
- *@see #setDisplayedValues(String[])
+ *
+ * @see #setDisplayedValues(String[])
*/
public void setFormatter(Formatter formatter) {
if (formatter == mFormatter) {
@@ -1093,35 +1068,26 @@ public class NumberPicker extends LinearLayout {
if (mValue == value) {
return;
}
- setValueInternal(value, false);
+ if (value < mMinValue) {
+ value = mWrapSelectorWheel ? mMaxValue : mMinValue;
+ }
+ if (value > mMaxValue) {
+ value = mWrapSelectorWheel ? mMinValue : mMaxValue;
+ }
+ mValue = value;
initializeSelectorWheelIndices();
+ updateInputTextView();
+ updateIncrementAndDecrementButtonsVisibilityState();
invalidate();
}
/**
- * Shows the soft input for its input text.
- */
- private void showSoftInput() {
- InputMethodManager inputMethodManager = InputMethodManager.peekInstance();
- if (inputMethodManager != null) {
- if (mHasSelectorWheel) {
- mInputText.setVisibility(View.VISIBLE);
- }
- mInputText.requestFocus();
- inputMethodManager.showSoftInput(mInputText, 0);
- }
- }
-
- /**
- * Hides the soft input if it is active for the input text.
+ * Hides the soft input of it is active for the input text.
*/
private void hideSoftInput() {
InputMethodManager inputMethodManager = InputMethodManager.peekInstance();
if (inputMethodManager != null && inputMethodManager.isActive(mInputText)) {
inputMethodManager.hideSoftInputFromWindow(getWindowToken(), 0);
- if (mHasSelectorWheel) {
- mInputText.setVisibility(View.INVISIBLE);
- }
}
}
@@ -1185,23 +1151,23 @@ public class NumberPicker extends LinearLayout {
* wrap around the {@link NumberPicker#getMinValue()} and
* {@link NumberPicker#getMaxValue()} values.
* <p>
- * By default if the range (max - min) is more than {@link #SELECTOR_WHEEL_ITEM_COUNT}
- * (the number of items shown on the selector wheel) the selector wheel
- * wrapping is enabled.
+ * By default if the range (max - min) is more than five (the number of
+ * items shown on the selector wheel) the selector wheel wrapping is
+ * enabled.
* </p>
* <p>
- * <strong>Note:</strong> If the number of items, i.e. the range (
- * {@link #getMaxValue()} - {@link #getMinValue()}) is less than
- * {@link #SELECTOR_WHEEL_ITEM_COUNT}, the selector wheel will not wrap.
- * Hence, in such a case calling this method is a NOP.
+ * <strong>Note:</strong> If the number of items, i.e. the range
+ * ({@link #getMaxValue()} - {@link #getMinValue()}) is less than
+ * {@link #SELECTOR_WHEEL_ITEM_COUNT}, the selector wheel will not
+ * wrap. Hence, in such a case calling this method is a NOP.
* </p>
- *
* @param wrapSelectorWheel Whether to wrap.
*/
public void setWrapSelectorWheel(boolean wrapSelectorWheel) {
final boolean wrappingAllowed = (mMaxValue - mMinValue) >= mSelectorIndices.length;
if ((!wrapSelectorWheel || wrappingAllowed) && wrapSelectorWheel != mWrapSelectorWheel) {
mWrapSelectorWheel = wrapSelectorWheel;
+ updateIncrementAndDecrementButtonsVisibilityState();
}
}
@@ -1258,7 +1224,6 @@ public class NumberPicker extends LinearLayout {
initializeSelectorWheelIndices();
updateInputTextView();
tryComputeMaxWidth();
- invalidate();
}
/**
@@ -1291,7 +1256,6 @@ public class NumberPicker extends LinearLayout {
initializeSelectorWheelIndices();
updateInputTextView();
tryComputeMaxWidth();
- invalidate();
}
/**
@@ -1336,49 +1300,102 @@ public class NumberPicker extends LinearLayout {
}
@Override
+ protected void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ // make sure we show the controls only the very
+ // first time the user sees this widget
+ if (mFlingable && !isInEditMode()) {
+ // animate a bit slower the very first time
+ showInputControls(mShowInputControlsAnimimationDuration * 2);
+ }
+ }
+
+ @Override
protected void onDetachedFromWindow() {
removeAllCallbacks();
}
@Override
+ protected void dispatchDraw(Canvas canvas) {
+ // There is a good reason for doing this. See comments in draw().
+ }
+
+ @Override
+ public void draw(Canvas canvas) {
+ // Dispatch draw to our children only if we are not currently running
+ // the animation for simultaneously dimming the scroll wheel and
+ // showing in the buttons. This class takes advantage of the View
+ // implementation of fading edges effect to draw the selector wheel.
+ // However, in View.draw(), the fading is applied after all the children
+ // have been drawn and we do not want this fading to be applied to the
+ // buttons. Therefore, we draw our children after we have completed
+ // drawing ourselves.
+ super.draw(canvas);
+
+ // Draw our children if we are not showing the selector wheel of fading
+ // it out
+ if (mShowInputControlsAnimator.isRunning()
+ || mSelectorWheelState != SELECTOR_WHEEL_STATE_LARGE) {
+ long drawTime = getDrawingTime();
+ for (int i = 0, count = getChildCount(); i < count; i++) {
+ View child = getChildAt(i);
+ if (!child.isShown()) {
+ continue;
+ }
+ drawChild(canvas, getChildAt(i), drawTime);
+ }
+ }
+ }
+
+ @Override
protected void onDraw(Canvas canvas) {
- if (!mHasSelectorWheel) {
- super.onDraw(canvas);
+ if (mSelectorWheelState == SELECTOR_WHEEL_STATE_NONE) {
return;
}
+
float x = (mRight - mLeft) / 2;
float y = mCurrentScrollOffset;
+ final int restoreCount = canvas.save();
+
+ if (mSelectorWheelState == SELECTOR_WHEEL_STATE_SMALL) {
+ Rect clipBounds = canvas.getClipBounds();
+ clipBounds.inset(0, mSelectorElementHeight);
+ canvas.clipRect(clipBounds);
+ }
+
// draw the selector wheel
int[] selectorIndices = mSelectorIndices;
for (int i = 0; i < selectorIndices.length; i++) {
int selectorIndex = selectorIndices[i];
String scrollSelectorValue = mSelectorIndexToStringCache.get(selectorIndex);
- // Do not draw the middle item if input is visible since the input
- // is shown only if the wheel is static and it covers the middle
- // item. Otherwise, if the user starts editing the text via the
- // IME he may see a dimmed version of the old value intermixed
- // with the new one.
+ // Do not draw the middle item if input is visible since the input is shown only
+ // if the wheel is static and it covers the middle item. Otherwise, if the user
+ // starts editing the text via the IME he may see a dimmed version of the old
+ // value intermixed with the new one.
if (i != SELECTOR_MIDDLE_ITEM_INDEX || mInputText.getVisibility() != VISIBLE) {
canvas.drawText(scrollSelectorValue, x, y, mSelectorWheelPaint);
}
y += mSelectorElementHeight;
}
- // draw the selection dividers
+ // draw the selection dividers (only if scrolling and drawable specified)
if (mSelectionDivider != null) {
// draw the top divider
- int topOfTopDivider = mTopSelectionDividerTop;
+ int topOfTopDivider =
+ (getHeight() - mSelectorElementHeight - mSelectionDividerHeight) / 2;
int bottomOfTopDivider = topOfTopDivider + mSelectionDividerHeight;
mSelectionDivider.setBounds(0, topOfTopDivider, mRight, bottomOfTopDivider);
mSelectionDivider.draw(canvas);
// draw the bottom divider
- int bottomOfBottomDivider = mBottomSelectionDividerBottom;
- int topOfBottomDivider = bottomOfBottomDivider - mSelectionDividerHeight;
+ int topOfBottomDivider = topOfTopDivider + mSelectorElementHeight;
+ int bottomOfBottomDivider = bottomOfTopDivider + mSelectorElementHeight;
mSelectionDivider.setBounds(0, topOfBottomDivider, mRight, bottomOfBottomDivider);
mSelectionDivider.draw(canvas);
}
+
+ canvas.restoreToCount(restoreCount);
}
@Override
@@ -1391,20 +1408,12 @@ public class NumberPicker extends LinearLayout {
public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
super.onInitializeAccessibilityEvent(event);
event.setClassName(NumberPicker.class.getName());
- event.setScrollable(true);
- event.setScrollY((mMinValue + mValue) * mSelectorElementHeight);
- event.setMaxScrollY((mMaxValue - mMinValue) * mSelectorElementHeight);
}
@Override
- public AccessibilityNodeProvider getAccessibilityNodeProvider() {
- if (!mHasSelectorWheel) {
- return super.getAccessibilityNodeProvider();
- }
- if (mAccessibilityNodeProvider == null) {
- mAccessibilityNodeProvider = new AccessibilityNodeProviderImpl();
- }
- return mAccessibilityNodeProvider;
+ public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
+ super.onInitializeAccessibilityNodeInfo(info);
+ info.setClassName(NumberPicker.class.getName());
}
/**
@@ -1433,17 +1442,17 @@ public class NumberPicker extends LinearLayout {
}
/**
- * Utility to reconcile a desired size and state, with constraints imposed
- * by a MeasureSpec. Tries to respect the min size, unless a different size
- * is imposed by the constraints.
+ * Utility to reconcile a desired size and state, with constraints imposed by
+ * a MeasureSpec. Tries to respect the min size, unless a different size is
+ * imposed by the constraints.
*
* @param minSize The minimal desired size.
* @param measuredSize The currently measured size.
* @param measureSpec The current measure spec.
* @return The resolved size and state.
*/
- private int resolveSizeAndStateRespectingMinSize(
- int minSize, int measuredSize, int measureSpec) {
+ private int resolveSizeAndStateRespectingMinSize(int minSize, int measuredSize,
+ int measureSpec) {
if (minSize != SIZE_UNSPECIFIED) {
final int desiredWidth = Math.max(minSize, measuredSize);
return resolveSizeAndState(desiredWidth, measureSpec, 0);
@@ -1453,8 +1462,8 @@ public class NumberPicker extends LinearLayout {
}
/**
- * Resets the selector indices and clear the cached string representation of
- * these indices.
+ * Resets the selector indices and clear the cached
+ * string representation of these indices.
*/
private void initializeSelectorWheelIndices() {
mSelectorIndexToStringCache.clear();
@@ -1471,44 +1480,39 @@ public class NumberPicker extends LinearLayout {
}
/**
- * Sets the current value of this NumberPicker.
+ * Sets the current value of this NumberPicker, and sets mPrevious to the
+ * previous value. If current is greater than mEnd less than mStart, the
+ * value of mCurrent is wrapped around. Subclasses can override this to
+ * change the wrapping behavior
*
- * @param current The new value of the NumberPicker.
- * @param notifyChange Whether to notify if the current value changed.
+ * @param current the new value of the NumberPicker
*/
- private void setValueInternal(int current, boolean notifyChange) {
+ private void changeCurrent(int current) {
if (mValue == current) {
return;
}
// Wrap around the values if we go past the start or end
if (mWrapSelectorWheel) {
current = getWrappedSelectorIndex(current);
- } else {
- current = Math.max(current, mMinValue);
- current = Math.min(current, mMaxValue);
}
int previous = mValue;
- mValue = current;
- updateInputTextView();
- if (notifyChange) {
- notifyChange(previous, current);
- }
+ setValue(current);
+ notifyChange(previous, current);
}
/**
* Changes the current value by one which is increment or
* decrement based on the passes argument.
- * decrement the current value.
*
* @param increment True to increment, false to decrement.
*/
- private void changeValueByOne(boolean increment) {
- if (mHasSelectorWheel) {
+ private void changeCurrentByOne(boolean increment) {
+ if (mFlingable) {
+ mDimSelectorWheelAnimator.cancel();
mInputText.setVisibility(View.INVISIBLE);
- if (!moveToFinalScrollerPosition(mFlingScroller)) {
- moveToFinalScrollerPosition(mAdjustScroller);
- }
+ mSelectorWheelPaint.setAlpha(SELECTOR_WHEEL_BRIGHT_ALPHA);
mPreviousScrollerY = 0;
+ forceCompleteChangeCurrentByOneViaScroll();
if (increment) {
mFlingScroller.startScroll(0, 0, 0, -mSelectorElementHeight,
CHANGE_CURRENT_BY_ONE_SCROLL_DURATION);
@@ -1519,26 +1523,81 @@ public class NumberPicker extends LinearLayout {
invalidate();
} else {
if (increment) {
- setValueInternal(mValue + 1, true);
+ changeCurrent(mValue + 1);
} else {
- setValueInternal(mValue - 1, true);
+ changeCurrent(mValue - 1);
}
}
}
+ /**
+ * Ensures that if we are in the process of changing the current value
+ * by one via scrolling the scroller gets to its final state and the
+ * value is updated.
+ */
+ private void forceCompleteChangeCurrentByOneViaScroll() {
+ Scroller scroller = mFlingScroller;
+ if (!scroller.isFinished()) {
+ final int yBeforeAbort = scroller.getCurrY();
+ scroller.abortAnimation();
+ final int yDelta = scroller.getCurrY() - yBeforeAbort;
+ scrollBy(0, yDelta);
+ }
+ }
+
+ /**
+ * Sets the <code>alpha</code> of the {@link Paint} for drawing the selector
+ * wheel.
+ */
+ @SuppressWarnings("unused")
+ // Called via reflection
+ private void setSelectorPaintAlpha(int alpha) {
+ mSelectorWheelPaint.setAlpha(alpha);
+ invalidate();
+ }
+
+ /**
+ * @return If the <code>event</code> is in the visible <code>view</code>.
+ */
+ private boolean isEventInVisibleViewHitRect(MotionEvent event, View view) {
+ if (view.getVisibility() == VISIBLE) {
+ view.getHitRect(mTempRect);
+ return mTempRect.contains((int) event.getX(), (int) event.getY());
+ }
+ return false;
+ }
+
+ /**
+ * Sets the <code>selectorWheelState</code>.
+ */
+ private void setSelectorWheelState(int selectorWheelState) {
+ mSelectorWheelState = selectorWheelState;
+ if (selectorWheelState == SELECTOR_WHEEL_STATE_LARGE) {
+ mSelectorWheelPaint.setAlpha(SELECTOR_WHEEL_BRIGHT_ALPHA);
+ }
+
+ if (mFlingable && selectorWheelState == SELECTOR_WHEEL_STATE_LARGE
+ && AccessibilityManager.getInstance(mContext).isEnabled()) {
+ AccessibilityManager.getInstance(mContext).interrupt();
+ String text = mContext.getString(R.string.number_picker_increment_scroll_action);
+ mInputText.setContentDescription(text);
+ mInputText.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED);
+ mInputText.setContentDescription(null);
+ }
+ }
+
private void initializeSelectorWheel() {
initializeSelectorWheelIndices();
int[] selectorIndices = mSelectorIndices;
int totalTextHeight = selectorIndices.length * mTextSize;
float totalTextGapHeight = (mBottom - mTop) - totalTextHeight;
- float textGapCount = selectorIndices.length;
+ float textGapCount = selectorIndices.length - 1;
mSelectorTextGapHeight = (int) (totalTextGapHeight / textGapCount + 0.5f);
mSelectorElementHeight = mTextSize + mSelectorTextGapHeight;
- // Ensure that the middle item is positioned the same as the text in
- // mInputText
+ // Ensure that the middle item is positioned the same as the text in mInputText
int editTextTextPosition = mInputText.getBaseline() + mInputText.getTop();
- mInitialScrollOffset = editTextTextPosition
- - (mSelectorElementHeight * SELECTOR_MIDDLE_ITEM_INDEX);
+ mInitialScrollOffset = editTextTextPosition -
+ (mSelectorElementHeight * SELECTOR_MIDDLE_ITEM_INDEX);
mCurrentScrollOffset = mInitialScrollOffset;
updateInputTextView();
}
@@ -1553,14 +1612,16 @@ public class NumberPicker extends LinearLayout {
*/
private void onScrollerFinished(Scroller scroller) {
if (scroller == mFlingScroller) {
- if (!ensureScrollWheelAdjusted()) {
+ if (mSelectorWheelState == SELECTOR_WHEEL_STATE_LARGE) {
+ postAdjustScrollerCommand(0);
+ onScrollStateChange(OnScrollListener.SCROLL_STATE_IDLE);
+ } else {
updateInputTextView();
+ fadeSelectorWheel(mShowInputControlsAnimimationDuration);
}
- onScrollStateChange(OnScrollListener.SCROLL_STATE_IDLE);
} else {
- if (mScrollState != OnScrollListener.SCROLL_STATE_TOUCH_SCROLL) {
- updateInputTextView();
- }
+ updateInputTextView();
+ showInputControls(mShowInputControlsAnimimationDuration);
}
}
@@ -1593,6 +1654,56 @@ public class NumberPicker extends LinearLayout {
}
/**
+ * Hides the input controls which is the up/down arrows and the text field.
+ */
+ private void hideInputControls() {
+ mShowInputControlsAnimator.cancel();
+ mIncrementButton.setVisibility(INVISIBLE);
+ mDecrementButton.setVisibility(INVISIBLE);
+ mInputText.setVisibility(INVISIBLE);
+ }
+
+ /**
+ * Show the input controls by making them visible and animating the alpha
+ * property up/down arrows.
+ *
+ * @param animationDuration The duration of the animation.
+ */
+ private void showInputControls(long animationDuration) {
+ updateIncrementAndDecrementButtonsVisibilityState();
+ mInputText.setVisibility(VISIBLE);
+ mShowInputControlsAnimator.setDuration(animationDuration);
+ mShowInputControlsAnimator.start();
+ }
+
+ /**
+ * Fade the selector wheel via an animation.
+ *
+ * @param animationDuration The duration of the animation.
+ */
+ private void fadeSelectorWheel(long animationDuration) {
+ mInputText.setVisibility(VISIBLE);
+ mDimSelectorWheelAnimator.setDuration(animationDuration);
+ mDimSelectorWheelAnimator.start();
+ }
+
+ /**
+ * Updates the visibility state of the increment and decrement buttons.
+ */
+ private void updateIncrementAndDecrementButtonsVisibilityState() {
+ if (mWrapSelectorWheel || mValue < mMaxValue) {
+ mIncrementButton.setVisibility(VISIBLE);
+ } else {
+ mIncrementButton.setVisibility(INVISIBLE);
+ }
+ if (mWrapSelectorWheel || mValue > mMinValue) {
+ mDecrementButton.setVisibility(VISIBLE);
+ } else {
+ mDecrementButton.setVisibility(INVISIBLE);
+ }
+ }
+
+ /**
* @return The wrapped index <code>selectorIndex</code> value.
*/
private int getWrappedSelectorIndex(int selectorIndex) {
@@ -1638,7 +1749,8 @@ public class NumberPicker extends LinearLayout {
/**
* Ensures we have a cached string representation of the given <code>
- * selectorIndex</code> to avoid multiple instantiations of the same string.
+ * selectorIndex</code>
+ * to avoid multiple instantiations of the same string.
*/
private void ensureCachedScrollSelectorValue(int selectorIndex) {
SparseArray<String> cache = mSelectorIndexToStringCache;
@@ -1671,7 +1783,7 @@ public class NumberPicker extends LinearLayout {
} else {
// Check the new value and ensure it's in range
int current = getSelectedPos(str.toString());
- setValueInternal(current, true);
+ changeCurrent(current);
}
}
@@ -1680,23 +1792,25 @@ public class NumberPicker extends LinearLayout {
* the string corresponding to the index specified by the current value will
* be returned. Otherwise, the formatter specified in {@link #setFormatter}
* will be used to format the number.
- *
- * @return Whether the text was updated.
*/
- private boolean updateInputTextView() {
+ private void updateInputTextView() {
/*
* If we don't have displayed values then use the current number else
* find the correct value in the displayed values for the current
* number.
*/
- String text = (mDisplayedValues == null) ? formatNumber(mValue)
- : mDisplayedValues[mValue - mMinValue];
- if (!TextUtils.isEmpty(text) && !text.equals(mInputText.getText().toString())) {
- mInputText.setText(text);
- return true;
+ if (mDisplayedValues == null) {
+ mInputText.setText(formatNumber(mValue));
+ } else {
+ mInputText.setText(mDisplayedValues[mValue - mMinValue]);
}
+ mInputText.setSelection(mInputText.getText().length());
- return false;
+ if (mFlingable && AccessibilityManager.getInstance(mContext).isEnabled()) {
+ String text = mContext.getString(R.string.number_picker_increment_scroll_mode,
+ mInputText.getText());
+ mInputText.setContentDescription(text);
+ }
}
/**
@@ -1714,45 +1828,14 @@ public class NumberPicker extends LinearLayout {
*
* @param increment Whether to increment or decrement the value.
*/
- private void postChangeCurrentByOneFromLongPress(boolean increment, long delayMillis) {
+ private void postChangeCurrentByOneFromLongPress(boolean increment) {
+ mInputText.clearFocus();
+ removeAllCallbacks();
if (mChangeCurrentByOneFromLongPressCommand == null) {
mChangeCurrentByOneFromLongPressCommand = new ChangeCurrentByOneFromLongPressCommand();
- } else {
- removeCallbacks(mChangeCurrentByOneFromLongPressCommand);
- }
- mChangeCurrentByOneFromLongPressCommand.setStep(increment);
- postDelayed(mChangeCurrentByOneFromLongPressCommand, delayMillis);
- }
-
- /**
- * Removes the command for changing the current value by one.
- */
- private void removeChangeCurrentByOneFromLongPress() {
- if (mChangeCurrentByOneFromLongPressCommand != null) {
- removeCallbacks(mChangeCurrentByOneFromLongPressCommand);
- }
- }
-
- /**
- * Posts a command for beginning an edit of the current value via IME on
- * long press.
- */
- private void postBeginSoftInputOnLongPressCommand() {
- if (mBeginSoftInputOnLongPressCommand == null) {
- mBeginSoftInputOnLongPressCommand = new BeginSoftInputOnLongPressCommand();
- } else {
- removeCallbacks(mBeginSoftInputOnLongPressCommand);
- }
- postDelayed(mBeginSoftInputOnLongPressCommand, ViewConfiguration.getLongPressTimeout());
- }
-
- /**
- * Removes the command for beginning an edit of the current value via IME.
- */
- private void removeBeginSoftInputCommand() {
- if (mBeginSoftInputOnLongPressCommand != null) {
- removeCallbacks(mBeginSoftInputOnLongPressCommand);
}
+ mChangeCurrentByOneFromLongPressCommand.setIncrement(increment);
+ post(mChangeCurrentByOneFromLongPressCommand);
}
/**
@@ -1762,12 +1845,12 @@ public class NumberPicker extends LinearLayout {
if (mChangeCurrentByOneFromLongPressCommand != null) {
removeCallbacks(mChangeCurrentByOneFromLongPressCommand);
}
+ if (mAdjustScrollerCommand != null) {
+ removeCallbacks(mAdjustScrollerCommand);
+ }
if (mSetSelectionCommand != null) {
removeCallbacks(mSetSelectionCommand);
}
- if (mBeginSoftInputOnLongPressCommand != null) {
- removeCallbacks(mBeginSoftInputOnLongPressCommand);
- }
}
/**
@@ -1805,7 +1888,8 @@ public class NumberPicker extends LinearLayout {
/**
* Posts an {@link SetSelectionCommand} from the given <code>selectionStart
- * </code> to <code>selectionEnd</code>.
+ * </code> to
+ * <code>selectionEnd</code>.
*/
private void postSetSelectionCommand(int selectionStart, int selectionEnd) {
if (mSetSelectionCommand == null) {
@@ -1819,6 +1903,20 @@ public class NumberPicker extends LinearLayout {
}
/**
+ * Posts an {@link AdjustScrollerCommand} within the given <code>
+ * delayMillis</code>
+ * .
+ */
+ private void postAdjustScrollerCommand(int delayMillis) {
+ if (mAdjustScrollerCommand == null) {
+ mAdjustScrollerCommand = new AdjustScrollerCommand();
+ } else {
+ removeCallbacks(mAdjustScrollerCommand);
+ }
+ postDelayed(mAdjustScrollerCommand, delayMillis);
+ }
+
+ /**
* Filter for accepting only valid indices or prefixes of the string
* representation of valid indices.
*/
@@ -1836,8 +1934,8 @@ public class NumberPicker extends LinearLayout {
}
@Override
- public CharSequence filter(
- CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
+ public CharSequence filter(CharSequence source, int start, int end, Spanned dest,
+ int dstart, int dend) {
if (mDisplayedValues == null) {
CharSequence filtered = super.filter(source, start, end, dest, dstart, dend);
if (filtered == null) {
@@ -1883,27 +1981,6 @@ public class NumberPicker extends LinearLayout {
}
/**
- * Ensures that the scroll wheel is adjusted i.e. there is no offset and the
- * middle element is in the middle of the widget.
- *
- * @return Whether an adjustment has been made.
- */
- private boolean ensureScrollWheelAdjusted() {
- // adjust to the closest value
- int deltaY = mInitialScrollOffset - mCurrentScrollOffset;
- if (deltaY != 0) {
- mPreviousScrollerY = 0;
- if (Math.abs(deltaY) > mSelectorElementHeight / 2) {
- deltaY += (deltaY > 0) ? -mSelectorElementHeight : mSelectorElementHeight;
- }
- mAdjustScroller.startScroll(0, 0, 0, deltaY, SELECTOR_ADJUSTMENT_DURATION_MILLIS);
- invalidate();
- return true;
- }
- return false;
- }
-
- /**
* Command for setting the input text selection.
*/
class SetSelectionCommand implements Runnable {
@@ -1917,18 +1994,39 @@ public class NumberPicker extends LinearLayout {
}
/**
+ * Command for adjusting the scroller to show in its center the closest of
+ * the displayed items.
+ */
+ class AdjustScrollerCommand implements Runnable {
+ public void run() {
+ mPreviousScrollerY = 0;
+ if (mInitialScrollOffset == mCurrentScrollOffset) {
+ updateInputTextView();
+ showInputControls(mShowInputControlsAnimimationDuration);
+ return;
+ }
+ // adjust to the closest value
+ int deltaY = mInitialScrollOffset - mCurrentScrollOffset;
+ if (Math.abs(deltaY) > mSelectorElementHeight / 2) {
+ deltaY += (deltaY > 0) ? -mSelectorElementHeight : mSelectorElementHeight;
+ }
+ mAdjustScroller.startScroll(0, 0, 0, deltaY, SELECTOR_ADJUSTMENT_DURATION_MILLIS);
+ invalidate();
+ }
+ }
+
+ /**
* Command for changing the current value from a long press by one.
*/
class ChangeCurrentByOneFromLongPressCommand implements Runnable {
private boolean mIncrement;
- private void setStep(boolean increment) {
+ private void setIncrement(boolean increment) {
mIncrement = increment;
}
- @Override
public void run() {
- changeValueByOne(mIncrement);
+ changeCurrentByOne(mIncrement);
postDelayed(this, mLongPressUpdateInterval);
}
}
@@ -1950,248 +2048,4 @@ public class NumberPicker extends LinearLayout {
}
}
}
-
- /**
- * Command for beginning soft input on long press.
- */
- class BeginSoftInputOnLongPressCommand implements Runnable {
-
- @Override
- public void run() {
- showSoftInput();
- mIngonreMoveEvents = true;
- }
- }
-
- class AccessibilityNodeProviderImpl extends AccessibilityNodeProvider {
- private static final int VIRTUAL_VIEW_ID_INCREMENT = 1;
-
- private static final int VIRTUAL_VIEW_ID_INPUT = 2;
-
- private static final int VIRTUAL_VIEW_ID_DECREMENT = 3;
-
- private final Rect mTempRect = new Rect();
-
- private final int[] mTempArray = new int[2];
-
- @Override
- public AccessibilityNodeInfo createAccessibilityNodeInfo(int virtualViewId) {
- switch (virtualViewId) {
- case View.NO_ID:
- return createAccessibilityNodeInfoForNumberPicker( mScrollX, mScrollY,
- mScrollX + (mRight - mLeft), mScrollY + (mBottom - mTop));
- case VIRTUAL_VIEW_ID_DECREMENT:
- return createAccessibilityNodeInfoForVirtualButton(VIRTUAL_VIEW_ID_DECREMENT,
- getVirtualDecrementButtonText(), mScrollX, mScrollY,
- mScrollX + (mRight - mLeft),
- mTopSelectionDividerTop + mSelectionDividerHeight);
- case VIRTUAL_VIEW_ID_INPUT:
- return createAccessibiltyNodeInfoForInputText();
- case VIRTUAL_VIEW_ID_INCREMENT:
- return createAccessibilityNodeInfoForVirtualButton(VIRTUAL_VIEW_ID_INCREMENT,
- getVirtualIncrementButtonText(), mScrollX,
- mBottomSelectionDividerBottom - mSelectionDividerHeight,
- mScrollX + (mRight - mLeft), mScrollY + (mBottom - mTop));
- }
- return super.createAccessibilityNodeInfo(virtualViewId);
- }
-
- @Override
- public List<AccessibilityNodeInfo> findAccessibilityNodeInfosByText(String searched,
- int virtualViewId) {
- if (TextUtils.isEmpty(searched)) {
- return Collections.emptyList();
- }
- String searchedLowerCase = searched.toLowerCase();
- List<AccessibilityNodeInfo> result = new ArrayList<AccessibilityNodeInfo>();
- switch (virtualViewId) {
- case View.NO_ID: {
- findAccessibilityNodeInfosByTextInChild(searchedLowerCase,
- VIRTUAL_VIEW_ID_DECREMENT, result);
- findAccessibilityNodeInfosByTextInChild(searchedLowerCase,
- VIRTUAL_VIEW_ID_INPUT, result);
- findAccessibilityNodeInfosByTextInChild(searchedLowerCase,
- VIRTUAL_VIEW_ID_INCREMENT, result);
- return result;
- }
- case VIRTUAL_VIEW_ID_DECREMENT:
- case VIRTUAL_VIEW_ID_INCREMENT:
- case VIRTUAL_VIEW_ID_INPUT: {
- findAccessibilityNodeInfosByTextInChild(searchedLowerCase, virtualViewId,
- result);
- return result;
- }
- }
- return super.findAccessibilityNodeInfosByText(searched, virtualViewId);
- }
-
- @Override
- public boolean performAccessibilityAction(int action, int virtualViewId) {
- switch (virtualViewId) {
- case VIRTUAL_VIEW_ID_INPUT: {
- switch (action) {
- case AccessibilityNodeInfo.ACTION_FOCUS: {
- if (!mInputText.isFocused()) {
- return mInputText.requestFocus();
- }
- } break;
- case AccessibilityNodeInfo.ACTION_CLEAR_FOCUS: {
- if (mInputText.isFocused()) {
- mInputText.clearFocus();
- return true;
- }
- } break;
- }
- } break;
- }
- return super.performAccessibilityAction(action, virtualViewId);
- }
-
- public void sendAccessibilityEventForVirtualView(int virtualViewId, int eventType) {
- switch (virtualViewId) {
- case VIRTUAL_VIEW_ID_DECREMENT: {
- sendAccessibilityEventForVirtualButton(virtualViewId, eventType,
- getVirtualDecrementButtonText());
- } break;
- case VIRTUAL_VIEW_ID_INPUT: {
- sendAccessibilityEventForVirtualText(eventType);
- } break;
- case VIRTUAL_VIEW_ID_INCREMENT: {
- sendAccessibilityEventForVirtualButton(virtualViewId, eventType,
- getVirtualIncrementButtonText());
- } break;
- }
- }
-
- private void sendAccessibilityEventForVirtualText(int eventType) {
- AccessibilityEvent event = AccessibilityEvent.obtain(eventType);
- mInputText.onInitializeAccessibilityEvent(event);
- mInputText.onPopulateAccessibilityEvent(event);
- event.setSource(NumberPicker.this, VIRTUAL_VIEW_ID_INPUT);
- requestSendAccessibilityEvent(NumberPicker.this, event);
- }
-
- private void sendAccessibilityEventForVirtualButton(int virtualViewId, int eventType,
- String text) {
- AccessibilityEvent event = AccessibilityEvent.obtain(eventType);
- event.setClassName(Button.class.getName());
- event.setPackageName(mContext.getPackageName());
- event.getText().add(text);
- event.setEnabled(NumberPicker.this.isEnabled());
- event.setSource(NumberPicker.this, virtualViewId);
- requestSendAccessibilityEvent(NumberPicker.this, event);
- }
-
- private void findAccessibilityNodeInfosByTextInChild(String searchedLowerCase,
- int virtualViewId, List<AccessibilityNodeInfo> outResult) {
- switch (virtualViewId) {
- case VIRTUAL_VIEW_ID_DECREMENT: {
- String text = getVirtualDecrementButtonText();
- if (!TextUtils.isEmpty(text)
- && text.toString().toLowerCase().contains(searchedLowerCase)) {
- outResult.add(createAccessibilityNodeInfo(VIRTUAL_VIEW_ID_DECREMENT));
- }
- } return;
- case VIRTUAL_VIEW_ID_INPUT: {
- CharSequence text = mInputText.getText();
- if (!TextUtils.isEmpty(text) &&
- text.toString().toLowerCase().contains(searchedLowerCase)) {
- outResult.add(createAccessibilityNodeInfo(VIRTUAL_VIEW_ID_INPUT));
- return;
- }
- CharSequence contentDesc = mInputText.getText();
- if (!TextUtils.isEmpty(contentDesc) &&
- contentDesc.toString().toLowerCase().contains(searchedLowerCase)) {
- outResult.add(createAccessibilityNodeInfo(VIRTUAL_VIEW_ID_INPUT));
- return;
- }
- } break;
- case VIRTUAL_VIEW_ID_INCREMENT: {
- String text = getVirtualIncrementButtonText();
- if (!TextUtils.isEmpty(text)
- && text.toString().toLowerCase().contains(searchedLowerCase)) {
- outResult.add(createAccessibilityNodeInfo(VIRTUAL_VIEW_ID_INCREMENT));
- }
- } return;
- }
- }
-
- private AccessibilityNodeInfo createAccessibiltyNodeInfoForInputText() {
- AccessibilityNodeInfo info = mInputText.createAccessibilityNodeInfo();
- info.setLongClickable(true);
- info.setSource(NumberPicker.this, VIRTUAL_VIEW_ID_INPUT);
- return info;
- }
-
- private AccessibilityNodeInfo createAccessibilityNodeInfoForVirtualButton(int virtualViewId,
- String text, int left, int top, int right, int bottom) {
- AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain();
- info.setClassName(Button.class.getName());
- info.setPackageName(mContext.getPackageName());
- info.setSource(NumberPicker.this, virtualViewId);
- info.setParent(NumberPicker.this);
- info.addChild(NumberPicker.this, VIRTUAL_VIEW_ID_DECREMENT);
- info.addChild(NumberPicker.this, VIRTUAL_VIEW_ID_INPUT);
- info.addChild(NumberPicker.this, VIRTUAL_VIEW_ID_INCREMENT);
- info.setText(text);
- info.setClickable(true);
- info.setLongClickable(true);
- info.setEnabled(NumberPicker.this.isEnabled());
- Rect boundsInParent = mTempRect;
- boundsInParent.set(left, top, right, bottom);
- info.setBoundsInParent(boundsInParent);
- Rect boundsInScreen = boundsInParent;
- int[] locationOnScreen = mTempArray;
- getLocationOnScreen(locationOnScreen);
- boundsInScreen.offsetTo(0, 0);
- boundsInScreen.offset(locationOnScreen[0], locationOnScreen[1]);
- info.setBoundsInScreen(boundsInScreen);
- return info;
- }
-
- private AccessibilityNodeInfo createAccessibilityNodeInfoForNumberPicker(int left, int top,
- int right, int bottom) {
- AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain();
- info.setClassName(Button.class.getName());
- info.setPackageName(mContext.getPackageName());
- info.setSource(NumberPicker.this);
- info.setParent((View) getParent());
- info.setEnabled(NumberPicker.this.isEnabled());
- info.setScrollable(true);
- Rect boundsInParent = mTempRect;
- boundsInParent.set(left, top, right, bottom);
- info.setBoundsInParent(boundsInParent);
- Rect boundsInScreen = boundsInParent;
- int[] locationOnScreen = mTempArray;
- getLocationOnScreen(locationOnScreen);
- boundsInScreen.offsetTo(0, 0);
- boundsInScreen.offset(locationOnScreen[0], locationOnScreen[1]);
- info.setBoundsInScreen(boundsInScreen);
- return info;
- }
-
- private String getVirtualDecrementButtonText() {
- int value = mValue - 1;
- if (mWrapSelectorWheel) {
- value = getWrappedSelectorIndex(value);
- }
- if (value >= mMinValue) {
- return (mDisplayedValues == null) ? formatNumber(value)
- : mDisplayedValues[value - mMinValue];
- }
- return null;
- }
-
- private String getVirtualIncrementButtonText() {
- int value = mValue + 1;
- if (mWrapSelectorWheel) {
- value = getWrappedSelectorIndex(value);
- }
- if (value <= mMaxValue) {
- return (mDisplayedValues == null) ? formatNumber(value)
- : mDisplayedValues[value - mMinValue];
- }
- return null;
- }
- }
}
diff --git a/core/java/android/widget/TimePicker.java b/core/java/android/widget/TimePicker.java
index bc88b62..7eff1aa 100644
--- a/core/java/android/widget/TimePicker.java
+++ b/core/java/android/widget/TimePicker.java
@@ -532,28 +532,21 @@ public class TimePicker extends FrameLayout {
private void setContentDescriptions() {
// Minute
- trySetContentDescription(mMinuteSpinner, R.id.increment,
- R.string.time_picker_increment_minute_button);
- trySetContentDescription(mMinuteSpinner, R.id.decrement,
- R.string.time_picker_decrement_minute_button);
+ String text = mContext.getString(R.string.time_picker_increment_minute_button);
+ mMinuteSpinner.findViewById(R.id.increment).setContentDescription(text);
+ text = mContext.getString(R.string.time_picker_decrement_minute_button);
+ mMinuteSpinner.findViewById(R.id.decrement).setContentDescription(text);
// Hour
- trySetContentDescription(mHourSpinner, R.id.increment,
- R.string.time_picker_increment_hour_button);
- trySetContentDescription(mHourSpinner, R.id.decrement,
- R.string.time_picker_decrement_hour_button);
+ text = mContext.getString(R.string.time_picker_increment_hour_button);
+ mHourSpinner.findViewById(R.id.increment).setContentDescription(text);
+ text = mContext.getString(R.string.time_picker_decrement_hour_button);
+ mHourSpinner.findViewById(R.id.decrement).setContentDescription(text);
// AM/PM
if (mAmPmSpinner != null) {
- trySetContentDescription(mAmPmSpinner, R.id.increment,
- R.string.time_picker_increment_set_pm_button);
- trySetContentDescription(mAmPmSpinner, R.id.decrement,
- R.string.time_picker_decrement_set_am_button);
- }
- }
-
- private void trySetContentDescription(View root, int viewId, int contDescResId) {
- View target = root.findViewById(viewId);
- if (target != null) {
- target.setContentDescription(mContext.getString(contDescResId));
+ text = mContext.getString(R.string.time_picker_increment_set_pm_button);
+ mAmPmSpinner.findViewById(R.id.increment).setContentDescription(text);
+ text = mContext.getString(R.string.time_picker_decrement_set_am_button);
+ mAmPmSpinner.findViewById(R.id.decrement).setContentDescription(text);
}
}