/** 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();
   }
 }
  /**
   * Initialize this selector with the state of the picker.
   *
   * @param context Current context.
   * @param is24HourMode Whether the selector is in 24-hour mode, which will tell us whether the
   *     circle's center is moved up slightly to make room for the AM/PM circles.
   * @param hasInnerCircle Whether we have both an inner and an outer circle of numbers that may be
   *     selected. Should be true for 24-hour mode in the hours circle.
   * @param disappearsOut Whether the numbers' animation will have them disappearing out or
   *     disappearing in.
   * @param selectionDegrees The initial degrees to be selected.
   * @param isInnerCircle Whether the initial selection is in the inner or outer circle. Will be
   *     ignored when hasInnerCircle is false.
   */
  public void initialize(
      Context context,
      boolean is24HourMode,
      boolean hasInnerCircle,
      boolean disappearsOut,
      int selectionDegrees,
      boolean isInnerCircle,
      boolean dark) {
    if (this.mIsInitialized) {
      Log.e(TAG, "This RadialSelectorView may only be initialized once.");
      return;
    }

    Resources res = context.getResources();

    int selectorColor = res.getColor(dark ? R.color.Red : R.color.blue);
    this.mPaint.setColor(selectorColor);
    this.mPaint.setAntiAlias(true);

    // Calculate values for the circle radius size.
    this.mIs24HourMode = is24HourMode;
    if (is24HourMode) {
      this.mCircleRadiusMultiplier =
          Float.parseFloat(res.getString(R.string.circle_radius_multiplier_24HourMode));
    } else {
      this.mCircleRadiusMultiplier =
          Float.parseFloat(res.getString(R.string.circle_radius_multiplier));
      this.mAmPmCircleRadiusMultiplier =
          Float.parseFloat(res.getString(R.string.ampm_circle_radius_multiplier));
    }

    // Calculate values for the radius size(s) of the numbers circle(s).
    this.mHasInnerCircle = hasInnerCircle;
    if (hasInnerCircle) {
      this.mInnerNumbersRadiusMultiplier =
          Float.parseFloat(res.getString(R.string.numbers_radius_multiplier_inner));
      this.mOuterNumbersRadiusMultiplier =
          Float.parseFloat(res.getString(R.string.numbers_radius_multiplier_outer));
    } else {
      this.mNumbersRadiusMultiplier =
          Float.parseFloat(res.getString(R.string.numbers_radius_multiplier_normal));
    }
    this.mSelectionRadiusMultiplier =
        Float.parseFloat(res.getString(R.string.selection_radius_multiplier));

    // Calculate values for the transition mid-way states.
    this.mAnimationRadiusMultiplier = 1;
    this.mTransitionMidRadiusMultiplier = 1f + 0.05f * (disappearsOut ? -1 : 1);
    this.mTransitionEndRadiusMultiplier = 1f + 0.3f * (disappearsOut ? 1 : -1);
    this.mInvalidateUpdateListener = new InvalidateUpdateListener();

    setSelection(selectionDegrees, isInnerCircle, false);
    this.mIsInitialized = true;
    this.mDark = dark;
  }
  /**
   * 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;
  }