From 67945c11a5e9547f71be91ceb99e7b9ff15a6292 Mon Sep 17 00:00:00 2001 From: Alan Viverette Date: Wed, 15 Oct 2014 13:20:47 -0700 Subject: [PATCH] Update AM/PM selectors for clock face TimePicker The selectors are now CheckedTextViews, which makes more sense when using a screen reader. BUG: 17468036 Change-Id: I09c62a08172a710faa8fb7ed2bf99a66331e5701 --- .../android/widget/RadialTimePickerView.java | 281 +++--------------- .../widget/TimePickerClockDelegate.java | 2 +- .../widget/TimePickerSpinnerDelegate.java | 180 ++++++----- core/res/res/layout/time_header_label.xml | 36 ++- core/res/res/values/dimens.xml | 15 +- core/res/res/values/symbols.xml | 4 +- 6 files changed, 185 insertions(+), 333 deletions(-) diff --git a/core/java/android/widget/RadialTimePickerView.java b/core/java/android/widget/RadialTimePickerView.java index 56f126cbe4477..d15f2d6e9e080 100644 --- a/core/java/android/widget/RadialTimePickerView.java +++ b/core/java/android/widget/RadialTimePickerView.java @@ -22,9 +22,7 @@ import android.animation.Keyframe; import android.animation.ObjectAnimator; import android.animation.PropertyValuesHolder; import android.animation.ValueAnimator; -import android.annotation.SuppressLint; import android.content.Context; -import android.content.res.ColorStateList; import android.content.res.Resources; import android.content.res.TypedArray; import android.graphics.Canvas; @@ -47,7 +45,6 @@ import android.view.accessibility.AccessibilityNodeInfo; import com.android.internal.R; -import java.text.DateFormatSymbols; import java.util.ArrayList; import java.util.Calendar; import java.util.Locale; @@ -69,7 +66,6 @@ public class RadialTimePickerView extends View implements View.OnTouchListener { private static final int HOURS = 0; private static final int MINUTES = 1; private static final int HOURS_INNER = 2; - private static final int AMPM = 3; private static final int SELECTOR_CIRCLE = 0; private static final int SELECTOR_DOT = 1; @@ -87,12 +83,6 @@ public class RadialTimePickerView extends View implements View.OnTouchListener { // Alpha level of color for selector. private static final int ALPHA_SELECTOR = 60; // was 51 - // Alpha level of color for selected circle. - private static final int ALPHA_AMPM_SELECTED = ALPHA_SELECTOR; - - // Alpha level of color for pressed circle. - private static final int ALPHA_AMPM_PRESSED = 255; // was 175 - private static final float COSINE_30_DEGREES = ((float) Math.sqrt(3)) * 0.5f; private static final float SINE_30_DEGREES = 0.5f; @@ -105,8 +95,6 @@ public class RadialTimePickerView extends View implements View.OnTouchListener { private static final int CENTER_RADIUS = 2; - private static final int[] STATE_SET_SELECTED = new int[] {R.attr.state_selected}; - private static int[] sSnapPrefer30sMap = new int[361]; private final String[] mHours12Texts = new String[12]; @@ -114,8 +102,6 @@ public class RadialTimePickerView extends View implements View.OnTouchListener { private final String[] mInnerHours24Texts = new String[12]; private final String[] mMinutesTexts = new String[12]; - private final String[] mAmPmText = new String[2]; - private final Paint[] mPaint = new Paint[2]; private final int[] mColor = new int[2]; private final IntHolder[] mAlpha = new IntHolder[2]; @@ -126,11 +112,7 @@ public class RadialTimePickerView extends View implements View.OnTouchListener { private final int[][] mColorSelector = new int[2][3]; private final IntHolder[][] mAlphaSelector = new IntHolder[2][3]; - private final Paint mPaintAmPmText = new Paint(); - private final Paint[] mPaintAmPmCircle = new Paint[2]; - private final Paint mPaintBackground = new Paint(); - private final Paint mPaintDisabled = new Paint(); private final Paint mPaintDebug = new Paint(); private Typeface mTypeface; @@ -184,21 +166,7 @@ public class RadialTimePickerView extends View implements View.OnTouchListener { private float mSelectionRadiusMultiplier; private int[] mSelectionDegrees = new int[3]; - private int mAmPmCircleRadius; - private float mAmPmYCenter; - - private float mAmPmCircleRadiusMultiplier; - private int mAmPmTextColor; - - private float mLeftIndicatorXCenter; - private float mRightIndicatorXCenter; - - private int mAmPmUnselectedColor; - private int mAmPmSelectedColor; - private int mAmOrPm; - private int mAmOrPmPressed; - private int mDisabledAlpha; private RectF mRectF = new RectF(); @@ -331,27 +299,6 @@ public class RadialTimePickerView extends View implements View.OnTouchListener { final TypedArray a = mContext.obtainStyledAttributes(attrs, R.styleable.TimePicker, defStyle, 0); - ColorStateList amPmBackgroundColor = a.getColorStateList( - R.styleable.TimePicker_amPmBackgroundColor); - if (amPmBackgroundColor == null) { - amPmBackgroundColor = res.getColorStateList( - R.color.timepicker_default_ampm_unselected_background_color_material); - } - - // Obtain the backup selected color. If the background color state - // list doesn't have a state for selected, we'll use this color. - final int amPmSelectedColor = a.getColor(R.styleable.TimePicker_amPmSelectedBackgroundColor, - res.getColor(R.color.timepicker_default_ampm_selected_background_color_material)); - amPmBackgroundColor = ColorStateList.addFirstIfMissing( - amPmBackgroundColor, R.attr.state_selected, amPmSelectedColor); - - mAmPmSelectedColor = amPmBackgroundColor.getColorForState( - STATE_SET_SELECTED, amPmSelectedColor); - mAmPmUnselectedColor = amPmBackgroundColor.getDefaultColor(); - - mAmPmTextColor = a.getColor(R.styleable.TimePicker_amPmTextColor, - res.getColor(R.color.timepicker_default_text_color_material)); - mTypeface = Typeface.create("sans-serif", Typeface.NORMAL); // Initialize all alpha values to opaque. @@ -419,16 +366,6 @@ public class RadialTimePickerView extends View implements View.OnTouchListener { R.styleable.TimePicker_numbersSelectorColor, R.color.timepicker_default_selector_color_material); - mPaintAmPmText.setColor(mAmPmTextColor); - mPaintAmPmText.setTypeface(mTypeface); - mPaintAmPmText.setAntiAlias(true); - mPaintAmPmText.setTextAlign(Paint.Align.CENTER); - - mPaintAmPmCircle[AM] = new Paint(); - mPaintAmPmCircle[AM].setAntiAlias(true); - mPaintAmPmCircle[PM] = new Paint(); - mPaintAmPmCircle[PM].setAntiAlias(true); - mPaintBackground.setColor(a.getColor(R.styleable.TimePicker_numbersBackgroundColor, res.getColor(R.color.timepicker_default_numbers_background_color_material))); mPaintBackground.setAntiAlias(true); @@ -444,7 +381,6 @@ public class RadialTimePickerView extends View implements View.OnTouchListener { mShowHours = true; mIs24HourMode = false; mAmOrPm = AM; - mAmOrPmPressed = -1; initHoursAndMinutesText(); initData(); @@ -530,13 +466,7 @@ public class RadialTimePickerView extends View implements View.OnTouchListener { // 0 is 12 AM (midnight) and 12 is 12 PM (noon). mAmOrPm = (hour == 0 || (hour % 24) < 12) ? AM : PM; - - if (mIs24HourMode) { - // Inner circle is 1 through 12. - mIsOnInnerCircle = hour >= 1 && hour <= 12; - } else { - mIsOnInnerCircle = false; - } + mIsOnInnerCircle = mIs24HourMode && hour >= 1 && hour <= 12; initData(); updateLayoutData(); @@ -586,11 +516,6 @@ public class RadialTimePickerView extends View implements View.OnTouchListener { return mAmOrPm; } - public void swapAmPm() { - mAmOrPm = (mAmOrPm == AM) ? PM : AM; - invalidate(); - } - public void showHours(boolean animate) { if (mShowHours) return; mShowHours = true; @@ -621,10 +546,6 @@ public class RadialTimePickerView extends View implements View.OnTouchListener { mInnerHours24Texts[i] = String.format("%d", HOURS_NUMBERS[i]); mMinutesTexts[i] = String.format("%02d", MINUTES_NUMBERS[i]); } - - String[] amPmStrings = TimePickerClockDelegate.getAmPmStrings(mContext); - mAmPmText[AM] = amPmStrings[0]; - mAmPmText[PM] = amPmStrings[1]; } private void initData() { @@ -674,9 +595,6 @@ public class RadialTimePickerView extends View implements View.OnTouchListener { mAnimationRadiusMultiplier[HOURS_INNER] = 1; mAnimationRadiusMultiplier[MINUTES] = 1; - mAmPmCircleRadiusMultiplier = Float.parseFloat( - res.getString(R.string.timepicker_ampm_circle_radius_multiplier)); - mAlpha[HOURS].setValue(mShowHours ? ALPHA_OPAQUE : ALPHA_TRANSPARENT); mAlpha[MINUTES].setValue(mShowHours ? ALPHA_TRANSPARENT : ALPHA_OPAQUE); @@ -710,14 +628,6 @@ public class RadialTimePickerView extends View implements View.OnTouchListener { mCircleRadius[HOURS_INNER] = min * mCircleRadiusMultiplier[HOURS]; mCircleRadius[MINUTES] = min * mCircleRadiusMultiplier[MINUTES]; - if (!mIs24HourMode) { - // We'll need to draw the AM/PM circles, so the main circle will need to have - // a slightly higher center. To keep the entire view centered vertically, we'll - // have to push it up by half the radius of the AM/PM circles. - int amPmCircleRadius = (int) (mCircleRadius[HOURS] * mAmPmCircleRadiusMultiplier); - mYCenter -= amPmCircleRadius / 2; - } - mMinHypotenuseForInnerNumber = (int) (mCircleRadius[HOURS] * mNumbersRadiusMultiplier[HOURS_INNER]) - mSelectionRadius[HOURS]; mMaxHypotenuseForOuterNumber = (int) (mCircleRadius[HOURS] @@ -738,17 +648,6 @@ public class RadialTimePickerView extends View implements View.OnTouchListener { mSelectionRadius[HOURS] = (int) (mCircleRadius[HOURS] * mSelectionRadiusMultiplier); mSelectionRadius[HOURS_INNER] = mSelectionRadius[HOURS]; mSelectionRadius[MINUTES] = (int) (mCircleRadius[MINUTES] * mSelectionRadiusMultiplier); - - mAmPmCircleRadius = (int) (mCircleRadius[HOURS] * mAmPmCircleRadiusMultiplier); - mPaintAmPmText.setTextSize(mAmPmCircleRadius * 3 / 4); - - // Line up the vertical center of the AM/PM circles with the bottom of the main circle. - mAmPmYCenter = mYCenter + mCircleRadius[HOURS]; - - // Line up the horizontal edges of the AM/PM circles with the horizontal edges - // of the main circle - mLeftIndicatorXCenter = mXCenter - mCircleRadius[HOURS] + mAmPmCircleRadius; - mRightIndicatorXCenter = mXCenter + mCircleRadius[HOURS] - mAmPmCircleRadius; } @Override @@ -780,9 +679,6 @@ public class RadialTimePickerView extends View implements View.OnTouchListener { mColor[MINUTES], mAlpha[MINUTES].getValue()); drawCenter(canvas); - if (!mIs24HourMode) { - drawAmPm(canvas); - } if (DEBUG) { drawDebug(canvas); @@ -804,50 +700,6 @@ public class RadialTimePickerView extends View implements View.OnTouchListener { drawSelector(canvas, MINUTES); } - private void drawAmPm(Canvas canvas) { - final boolean isLayoutRtl = isLayoutRtl(); - - int amColor = mAmPmUnselectedColor; - int amAlpha = ALPHA_OPAQUE; - int pmColor = mAmPmUnselectedColor; - int pmAlpha = ALPHA_OPAQUE; - if (mAmOrPm == AM) { - amColor = mAmPmSelectedColor; - amAlpha = ALPHA_AMPM_SELECTED; - } else if (mAmOrPm == PM) { - pmColor = mAmPmSelectedColor; - pmAlpha = ALPHA_AMPM_SELECTED; - } - if (mAmOrPmPressed == AM) { - amColor = mAmPmSelectedColor; - amAlpha = ALPHA_AMPM_PRESSED; - } else if (mAmOrPmPressed == PM) { - pmColor = mAmPmSelectedColor; - pmAlpha = ALPHA_AMPM_PRESSED; - } - - // Draw the two circles - mPaintAmPmCircle[AM].setColor(amColor); - mPaintAmPmCircle[AM].setAlpha(getMultipliedAlpha(amColor, amAlpha)); - canvas.drawCircle(isLayoutRtl ? mRightIndicatorXCenter : mLeftIndicatorXCenter, - mAmPmYCenter, mAmPmCircleRadius, mPaintAmPmCircle[AM]); - - mPaintAmPmCircle[PM].setColor(pmColor); - mPaintAmPmCircle[PM].setAlpha(getMultipliedAlpha(pmColor, pmAlpha)); - canvas.drawCircle(isLayoutRtl ? mLeftIndicatorXCenter : mRightIndicatorXCenter, - mAmPmYCenter, mAmPmCircleRadius, mPaintAmPmCircle[PM]); - - // Draw the AM/PM texts on top - mPaintAmPmText.setColor(mAmPmTextColor); - float textYCenter = mAmPmYCenter - - (int) (mPaintAmPmText.descent() + mPaintAmPmText.ascent()) / 2; - - canvas.drawText(isLayoutRtl ? mAmPmText[PM] : mAmPmText[AM], mLeftIndicatorXCenter, - textYCenter, mPaintAmPmText); - canvas.drawText(isLayoutRtl ? mAmPmText[AM] : mAmPmText[PM], mRightIndicatorXCenter, - textYCenter, mPaintAmPmText); - } - private int getMultipliedAlpha(int argb, int alpha) { return (int) (Color.alpha(argb) * (alpha / 255.0) + 0.5); } @@ -950,7 +802,7 @@ public class RadialTimePickerView extends View implements View.OnTouchListener { float x = mXCenter - width / 2; float y = mYCenter + 1.5f * height; - canvas.drawText(selected.toString(), x, y, paint); + canvas.drawText(selected, x, y, paint); } private void calculateGridSizesHours() { @@ -1259,26 +1111,6 @@ public class RadialTimePickerView extends View implements View.OnTouchListener { return (int) degrees; } - private int getIsTouchingAmOrPm(float x, float y) { - final boolean isLayoutRtl = isLayoutRtl(); - int squaredYDistance = (int) ((y - mAmPmYCenter) * (y - mAmPmYCenter)); - - int distanceToAmCenter = (int) Math.sqrt( - (x - mLeftIndicatorXCenter) * (x - mLeftIndicatorXCenter) + squaredYDistance); - if (distanceToAmCenter <= mAmPmCircleRadius) { - return (isLayoutRtl ? PM : AM); - } - - int distanceToPmCenter = (int) Math.sqrt( - (x - mRightIndicatorXCenter) * (x - mRightIndicatorXCenter) + squaredYDistance); - if (distanceToPmCenter <= mAmPmCircleRadius) { - return (isLayoutRtl ? AM : PM); - } - - // Neither was close enough. - return -1; - } - @Override public boolean onTouch(View v, MotionEvent event) { if(!mInputEnabled) { @@ -1295,75 +1127,53 @@ public class RadialTimePickerView extends View implements View.OnTouchListener { switch(event.getAction()) { case MotionEvent.ACTION_DOWN: case MotionEvent.ACTION_MOVE: - mAmOrPmPressed = getIsTouchingAmOrPm(eventX, eventY); - if (mAmOrPmPressed != -1) { - result = true; - } else { - degrees = getDegreesFromXY(eventX, eventY); - if (degrees != -1) { - snapDegrees = (mShowHours ? - snapOnly30s(degrees, 0) : snapPrefer30s(degrees)) % 360; - if (mShowHours) { - mSelectionDegrees[HOURS] = snapDegrees; - mSelectionDegrees[HOURS_INNER] = snapDegrees; - } else { - mSelectionDegrees[MINUTES] = snapDegrees; - } - performHapticFeedback(HapticFeedbackConstants.CLOCK_TICK); - if (mListener != null) { - if (mShowHours) { - mListener.onValueSelected(HOURS, getCurrentHour(), false); - } else { - mListener.onValueSelected(MINUTES, getCurrentMinute(), false); - } - } - result = true; + degrees = getDegreesFromXY(eventX, eventY); + if (degrees != -1) { + snapDegrees = (mShowHours ? + snapOnly30s(degrees, 0) : snapPrefer30s(degrees)) % 360; + if (mShowHours) { + mSelectionDegrees[HOURS] = snapDegrees; + mSelectionDegrees[HOURS_INNER] = snapDegrees; + } else { + mSelectionDegrees[MINUTES] = snapDegrees; } - } - invalidate(); - return result; - - case MotionEvent.ACTION_UP: - mAmOrPmPressed = getIsTouchingAmOrPm(eventX, eventY); - if (mAmOrPmPressed != -1) { - if (mAmOrPm != mAmOrPmPressed) { - swapAmPm(); - } - mAmOrPmPressed = -1; + performHapticFeedback(HapticFeedbackConstants.CLOCK_TICK); if (mListener != null) { - mListener.onValueSelected(AMPM, getCurrentHour(), true); + if (mShowHours) { + mListener.onValueSelected(HOURS, getCurrentHour(), false); + } else { + mListener.onValueSelected(MINUTES, getCurrentMinute(), false); + } } result = true; - } else { - degrees = getDegreesFromXY(eventX, eventY); - if (degrees != -1) { - snapDegrees = (mShowHours ? - snapOnly30s(degrees, 0) : snapPrefer30s(degrees)) % 360; - if (mShowHours) { - mSelectionDegrees[HOURS] = snapDegrees; - mSelectionDegrees[HOURS_INNER] = snapDegrees; - } else { - mSelectionDegrees[MINUTES] = snapDegrees; - } - if (mListener != null) { - if (mShowHours) { - mListener.onValueSelected(HOURS, getCurrentHour(), true); - } else { - mListener.onValueSelected(MINUTES, getCurrentMinute(), true); - } - } - result = true; - } - } - if (result) { invalidate(); } - return result; + break; - default: + case MotionEvent.ACTION_UP: + degrees = getDegreesFromXY(eventX, eventY); + if (degrees != -1) { + snapDegrees = (mShowHours ? + snapOnly30s(degrees, 0) : snapPrefer30s(degrees)) % 360; + if (mShowHours) { + mSelectionDegrees[HOURS] = snapDegrees; + mSelectionDegrees[HOURS_INNER] = snapDegrees; + } else { + mSelectionDegrees[MINUTES] = snapDegrees; + } + if (mListener != null) { + if (mShowHours) { + mListener.onValueSelected(HOURS, getCurrentHour(), true); + } else { + mListener.onValueSelected(MINUTES, getCurrentMinute(), true); + } + } + invalidate(); + result = true; + } break; } - return false; + return result; } /** @@ -1373,8 +1183,8 @@ public class RadialTimePickerView extends View implements View.OnTouchListener { @Override public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { super.onInitializeAccessibilityNodeInfo(info); - info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD); - info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD); + info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_FORWARD); + info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_BACKWARD); } /** @@ -1404,7 +1214,6 @@ public class RadialTimePickerView extends View implements View.OnTouchListener { * When scroll forward/backward events are received, jump the time to the higher/lower * discrete, visible value on the circle. */ - @SuppressLint("NewApi") @Override public boolean performAccessibilityAction(int action, Bundle arguments) { if (super.performAccessibilityAction(action, arguments)) { @@ -1418,8 +1227,8 @@ public class RadialTimePickerView extends View implements View.OnTouchListener { changeMultiplier = -1; } if (changeMultiplier != 0) { - int value = 0; - int stepSize = 0; + int value; + final int stepSize; if (mShowHours) { stepSize = DEGREES_FOR_ONE_HOUR; value = getCurrentHour() % 12; @@ -1431,7 +1240,7 @@ public class RadialTimePickerView extends View implements View.OnTouchListener { int degrees = value * stepSize; degrees = snapOnly30s(degrees, changeMultiplier); value = degrees / stepSize; - int maxValue = 0; + final int maxValue; int minValue = 0; if (mShowHours) { if (mIs24HourMode) { diff --git a/core/java/android/widget/TimePickerClockDelegate.java b/core/java/android/widget/TimePickerClockDelegate.java index 8917f39e78173..6dfea9256bf14 100644 --- a/core/java/android/widget/TimePickerClockDelegate.java +++ b/core/java/android/widget/TimePickerClockDelegate.java @@ -43,7 +43,7 @@ import static android.view.View.IMPORTANT_FOR_ACCESSIBILITY_AUTO; import static android.view.View.IMPORTANT_FOR_ACCESSIBILITY_YES; /** - * A delegate implementing the basic TimePicker + * A delegate implementing the basic spinner-based TimePicker. */ class TimePickerClockDelegate extends TimePicker.AbstractTimePickerDelegate { private static final boolean DEFAULT_ENABLED_STATE = true; diff --git a/core/java/android/widget/TimePickerSpinnerDelegate.java b/core/java/android/widget/TimePickerSpinnerDelegate.java index 73e05e8d49329..e4342b1e00e84 100644 --- a/core/java/android/widget/TimePickerSpinnerDelegate.java +++ b/core/java/android/widget/TimePickerSpinnerDelegate.java @@ -28,6 +28,7 @@ import android.text.format.DateFormat; import android.text.format.DateUtils; import android.util.AttributeSet; import android.util.Log; +import android.util.TypedValue; import android.view.HapticFeedbackConstants; import android.view.KeyCharacterMap; import android.view.KeyEvent; @@ -44,7 +45,7 @@ import java.util.Calendar; import java.util.Locale; /** - * A view for selecting the time of day, in either 24 hour or AM/PM mode. + * A delegate implementing the radial clock-based TimePicker. */ class TimePickerSpinnerDelegate extends TimePicker.AbstractTimePickerDelegate implements RadialTimePickerView.OnValueSelectedListener { @@ -61,23 +62,27 @@ class TimePickerSpinnerDelegate extends TimePicker.AbstractTimePickerDelegate im // Also NOT a real index, just used for keyboard mode. private static final int ENABLE_PICKER_INDEX = 3; - private static final int AM = 0; - private static final int PM = 1; + static final int AM = 0; + static final int PM = 1; private static final boolean DEFAULT_ENABLED_STATE = true; private boolean mIsEnabled = DEFAULT_ENABLED_STATE; private static final int HOURS_IN_HALF_DAY = 12; - private View mHeaderView; - private TextView mHourView; - private TextView mMinuteView; - private TextView mAmPmTextView; - private RadialTimePickerView mRadialTimePickerView; - private TextView mSeparatorView; + private final View mHeaderView; + private final TextView mHourView; + private final TextView mMinuteView; + private final View mAmPmLayout; + private final CheckedTextView mAmLabel; + private final CheckedTextView mPmLabel; + private final RadialTimePickerView mRadialTimePickerView; + private final TextView mSeparatorView; - private String mAmText; - private String mPmText; + private final String mAmText; + private final String mPmText; + + private final float mDisabledAlpha; private boolean mAllowAutoAdvance; private int mInitialHourOfDay; @@ -124,15 +129,18 @@ class TimePickerSpinnerDelegate extends TimePicker.AbstractTimePickerDelegate im final int layoutResourceId = a.getResourceId(R.styleable.TimePicker_internalLayout, R.layout.time_picker_holo); - final View mainView = inflater.inflate(layoutResourceId, null); - mDelegator.addView(mainView); + final View mainView = inflater.inflate(layoutResourceId, delegator); - mHourView = (TextView) mainView.findViewById(R.id.hours); - mSeparatorView = (TextView) mainView.findViewById(R.id.separator); - mMinuteView = (TextView) mainView.findViewById(R.id.minutes); - mAmPmTextView = (TextView) mainView.findViewById(R.id.ampm_label); + mHeaderView = mainView.findViewById(R.id.time_header); + mHeaderView.setBackground(a.getDrawable(R.styleable.TimePicker_headerBackground)); + + // Set up hour/minute labels. + mHourView = (TextView) mHeaderView.findViewById(R.id.hours); + mHourView.setOnClickListener(mClickListener); + mSeparatorView = (TextView) mHeaderView.findViewById(R.id.separator); + mMinuteView = (TextView) mHeaderView.findViewById(R.id.minutes); + mMinuteView.setOnClickListener(mClickListener); - // Set up text appearances from style. final int headerTimeTextAppearance = a.getResourceId( R.styleable.TimePicker_headerTimeTextAppearance, 0); if (headerTimeTextAppearance != 0) { @@ -141,6 +149,7 @@ class TimePickerSpinnerDelegate extends TimePicker.AbstractTimePickerDelegate im mMinuteView.setTextAppearance(context, headerTimeTextAppearance); } + // TODO: This can be removed once we support themed color state lists. final int headerSelectedTextColor = a.getColor( R.styleable.TimePicker_headerSelectedTextColor, res.getColor(R.color.timepicker_default_selector_color_material)); @@ -149,17 +158,29 @@ class TimePickerSpinnerDelegate extends TimePicker.AbstractTimePickerDelegate im mMinuteView.setTextColor(ColorStateList.addFirstIfMissing(mMinuteView.getTextColors(), R.attr.state_selected, headerSelectedTextColor)); + // Set up AM/PM labels. + mAmPmLayout = mHeaderView.findViewById(R.id.ampm_layout); + mAmLabel = (CheckedTextView) mAmPmLayout.findViewById(R.id.am_label); + mAmLabel.setText(amPmStrings[0]); + mAmLabel.setOnClickListener(mClickListener); + mPmLabel = (CheckedTextView) mAmPmLayout.findViewById(R.id.pm_label); + mPmLabel.setText(amPmStrings[1]); + mPmLabel.setOnClickListener(mClickListener); + final int headerAmPmTextAppearance = a.getResourceId( R.styleable.TimePicker_headerAmPmTextAppearance, 0); if (headerAmPmTextAppearance != 0) { - mAmPmTextView.setTextAppearance(context, headerAmPmTextAppearance); + mAmLabel.setTextAppearance(context, headerAmPmTextAppearance); + mPmLabel.setTextAppearance(context, headerAmPmTextAppearance); } - mHeaderView = mainView.findViewById(R.id.time_header); - mHeaderView.setBackground(a.getDrawable(R.styleable.TimePicker_headerBackground)); - a.recycle(); + // Pull disabled alpha from theme. + final TypedValue outValue = new TypedValue(); + context.getTheme().resolveAttribute(android.R.attr.disabledAlpha, outValue, true); + mDisabledAlpha = outValue.getFloat(); + mRadialTimePickerView = (RadialTimePickerView) mainView.findViewById( R.id.radial_picker); @@ -195,21 +216,6 @@ class TimePickerSpinnerDelegate extends TimePicker.AbstractTimePickerDelegate im mHeaderView.setFocusable(true); mRadialTimePickerView.setOnValueSelectedListener(this); - - mHourView.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - setCurrentItemShowing(HOUR_INDEX, true, true); - tryVibrate(); - } - }); - mMinuteView.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - setCurrentItemShowing(MINUTE_INDEX, true, true); - tryVibrate(); - } - }); } private void updateUI(int index) { @@ -250,46 +256,31 @@ class TimePickerSpinnerDelegate extends TimePicker.AbstractTimePickerDelegate im private void updateHeaderAmPm() { if (mIs24HourView) { - mAmPmTextView.setVisibility(View.GONE); + mAmPmLayout.setVisibility(View.GONE); } else { - mAmPmTextView.setVisibility(View.VISIBLE); - final String bestDateTimePattern = DateFormat.getBestDateTimePattern(mCurrentLocale, - "hm"); - + final String bestDateTimePattern = DateFormat.getBestDateTimePattern( + mCurrentLocale, "hm"); boolean amPmOnLeft = bestDateTimePattern.startsWith("a"); if (TextUtils.getLayoutDirectionFromLocale(mCurrentLocale) == View.LAYOUT_DIRECTION_RTL) { amPmOnLeft = !amPmOnLeft; } - RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) - mAmPmTextView.getLayoutParams(); + final ViewGroup.MarginLayoutParams params = + (ViewGroup.MarginLayoutParams) mAmPmLayout.getLayoutParams(); if (amPmOnLeft) { - layoutParams.rightMargin = computeMaxWidthOfNumbers(12 /* for hours */); - layoutParams.removeRule(RelativeLayout.RIGHT_OF); - layoutParams.addRule(RelativeLayout.LEFT_OF, R.id.separator); + params.leftMargin = 0; + params.rightMargin = computeMaxWidthOfNumbers(12 /* for hours */); } else { - layoutParams.leftMargin = computeMaxWidthOfNumbers(60 /* for minutes */); - layoutParams.removeRule(RelativeLayout.LEFT_OF); - layoutParams.addRule(RelativeLayout.RIGHT_OF, R.id.separator); + params.leftMargin = computeMaxWidthOfNumbers(60 /* for minutes */); + params.rightMargin = 0; } - updateAmPmDisplay(mInitialHourOfDay < 12 ? AM : PM); - mAmPmTextView.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - tryVibrate(); - int amOrPm = mRadialTimePickerView.getAmOrPm(); - if (amOrPm == AM) { - amOrPm = PM; - } else if (amOrPm == PM){ - amOrPm = AM; - } - updateAmPmDisplay(amOrPm); - mRadialTimePickerView.setAmOrPm(amOrPm); - } - }); + mAmPmLayout.setLayoutParams(params); + mAmPmLayout.setVisibility(View.VISIBLE); + + updateAmPmLabelStates(mInitialHourOfDay < 12 ? AM : PM); } } @@ -389,7 +380,8 @@ class TimePickerSpinnerDelegate extends TimePicker.AbstractTimePickerDelegate im public void setEnabled(boolean enabled) { mHourView.setEnabled(enabled); mMinuteView.setEnabled(enabled); - mAmPmTextView.setEnabled(enabled); + mAmLabel.setEnabled(enabled); + mPmLabel.setEnabled(enabled); mRadialTimePickerView.setEnabled(enabled); mIsEnabled = enabled; } @@ -596,16 +588,14 @@ class TimePickerSpinnerDelegate extends TimePicker.AbstractTimePickerDelegate im mDelegator.performHapticFeedback(HapticFeedbackConstants.CLOCK_TICK); } - private void updateAmPmDisplay(int amOrPm) { - if (amOrPm == AM) { - mAmPmTextView.setText(mAmText); - mRadialTimePickerView.announceForAccessibility(mAmText); - } else if (amOrPm == PM){ - mAmPmTextView.setText(mPmText); - mRadialTimePickerView.announceForAccessibility(mPmText); - } else { - mAmPmTextView.setText(mDoublePlaceholderText); - } + private void updateAmPmLabelStates(int amOrPm) { + final boolean isAm = amOrPm == AM; + mAmLabel.setChecked(isAm); + mAmLabel.setAlpha(isAm ? 1 : mDisabledAlpha); + + final boolean isPm = amOrPm == PM; + mPmLabel.setChecked(isPm); + mPmLabel.setAlpha(isPm ? 1 : mDisabledAlpha); } /** @@ -629,7 +619,7 @@ class TimePickerSpinnerDelegate extends TimePicker.AbstractTimePickerDelegate im updateHeaderMinute(newValue); mRadialTimePickerView.setContentDescription(mMinutePickerDescription + ": " + newValue); } else if (pickerIndex == AMPM_INDEX) { - updateAmPmDisplay(newValue); + updateAmPmLabelStates(newValue); } else if (pickerIndex == ENABLE_PICKER_INDEX) { if (!isTypedTimeFullyLegal()) { mTypedTimes.clear(); @@ -761,6 +751,11 @@ class TimePickerSpinnerDelegate extends TimePicker.AbstractTimePickerDelegate im mMinuteView.setSelected(index == MINUTE_INDEX); } + private void setAmOrPm(int amOrPm) { + updateAmPmLabelStates(amOrPm); + mRadialTimePickerView.setAmOrPm(amOrPm); + } + /** * For keyboard mode, processes key events. * @@ -929,7 +924,7 @@ class TimePickerSpinnerDelegate extends TimePicker.AbstractTimePickerDelegate im updateHeaderHour(hour, true); updateHeaderMinute(minute); if (!mIs24HourView) { - updateAmPmDisplay(hour < 12 ? AM : PM); + updateAmPmLabelStates(hour < 12 ? AM : PM); } setCurrentItemShowing(mRadialTimePickerView.getCurrentItemShowing(), true, true); onValidationChanged(true); @@ -947,7 +942,7 @@ class TimePickerSpinnerDelegate extends TimePicker.AbstractTimePickerDelegate im mMinuteView.setText(minuteStr); mMinuteView.setSelected(false); if (!mIs24HourView) { - updateAmPmDisplay(values[2]); + updateAmPmLabelStates(values[2]); } } } @@ -1231,6 +1226,33 @@ class TimePickerSpinnerDelegate extends TimePicker.AbstractTimePickerDelegate im } } + private final View.OnClickListener mClickListener = new View.OnClickListener() { + @Override + public void onClick(View v) { + + final int amOrPm; + switch (v.getId()) { + case R.id.am_label: + setAmOrPm(AM); + break; + case R.id.pm_label: + setAmOrPm(PM); + break; + case R.id.hours: + setCurrentItemShowing(HOUR_INDEX, true, true); + break; + case R.id.minutes: + setCurrentItemShowing(MINUTE_INDEX, true, true); + break; + default: + // Failed to handle this click, don't vibrate. + return; + } + + tryVibrate(); + } + }; + private final View.OnKeyListener mKeyListener = new View.OnKeyListener() { @Override public boolean onKey(View v, int keyCode, KeyEvent event) { diff --git a/core/res/res/layout/time_header_label.xml b/core/res/res/layout/time_header_label.xml index 5c970402cc12c..84b2b0cdcb882 100644 --- a/core/res/res/layout/time_header_label.xml +++ b/core/res/res/layout/time_header_label.xml @@ -20,14 +20,13 @@ android:layout_height="match_parent"> + android:layout_height="match_parent"> + android:layout_centerVertical="true" /> - + + android:baselineAlignedChildIndex="1" + android:orientation="vertical"> + + + diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml index 26d313371ae1a..71f66ba7b6af7 100644 --- a/core/res/res/values/dimens.xml +++ b/core/res/res/values/dimens.xml @@ -367,12 +367,15 @@ 60sp -30dp 16sp - 6dip - 4dip - 96dip - 48dip - 24dip - 270dip + 12dp + 16dp + 1dp + 2dp + 4dp + 96dp + 48dp + 24dp + 270dp 12sp diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index d9129fef6dab2..71f06429ab683 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -1936,7 +1936,9 @@ - + + +