/** * Initialize the Layout with starting values. * * @param context * @param initialHoursOfDay * @param initialMinutes * @param is24HourMode */ public void initialize( Context context, int initialHoursOfDay, int initialMinutes, boolean is24HourMode, boolean vibrate) { if (mTimeInitialized) { Log.e(TAG, "Time has already been initialized."); return; } mIs24HourMode = is24HourMode; mHideAmPm = Utils.isTouchExplorationEnabled(mAccessibilityManager) ? true : mIs24HourMode; mVibrate = vibrate; // Initialize the circle and AM/PM circles if applicable. mCircleView.initialize(context, mHideAmPm); mCircleView.invalidate(); if (!mHideAmPm) { mAmPmCirclesView.initialize(context, initialHoursOfDay < 12 ? AM : PM); mAmPmCirclesView.invalidate(); } // Initialize the hours and minutes numbers. Resources res = context.getResources(); int[] hours = {12, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}; int[] hours_24 = {0, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23}; int[] minutes = {0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55}; String[] hoursTexts = new String[12]; String[] innerHoursTexts = new String[12]; String[] minutesTexts = new String[12]; for (int i = 0; i < 12; i++) { hoursTexts[i] = is24HourMode ? String.format("%02d", hours_24[i]) : String.format("%d", hours[i]); innerHoursTexts[i] = String.format("%d", hours[i]); minutesTexts[i] = String.format("%02d", minutes[i]); } mHourRadialTextsView.initialize( res, hoursTexts, (is24HourMode ? innerHoursTexts : null), mHideAmPm, true); mHourRadialTextsView.invalidate(); mMinuteRadialTextsView.initialize(res, minutesTexts, null, mHideAmPm, false); mMinuteRadialTextsView.invalidate(); // Initialize the currently-selected hour and minute. setValueForItem(HOUR_INDEX, initialHoursOfDay); setValueForItem(MINUTE_INDEX, initialMinutes); int hourDegrees = (initialHoursOfDay % 12) * HOUR_VALUE_TO_DEGREES_STEP_SIZE; mHourRadialSelectorView.initialize( context, mHideAmPm, is24HourMode, true, hourDegrees, isHourInnerCircle(initialHoursOfDay)); int minuteDegrees = initialMinutes * MINUTE_VALUE_TO_DEGREES_STEP_SIZE; mMinuteRadialSelectorView.initialize(context, mHideAmPm, false, false, minuteDegrees, false); mTimeInitialized = true; }
/** * Calculate the degrees within the circle that corresponds to the specified coordinates, if the * coordinates are within the range that will trigger a selection. * * @param pointX The x coordinate. * @param pointY The y coordinate. * @param forceLegal Force the selection to be legal, regardless of how far the coordinates are * from the actual numbers. * @param isInnerCircle If the selection may be in the inner circle, pass in a size-1 boolean * array here, inside which the value will be true if the selection is in the inner circle, * and false if in the outer circle. * @return Degrees from 0 to 360, if the selection was within the legal range. -1 if not. */ private int getDegreesFromCoords( float pointX, float pointY, boolean forceLegal, final Boolean[] isInnerCircle) { int currentItem = getCurrentItemShowing(); if (currentItem == HOUR_INDEX) { return mHourRadialSelectorView.getDegreesFromCoords( pointX, pointY, forceLegal, isInnerCircle); } else if (currentItem == MINUTE_INDEX) { return mMinuteRadialSelectorView.getDegreesFromCoords( pointX, pointY, forceLegal, isInnerCircle); } else { return -1; } }
/** Set either the hour or the minute. Will set the internal value, and set the selection. */ private void setItem(int index, int value) { if (index == HOUR_INDEX) { setValueForItem(HOUR_INDEX, value); int hourDegrees = (value % 12) * HOUR_VALUE_TO_DEGREES_STEP_SIZE; mHourRadialSelectorView.setSelection(hourDegrees, isHourInnerCircle(value), false); mHourRadialSelectorView.invalidate(); } else if (index == MINUTE_INDEX) { setValueForItem(MINUTE_INDEX, value); int minuteDegrees = value * MINUTE_VALUE_TO_DEGREES_STEP_SIZE; mMinuteRadialSelectorView.setSelection(minuteDegrees, false, false); mMinuteRadialSelectorView.invalidate(); } }
/** * For the currently showing view (either hours or minutes), re-calculate the position for the * selector, and redraw it at that position. The input degrees will be snapped to a selectable * value. * * @param degrees Degrees which should be selected. * @param isInnerCircle Whether the selection should be in the inner circle; will be ignored if * there is no inner circle. * @param forceToVisibleValue Even if the currently-showing circle allows for fine-grained * selection (i.e. minutes), force the selection to one of the visibly-showing values. * @param forceDrawDot The dot in the circle will generally only be shown when the selection is on * non-visible values, but use this to force the dot to be shown. * @return The value that was selected, i.e. 0-23 for hours, 0-59 for minutes. */ private int reselectSelector( int degrees, boolean isInnerCircle, boolean forceToVisibleValue, boolean forceDrawDot) { if (degrees == -1) { return -1; } int currentShowing = getCurrentItemShowing(); int stepSize; boolean allowFineGrained = !forceToVisibleValue && (currentShowing == MINUTE_INDEX); if (allowFineGrained) { degrees = snapPrefer30s(degrees); } else { degrees = snapOnly30s(degrees, 0); } RadialSelectorView radialSelectorView; if (currentShowing == HOUR_INDEX) { radialSelectorView = mHourRadialSelectorView; stepSize = HOUR_VALUE_TO_DEGREES_STEP_SIZE; } else { radialSelectorView = mMinuteRadialSelectorView; stepSize = MINUTE_VALUE_TO_DEGREES_STEP_SIZE; } radialSelectorView.setSelection(degrees, isInnerCircle, forceDrawDot); radialSelectorView.invalidate(); if (currentShowing == HOUR_INDEX) { if (mIs24HourMode) { if (degrees == 0 && isInnerCircle) { degrees = 360; } else if (degrees == 360 && !isInnerCircle) { degrees = 0; } } else if (degrees == 0) { degrees = 360; } } else if (degrees == 360 && currentShowing == MINUTE_INDEX) { degrees = 0; } int value = degrees / stepSize; if (currentShowing == HOUR_INDEX && mIs24HourMode && !isInnerCircle && degrees != 0) { value += 12; } return value; }
/** * Set either minutes or hours as showing. * * @param animate True to animate the transition, false to show with no animation. */ @SuppressLint("NewApi") public void setCurrentItemShowing(int index, boolean animate) { if (index != HOUR_INDEX && index != MINUTE_INDEX) { Log.e(TAG, "TimePicker does not support view at index " + index); return; } // NineOldDroids does not work in this case due to denepency recursion. animate = animate && Build.VERSION.SDK_INT >= 14; int lastIndex = getCurrentItemShowing(); mCurrentItemShowing = index; if (animate && (index != lastIndex)) { ObjectAnimator[] anims = new ObjectAnimator[4]; if (index == MINUTE_INDEX) { anims[0] = mHourRadialTextsView.getDisappearAnimator(); anims[1] = mHourRadialSelectorView.getDisappearAnimator(); anims[2] = mMinuteRadialTextsView.getReappearAnimator(); anims[3] = mMinuteRadialSelectorView.getReappearAnimator(); } else if (index == HOUR_INDEX) { anims[0] = mHourRadialTextsView.getReappearAnimator(); anims[1] = mHourRadialSelectorView.getReappearAnimator(); anims[2] = mMinuteRadialTextsView.getDisappearAnimator(); anims[3] = mMinuteRadialSelectorView.getDisappearAnimator(); } if (mTransition != null && mTransition.isRunning()) { mTransition.end(); } mTransition = new AnimatorSet(); mTransition.playTogether(anims); mTransition.start(); } else { if (Build.VERSION.SDK_INT >= 11) { int hourAlpha = (index == HOUR_INDEX) ? 255 : 0; int minuteAlpha = (index == MINUTE_INDEX) ? 255 : 0; mHourRadialTextsView.setAlpha(hourAlpha); mHourRadialSelectorView.setAlpha(hourAlpha); mMinuteRadialTextsView.setAlpha(minuteAlpha); mMinuteRadialSelectorView.setAlpha(minuteAlpha); } else { int hourVisibility = (index == HOUR_INDEX) ? View.VISIBLE : View.INVISIBLE; int minuteVisibility = (index == MINUTE_INDEX) ? View.VISIBLE : View.INVISIBLE; mHourRadialTextsView.setVisibility(hourVisibility); mHourRadialSelectorView.setVisibility(hourVisibility); mMinuteRadialTextsView.setVisibility(minuteVisibility); mMinuteRadialSelectorView.setVisibility(minuteVisibility); } } }