RadialTimePickerView.java revision 11a68e18039b6bb2b67c5f7a82fa13d60583b2c3
1eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio/* 2eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio * Copyright (C) 2013 The Android Open Source Project 3eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio * 4eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio * Licensed under the Apache License, Version 2.0 (the "License"); 5eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio * you may not use this file except in compliance with the License. 6eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio * You may obtain a copy of the License at 7eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio * 8eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio * http://www.apache.org/licenses/LICENSE-2.0 9eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio * 10eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio * Unless required by applicable law or agreed to in writing, software 11eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio * distributed under the License is distributed on an "AS IS" BASIS, 12eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio * See the License for the specific language governing permissions and 14eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio * limitations under the License. 15eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio */ 16eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 17eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Megliopackage android.widget; 18eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 19eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglioimport android.animation.Animator; 20eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglioimport android.animation.AnimatorSet; 21eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglioimport android.animation.Keyframe; 22eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglioimport android.animation.ObjectAnimator; 23eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglioimport android.animation.PropertyValuesHolder; 24eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglioimport android.animation.ValueAnimator; 25eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglioimport android.content.Context; 26eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglioimport android.content.res.Resources; 27eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglioimport android.content.res.TypedArray; 28eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglioimport android.graphics.Canvas; 29eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglioimport android.graphics.Color; 30eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglioimport android.graphics.Paint; 31ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viveretteimport android.graphics.Rect; 32eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglioimport android.graphics.Typeface; 33eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglioimport android.os.Bundle; 34eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglioimport android.util.AttributeSet; 35ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viveretteimport android.util.IntArray; 36eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglioimport android.util.Log; 37ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viveretteimport android.util.MathUtils; 385134478151d8aa3d776f8d4f368dbcdbc501a92aAlan Viveretteimport android.util.TypedValue; 39eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglioimport android.view.HapticFeedbackConstants; 40eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglioimport android.view.MotionEvent; 41eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglioimport android.view.View; 42eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglioimport android.view.ViewGroup; 43eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglioimport android.view.accessibility.AccessibilityEvent; 44eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglioimport android.view.accessibility.AccessibilityNodeInfo; 45ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viveretteimport android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction; 46eb1d3798e37572ca515aad572350f5745adf023dAlan Viverette 47eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglioimport com.android.internal.R; 48ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viveretteimport com.android.internal.widget.ExploreByTouchHelper; 49eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 50eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglioimport java.util.ArrayList; 51eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglioimport java.util.Calendar; 52eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglioimport java.util.Locale; 53eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 54eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio/** 55eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio * View to show a clock circle picker (with one or two picking circles) 56eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio * 57eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio * @hide 58eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio */ 59eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Megliopublic class RadialTimePickerView extends View implements View.OnTouchListener { 60eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio private static final String TAG = "ClockView"; 61eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 62eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio private static final boolean DEBUG = false; 63eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 64eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio private static final int DEBUG_COLOR = 0x20FF0000; 65eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio private static final int DEBUG_TEXT_COLOR = 0x60FF0000; 66eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio private static final int DEBUG_STROKE_WIDTH = 2; 67eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 68eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio private static final int HOURS = 0; 69eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio private static final int MINUTES = 1; 70eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio private static final int HOURS_INNER = 2; 71eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 72eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio private static final int SELECTOR_CIRCLE = 0; 73eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio private static final int SELECTOR_DOT = 1; 74eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio private static final int SELECTOR_LINE = 2; 75eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 76eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio private static final int AM = 0; 77eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio private static final int PM = 1; 78eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 79eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio // Opaque alpha level 80eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio private static final int ALPHA_OPAQUE = 255; 81eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 82eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio // Transparent alpha level 83eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio private static final int ALPHA_TRANSPARENT = 0; 84eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 85eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio // Alpha level of color for selector. 86518ff0de95e64116ecb07706fc564d4c19197ca7Alan Viverette private static final int ALPHA_SELECTOR = 60; // was 51 87eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 88eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio private static final float COSINE_30_DEGREES = ((float) Math.sqrt(3)) * 0.5f; 89eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio private static final float SINE_30_DEGREES = 0.5f; 90eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 91eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio private static final int DEGREES_FOR_ONE_HOUR = 30; 92eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio private static final int DEGREES_FOR_ONE_MINUTE = 6; 93eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 94eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio private static final int[] HOURS_NUMBERS = {12, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}; 95eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio private static final int[] HOURS_NUMBERS_24 = {0, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23}; 96eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio private static final int[] MINUTES_NUMBERS = {0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55}; 97eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 98eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio private static final int CENTER_RADIUS = 2; 99eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 100eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio private static int[] sSnapPrefer30sMap = new int[361]; 101eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 102ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette private final InvalidateUpdateListener mInvalidateUpdateListener = 103ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette new InvalidateUpdateListener(); 104ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette 105eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio private final String[] mHours12Texts = new String[12]; 106eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio private final String[] mOuterHours24Texts = new String[12]; 107eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio private final String[] mInnerHours24Texts = new String[12]; 108eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio private final String[] mMinutesTexts = new String[12]; 109eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 110eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio private final Paint[] mPaint = new Paint[2]; 111eb1d3798e37572ca515aad572350f5745adf023dAlan Viverette private final int[] mColor = new int[2]; 112eb1d3798e37572ca515aad572350f5745adf023dAlan Viverette private final IntHolder[] mAlpha = new IntHolder[2]; 113eb1d3798e37572ca515aad572350f5745adf023dAlan Viverette 114eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio private final Paint mPaintCenter = new Paint(); 115eb1d3798e37572ca515aad572350f5745adf023dAlan Viverette 116eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio private final Paint[][] mPaintSelector = new Paint[2][3]; 117eb1d3798e37572ca515aad572350f5745adf023dAlan Viverette private final int[][] mColorSelector = new int[2][3]; 118eb1d3798e37572ca515aad572350f5745adf023dAlan Viverette private final IntHolder[][] mAlphaSelector = new IntHolder[2][3]; 119eb1d3798e37572ca515aad572350f5745adf023dAlan Viverette 120eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio private final Paint mPaintBackground = new Paint(); 121eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio private final Paint mPaintDebug = new Paint(); 122eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 123ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette private final Typeface mTypeface; 124ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette 125ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette private final float[] mCircleRadius = new float[3]; 126ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette 127ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette private final float[] mTextSize = new float[2]; 128ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette 129ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette private final float[][] mTextGridHeights = new float[2][7]; 130ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette private final float[][] mTextGridWidths = new float[2][7]; 131ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette 132ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette private final float[] mInnerTextGridHeights = new float[7]; 133ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette private final float[] mInnerTextGridWidths = new float[7]; 134ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette 135ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette private final float[] mCircleRadiusMultiplier = new float[2]; 136ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette private final float[] mNumbersRadiusMultiplier = new float[3]; 137ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette 138ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette private final float[] mTextSizeMultiplier = new float[3]; 139ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette 140ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette private final float[] mAnimationRadiusMultiplier = new float[3]; 141ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette 142ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette private final float mTransitionMidRadiusMultiplier; 143ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette private final float mTransitionEndRadiusMultiplier; 144ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette 145ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette private final int[] mLineLength = new int[3]; 146ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette private final int[] mSelectionRadius = new int[3]; 147ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette private final float mSelectionRadiusMultiplier; 148ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette private final int[] mSelectionDegrees = new int[3]; 149ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette 150ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette private final ArrayList<Animator> mHoursToMinutesAnims = new ArrayList<Animator>(); 151ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette private final ArrayList<Animator> mMinuteToHoursAnims = new ArrayList<Animator>(); 152ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette 153ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette private final RadialPickerTouchHelper mTouchHelper; 154ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette 155ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette private float mInnerTextSize; 156eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 157eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio private boolean mIs24HourMode; 158eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio private boolean mShowHours; 159d735c9b1ed36c7a45afc662c109c2dbf3e205e39Alan Viverette 160d735c9b1ed36c7a45afc662c109c2dbf3e205e39Alan Viverette /** 161d735c9b1ed36c7a45afc662c109c2dbf3e205e39Alan Viverette * When in 24-hour mode, indicates that the current hour is between 162d735c9b1ed36c7a45afc662c109c2dbf3e205e39Alan Viverette * 1 and 12 (inclusive). 163d735c9b1ed36c7a45afc662c109c2dbf3e205e39Alan Viverette */ 164eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio private boolean mIsOnInnerCircle; 165eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 166eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio private int mXCenter; 167eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio private int mYCenter; 168eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 169eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio private int mMinHypotenuseForInnerNumber; 170eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio private int mMaxHypotenuseForOuterNumber; 171eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio private int mHalfwayHypotenusePoint; 172eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 173eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio private String[] mOuterTextHours; 174eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio private String[] mInnerTextHours; 175eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio private String[] mOuterTextMinutes; 176eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio private AnimatorSet mTransition; 177eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 178eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio private int mAmOrPm; 1795134478151d8aa3d776f8d4f368dbcdbc501a92aAlan Viverette private int mDisabledAlpha; 1805134478151d8aa3d776f8d4f368dbcdbc501a92aAlan Viverette 181eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio private OnValueSelectedListener mListener; 182eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 183ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette private boolean mInputEnabled = true; 184eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 185eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio public interface OnValueSelectedListener { 186eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio void onValueSelected(int pickerIndex, int newValue, boolean autoAdvance); 187eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio } 188eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 189eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio static { 190eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio // Prepare mapping to snap touchable degrees to selectable degrees. 191eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio preparePrefer30sMap(); 192eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio } 193eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 194eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio /** 195eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio * Split up the 360 degrees of the circle among the 60 selectable values. Assigns a larger 196eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio * selectable area to each of the 12 visible values, such that the ratio of space apportioned 197eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio * to a visible value : space apportioned to a non-visible value will be 14 : 4. 198eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio * E.g. the output of 30 degrees should have a higher range of input associated with it than 199eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio * the output of 24 degrees, because 30 degrees corresponds to a visible number on the clock 200eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio * circle (5 on the minutes, 1 or 13 on the hours). 201eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio */ 202eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio private static void preparePrefer30sMap() { 203eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio // We'll split up the visible output and the non-visible output such that each visible 204eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio // output will correspond to a range of 14 associated input degrees, and each non-visible 205eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio // output will correspond to a range of 4 associate input degrees, so visible numbers 206eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio // are more than 3 times easier to get than non-visible numbers: 207eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio // {354-359,0-7}:0, {8-11}:6, {12-15}:12, {16-19}:18, {20-23}:24, {24-37}:30, etc. 208eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio // 209eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio // If an output of 30 degrees should correspond to a range of 14 associated degrees, then 210eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio // we'll need any input between 24 - 37 to snap to 30. Working out from there, 20-23 should 211eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio // snap to 24, while 38-41 should snap to 36. This is somewhat counter-intuitive, that you 212eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio // can be touching 36 degrees but have the selection snapped to 30 degrees; however, this 213eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio // inconsistency isn't noticeable at such fine-grained degrees, and it affords us the 214eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio // ability to aggressively prefer the visible values by a factor of more than 3:1, which 215eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio // greatly contributes to the selectability of these values. 216eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 217eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio // The first output is 0, and each following output will increment by 6 {0, 6, 12, ...}. 218eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio int snappedOutputDegrees = 0; 219eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio // Count of how many inputs we've designated to the specified output. 220eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio int count = 1; 221eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio // How many input we expect for a specified output. This will be 14 for output divisible 222eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio // by 30, and 4 for the remaining output. We'll special case the outputs of 0 and 360, so 223eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio // the caller can decide which they need. 224eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio int expectedCount = 8; 225eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio // Iterate through the input. 226eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio for (int degrees = 0; degrees < 361; degrees++) { 227eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio // Save the input-output mapping. 228eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio sSnapPrefer30sMap[degrees] = snappedOutputDegrees; 229eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio // If this is the last input for the specified output, calculate the next output and 230eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio // the next expected count. 231eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio if (count == expectedCount) { 232eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio snappedOutputDegrees += 6; 233eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio if (snappedOutputDegrees == 360) { 234eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio expectedCount = 7; 235eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio } else if (snappedOutputDegrees % 30 == 0) { 236eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio expectedCount = 14; 237eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio } else { 238eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio expectedCount = 4; 239eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio } 240eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio count = 1; 241eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio } else { 242eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio count++; 243eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio } 244eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio } 245eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio } 246eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 247eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio /** 248eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio * Returns mapping of any input degrees (0 to 360) to one of 60 selectable output degrees, 249eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio * where the degrees corresponding to visible numbers (i.e. those divisible by 30) will be 250eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio * weighted heavier than the degrees corresponding to non-visible numbers. 251eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio * See {@link #preparePrefer30sMap()} documentation for the rationale and generation of the 252eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio * mapping. 253eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio */ 254eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio private static int snapPrefer30s(int degrees) { 255eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio if (sSnapPrefer30sMap == null) { 256eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio return -1; 257eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio } 258eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio return sSnapPrefer30sMap[degrees]; 259eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio } 260eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 261eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio /** 262eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio * Returns mapping of any input degrees (0 to 360) to one of 12 visible output degrees (all 263eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio * multiples of 30), where the input will be "snapped" to the closest visible degrees. 264eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio * @param degrees The input degrees 265eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio * @param forceHigherOrLower The output may be forced to either the higher or lower step, or may 266eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio * be allowed to snap to whichever is closer. Use 1 to force strictly higher, -1 to force 267eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio * strictly lower, and 0 to snap to the closer one. 268eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio * @return output degrees, will be a multiple of 30 269eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio */ 270eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio private static int snapOnly30s(int degrees, int forceHigherOrLower) { 271eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio final int stepSize = DEGREES_FOR_ONE_HOUR; 272eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio int floor = (degrees / stepSize) * stepSize; 273eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio final int ceiling = floor + stepSize; 274eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio if (forceHigherOrLower == 1) { 275eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio degrees = ceiling; 276eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio } else if (forceHigherOrLower == -1) { 277eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio if (degrees == floor) { 278eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio floor -= stepSize; 279eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio } 280eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio degrees = floor; 281eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio } else { 282eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio if ((degrees - floor) < (ceiling - degrees)) { 283eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio degrees = floor; 284eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio } else { 285eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio degrees = ceiling; 286eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio } 287eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio } 288eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio return degrees; 289eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio } 290eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 291ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette @SuppressWarnings("unused") 292ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette public RadialTimePickerView(Context context) { 293ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette this(context, null); 294ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette } 295ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette 296eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio public RadialTimePickerView(Context context, AttributeSet attrs) { 297eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio this(context, attrs, R.attr.timePickerStyle); 298eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio } 299eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 300ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette public RadialTimePickerView(Context context, AttributeSet attrs, int defStyleAttr) { 301ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette this(context, attrs, defStyleAttr, 0); 302ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette } 303ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette 304ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette public RadialTimePickerView( 305ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { 306eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio super(context, attrs); 307eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 3085134478151d8aa3d776f8d4f368dbcdbc501a92aAlan Viverette // Pull disabled alpha from theme. 3095134478151d8aa3d776f8d4f368dbcdbc501a92aAlan Viverette final TypedValue outValue = new TypedValue(); 3105134478151d8aa3d776f8d4f368dbcdbc501a92aAlan Viverette context.getTheme().resolveAttribute(android.R.attr.disabledAlpha, outValue, true); 3115134478151d8aa3d776f8d4f368dbcdbc501a92aAlan Viverette mDisabledAlpha = (int) (outValue.getFloat() * 255 + 0.5f); 3125134478151d8aa3d776f8d4f368dbcdbc501a92aAlan Viverette 313eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio // process style attributes 3145134478151d8aa3d776f8d4f368dbcdbc501a92aAlan Viverette final Resources res = getResources(); 315eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio final TypedArray a = mContext.obtainStyledAttributes(attrs, R.styleable.TimePicker, 316ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette defStyleAttr, defStyleRes); 317eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 318eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio mTypeface = Typeface.create("sans-serif", Typeface.NORMAL); 319eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 320eb1d3798e37572ca515aad572350f5745adf023dAlan Viverette // Initialize all alpha values to opaque. 321eb1d3798e37572ca515aad572350f5745adf023dAlan Viverette for (int i = 0; i < mAlpha.length; i++) { 322eb1d3798e37572ca515aad572350f5745adf023dAlan Viverette mAlpha[i] = new IntHolder(ALPHA_OPAQUE); 323eb1d3798e37572ca515aad572350f5745adf023dAlan Viverette } 324eb1d3798e37572ca515aad572350f5745adf023dAlan Viverette for (int i = 0; i < mAlphaSelector.length; i++) { 325eb1d3798e37572ca515aad572350f5745adf023dAlan Viverette for (int j = 0; j < mAlphaSelector[i].length; j++) { 326eb1d3798e37572ca515aad572350f5745adf023dAlan Viverette mAlphaSelector[i][j] = new IntHolder(ALPHA_OPAQUE); 327eb1d3798e37572ca515aad572350f5745adf023dAlan Viverette } 328eb1d3798e37572ca515aad572350f5745adf023dAlan Viverette } 329eb1d3798e37572ca515aad572350f5745adf023dAlan Viverette 330eb1d3798e37572ca515aad572350f5745adf023dAlan Viverette final int numbersTextColor = a.getColor(R.styleable.TimePicker_numbersTextColor, 331830960cce032a1b0dc0cf54bcc44ffa339388c21Alan Viverette res.getColor(R.color.timepicker_default_text_color_material)); 332eb1d3798e37572ca515aad572350f5745adf023dAlan Viverette 333eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio mPaint[HOURS] = new Paint(); 334eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio mPaint[HOURS].setAntiAlias(true); 335eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio mPaint[HOURS].setTextAlign(Paint.Align.CENTER); 336eb1d3798e37572ca515aad572350f5745adf023dAlan Viverette mColor[HOURS] = numbersTextColor; 337eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 338eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio mPaint[MINUTES] = new Paint(); 339eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio mPaint[MINUTES].setAntiAlias(true); 340eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio mPaint[MINUTES].setTextAlign(Paint.Align.CENTER); 341eb1d3798e37572ca515aad572350f5745adf023dAlan Viverette mColor[MINUTES] = numbersTextColor; 342eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 343eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio mPaintCenter.setColor(numbersTextColor); 344eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio mPaintCenter.setAntiAlias(true); 345eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio mPaintCenter.setTextAlign(Paint.Align.CENTER); 346eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 347eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio mPaintSelector[HOURS][SELECTOR_CIRCLE] = new Paint(); 348eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio mPaintSelector[HOURS][SELECTOR_CIRCLE].setAntiAlias(true); 349eb1d3798e37572ca515aad572350f5745adf023dAlan Viverette mColorSelector[HOURS][SELECTOR_CIRCLE] = a.getColor( 350eb1d3798e37572ca515aad572350f5745adf023dAlan Viverette R.styleable.TimePicker_numbersSelectorColor, 351830960cce032a1b0dc0cf54bcc44ffa339388c21Alan Viverette R.color.timepicker_default_selector_color_material); 352eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 353eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio mPaintSelector[HOURS][SELECTOR_DOT] = new Paint(); 354eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio mPaintSelector[HOURS][SELECTOR_DOT].setAntiAlias(true); 355eb1d3798e37572ca515aad572350f5745adf023dAlan Viverette mColorSelector[HOURS][SELECTOR_DOT] = a.getColor( 356eb1d3798e37572ca515aad572350f5745adf023dAlan Viverette R.styleable.TimePicker_numbersSelectorColor, 357830960cce032a1b0dc0cf54bcc44ffa339388c21Alan Viverette R.color.timepicker_default_selector_color_material); 358eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 359eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio mPaintSelector[HOURS][SELECTOR_LINE] = new Paint(); 360eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio mPaintSelector[HOURS][SELECTOR_LINE].setAntiAlias(true); 361eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio mPaintSelector[HOURS][SELECTOR_LINE].setStrokeWidth(2); 362eb1d3798e37572ca515aad572350f5745adf023dAlan Viverette mColorSelector[HOURS][SELECTOR_LINE] = a.getColor( 363eb1d3798e37572ca515aad572350f5745adf023dAlan Viverette R.styleable.TimePicker_numbersSelectorColor, 364830960cce032a1b0dc0cf54bcc44ffa339388c21Alan Viverette R.color.timepicker_default_selector_color_material); 365eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 366eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio mPaintSelector[MINUTES][SELECTOR_CIRCLE] = new Paint(); 367eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio mPaintSelector[MINUTES][SELECTOR_CIRCLE].setAntiAlias(true); 368eb1d3798e37572ca515aad572350f5745adf023dAlan Viverette mColorSelector[MINUTES][SELECTOR_CIRCLE] = a.getColor( 369eb1d3798e37572ca515aad572350f5745adf023dAlan Viverette R.styleable.TimePicker_numbersSelectorColor, 370830960cce032a1b0dc0cf54bcc44ffa339388c21Alan Viverette R.color.timepicker_default_selector_color_material); 371eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 372eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio mPaintSelector[MINUTES][SELECTOR_DOT] = new Paint(); 373eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio mPaintSelector[MINUTES][SELECTOR_DOT].setAntiAlias(true); 374eb1d3798e37572ca515aad572350f5745adf023dAlan Viverette mColorSelector[MINUTES][SELECTOR_DOT] = a.getColor( 375eb1d3798e37572ca515aad572350f5745adf023dAlan Viverette R.styleable.TimePicker_numbersSelectorColor, 376830960cce032a1b0dc0cf54bcc44ffa339388c21Alan Viverette R.color.timepicker_default_selector_color_material); 377eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 378eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio mPaintSelector[MINUTES][SELECTOR_LINE] = new Paint(); 379eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio mPaintSelector[MINUTES][SELECTOR_LINE].setAntiAlias(true); 380eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio mPaintSelector[MINUTES][SELECTOR_LINE].setStrokeWidth(2); 381eb1d3798e37572ca515aad572350f5745adf023dAlan Viverette mColorSelector[MINUTES][SELECTOR_LINE] = a.getColor( 382eb1d3798e37572ca515aad572350f5745adf023dAlan Viverette R.styleable.TimePicker_numbersSelectorColor, 383830960cce032a1b0dc0cf54bcc44ffa339388c21Alan Viverette R.color.timepicker_default_selector_color_material); 384eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 385eb1d3798e37572ca515aad572350f5745adf023dAlan Viverette mPaintBackground.setColor(a.getColor(R.styleable.TimePicker_numbersBackgroundColor, 386830960cce032a1b0dc0cf54bcc44ffa339388c21Alan Viverette res.getColor(R.color.timepicker_default_numbers_background_color_material))); 387eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio mPaintBackground.setAntiAlias(true); 388eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 389eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio if (DEBUG) { 390eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio mPaintDebug.setColor(DEBUG_COLOR); 391eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio mPaintDebug.setAntiAlias(true); 392eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio mPaintDebug.setStrokeWidth(DEBUG_STROKE_WIDTH); 393eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio mPaintDebug.setStyle(Paint.Style.STROKE); 394eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio mPaintDebug.setTextAlign(Paint.Align.CENTER); 395eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio } 396eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 397eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio mShowHours = true; 398eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio mIs24HourMode = false; 399eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio mAmOrPm = AM; 400eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 401ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette // Set up accessibility components. 402ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette mTouchHelper = new RadialPickerTouchHelper(); 403ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette setAccessibilityDelegate(mTouchHelper); 404ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette 405ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette if (getImportantForAccessibility() == IMPORTANT_FOR_ACCESSIBILITY_AUTO) { 406ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES); 407ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette } 408ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette 409eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio initHoursAndMinutesText(); 410eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio initData(); 411eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 412eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio mTransitionMidRadiusMultiplier = Float.parseFloat( 413eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio res.getString(R.string.timepicker_transition_mid_radius_multiplier)); 414eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio mTransitionEndRadiusMultiplier = Float.parseFloat( 415eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio res.getString(R.string.timepicker_transition_end_radius_multiplier)); 416eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 417eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio mTextGridHeights[HOURS] = new float[7]; 418eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio mTextGridHeights[MINUTES] = new float[7]; 419eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 420eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio mSelectionRadiusMultiplier = Float.parseFloat( 421eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio res.getString(R.string.timepicker_selection_radius_multiplier)); 422eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 423eb1d3798e37572ca515aad572350f5745adf023dAlan Viverette a.recycle(); 424eb1d3798e37572ca515aad572350f5745adf023dAlan Viverette 425eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio setOnTouchListener(this); 426ba9bf41a77261471a4dc9d7964aec41726b4e4e6Alan Viverette setClickable(true); 427eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 428eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio // Initial values 429eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio final Calendar calendar = Calendar.getInstance(Locale.getDefault()); 430eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio final int currentHour = calendar.get(Calendar.HOUR_OF_DAY); 431eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio final int currentMinute = calendar.get(Calendar.MINUTE); 432eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 433ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette setCurrentHourInternal(currentHour, false, false); 434ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette setCurrentMinuteInternal(currentMinute, false); 435eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 436eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio setHapticFeedbackEnabled(true); 437eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio } 438eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 439eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio /** 440eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio * Measure the view to end up as a square, based on the minimum of the height and width. 441eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio */ 442eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio @Override 443eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 444eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio int measuredWidth = MeasureSpec.getSize(widthMeasureSpec); 445eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio int widthMode = MeasureSpec.getMode(widthMeasureSpec); 446eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio int measuredHeight = MeasureSpec.getSize(heightMeasureSpec); 447eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio int heightMode = MeasureSpec.getMode(heightMeasureSpec); 448eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio int minDimension = Math.min(measuredWidth, measuredHeight); 449eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 450eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio super.onMeasure(MeasureSpec.makeMeasureSpec(minDimension, widthMode), 451eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio MeasureSpec.makeMeasureSpec(minDimension, heightMode)); 452eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio } 453eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 454eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio public void initialize(int hour, int minute, boolean is24HourMode) { 455448ff718a0bb92c5b760668c12d2449a00f9aa2aAlan Viverette if (mIs24HourMode != is24HourMode) { 456448ff718a0bb92c5b760668c12d2449a00f9aa2aAlan Viverette mIs24HourMode = is24HourMode; 457448ff718a0bb92c5b760668c12d2449a00f9aa2aAlan Viverette initData(); 458448ff718a0bb92c5b760668c12d2449a00f9aa2aAlan Viverette } 459ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette 460ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette setCurrentHourInternal(hour, false, false); 461ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette setCurrentMinuteInternal(minute, false); 462eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio } 463eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 464eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio public void setCurrentItemShowing(int item, boolean animate) { 465eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio switch (item){ 466eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio case HOURS: 467eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio showHours(animate); 468eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio break; 469eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio case MINUTES: 470eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio showMinutes(animate); 471eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio break; 472eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio default: 473eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio Log.e(TAG, "ClockView does not support showing item " + item); 474eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio } 475eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio } 476eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 477eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio public int getCurrentItemShowing() { 478eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio return mShowHours ? HOURS : MINUTES; 479eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio } 480eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 481eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio public void setOnValueSelectedListener(OnValueSelectedListener listener) { 482eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio mListener = listener; 483eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio } 484eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 485d735c9b1ed36c7a45afc662c109c2dbf3e205e39Alan Viverette /** 486d735c9b1ed36c7a45afc662c109c2dbf3e205e39Alan Viverette * Sets the current hour in 24-hour time. 487d735c9b1ed36c7a45afc662c109c2dbf3e205e39Alan Viverette * 488d735c9b1ed36c7a45afc662c109c2dbf3e205e39Alan Viverette * @param hour the current hour between 0 and 23 (inclusive) 489d735c9b1ed36c7a45afc662c109c2dbf3e205e39Alan Viverette */ 490eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio public void setCurrentHour(int hour) { 491ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette setCurrentHourInternal(hour, true, false); 492ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette } 493ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette 494ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette /** 495ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette * Sets the current hour. 496ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette * 497ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette * @param hour The current hour 498ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette * @param callback Whether the value listener should be invoked 499ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette * @param autoAdvance Whether the listener should auto-advance to the next 500ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette * selection mode, e.g. hour to minutes 501ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette */ 502ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette private void setCurrentHourInternal(int hour, boolean callback, boolean autoAdvance) { 503eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio final int degrees = (hour % 12) * DEGREES_FOR_ONE_HOUR; 504eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio mSelectionDegrees[HOURS] = degrees; 505eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio mSelectionDegrees[HOURS_INNER] = degrees; 506d735c9b1ed36c7a45afc662c109c2dbf3e205e39Alan Viverette 507d735c9b1ed36c7a45afc662c109c2dbf3e205e39Alan Viverette // 0 is 12 AM (midnight) and 12 is 12 PM (noon). 508ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette final int amOrPm = (hour == 0 || (hour % 24) < 12) ? AM : PM; 509ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette final boolean isOnInnerCircle = mIs24HourMode && hour >= 1 && hour <= 12; 510ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette if (mAmOrPm != amOrPm || mIsOnInnerCircle != isOnInnerCircle) { 511ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette mAmOrPm = amOrPm; 512ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette mIsOnInnerCircle = isOnInnerCircle; 513ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette 514ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette initData(); 515ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette updateLayoutData(); 516ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette mTouchHelper.invalidateRoot(); 517ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette } 518d735c9b1ed36c7a45afc662c109c2dbf3e205e39Alan Viverette 519eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio invalidate(); 520ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette 521ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette if (callback && mListener != null) { 522ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette mListener.onValueSelected(HOURS, hour, autoAdvance); 523ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette } 524eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio } 525eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 526d735c9b1ed36c7a45afc662c109c2dbf3e205e39Alan Viverette /** 527d735c9b1ed36c7a45afc662c109c2dbf3e205e39Alan Viverette * Returns the current hour in 24-hour time. 528d735c9b1ed36c7a45afc662c109c2dbf3e205e39Alan Viverette * 529d735c9b1ed36c7a45afc662c109c2dbf3e205e39Alan Viverette * @return the current hour between 0 and 23 (inclusive) 530d735c9b1ed36c7a45afc662c109c2dbf3e205e39Alan Viverette */ 531eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio public int getCurrentHour() { 532ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette return getHourForDegrees( 533ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette mSelectionDegrees[mIsOnInnerCircle ? HOURS_INNER : HOURS], mIsOnInnerCircle); 534ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette } 535ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette 536ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette private int getHourForDegrees(int degrees, boolean innerCircle) { 537ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette int hour = (degrees / DEGREES_FOR_ONE_HOUR) % 12; 538eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio if (mIs24HourMode) { 539d735c9b1ed36c7a45afc662c109c2dbf3e205e39Alan Viverette // Convert the 12-hour value into 24-hour time based on where the 540d735c9b1ed36c7a45afc662c109c2dbf3e205e39Alan Viverette // selector is positioned. 541ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette if (innerCircle && hour == 0) { 542d735c9b1ed36c7a45afc662c109c2dbf3e205e39Alan Viverette // Inner circle is 1 through 12. 543d735c9b1ed36c7a45afc662c109c2dbf3e205e39Alan Viverette hour = 12; 544ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette } else if (!innerCircle && hour != 0) { 545d735c9b1ed36c7a45afc662c109c2dbf3e205e39Alan Viverette // Outer circle is 13 through 23 and 0. 546d735c9b1ed36c7a45afc662c109c2dbf3e205e39Alan Viverette hour += 12; 547eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio } 548d735c9b1ed36c7a45afc662c109c2dbf3e205e39Alan Viverette } else if (mAmOrPm == PM) { 549d735c9b1ed36c7a45afc662c109c2dbf3e205e39Alan Viverette hour += 12; 550eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio } 551d735c9b1ed36c7a45afc662c109c2dbf3e205e39Alan Viverette return hour; 552eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio } 553eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 554ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette private int getDegreesForHour(int hour) { 555ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette // Convert to be 0-11. 556ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette if (mIs24HourMode) { 557ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette if (hour >= 12) { 558ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette hour -= 12; 559ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette } 560ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette } else if (hour == 12) { 561ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette hour = 0; 562ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette } 563ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette return hour * DEGREES_FOR_ONE_HOUR; 564ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette } 565ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette 566eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio public void setCurrentMinute(int minute) { 567ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette setCurrentMinuteInternal(minute, true); 568ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette } 569ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette 570ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette private void setCurrentMinuteInternal(int minute, boolean callback) { 571eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio mSelectionDegrees[MINUTES] = (minute % 60) * DEGREES_FOR_ONE_MINUTE; 572ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette 573eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio invalidate(); 574ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette 575ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette if (callback && mListener != null) { 576ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette mListener.onValueSelected(MINUTES, minute, false); 577ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette } 578eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio } 579eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 580eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio // Returns minutes in 0-59 range 581eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio public int getCurrentMinute() { 582ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette return getMinuteForDegrees(mSelectionDegrees[MINUTES]); 583ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette } 584ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette 585ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette private int getMinuteForDegrees(int degrees) { 586ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette return degrees / DEGREES_FOR_ONE_MINUTE; 587ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette } 588ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette 589ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette private int getDegreesForMinute(int minute) { 590ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette return minute * DEGREES_FOR_ONE_MINUTE; 591eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio } 592eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 593eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio public void setAmOrPm(int val) { 594eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio mAmOrPm = (val % 2); 595eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio invalidate(); 596ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette mTouchHelper.invalidateRoot(); 597eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio } 598eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 599eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio public int getAmOrPm() { 600eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio return mAmOrPm; 601eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio } 602eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 603eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio public void showHours(boolean animate) { 604eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio if (mShowHours) return; 605eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio mShowHours = true; 606eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio if (animate) { 607eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio startMinutesToHoursAnimation(); 608eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio } 609eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio initData(); 610eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio updateLayoutData(); 611eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio invalidate(); 612eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio } 613eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 614eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio public void showMinutes(boolean animate) { 615eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio if (!mShowHours) return; 616eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio mShowHours = false; 617eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio if (animate) { 618eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio startHoursToMinutesAnimation(); 619eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio } 620eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio initData(); 621eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio updateLayoutData(); 622eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio invalidate(); 623eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio } 624eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 625eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio private void initHoursAndMinutesText() { 626eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio // Initialize the hours and minutes numbers. 627eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio for (int i = 0; i < 12; i++) { 628eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio mHours12Texts[i] = String.format("%d", HOURS_NUMBERS[i]); 629eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio mOuterHours24Texts[i] = String.format("%02d", HOURS_NUMBERS_24[i]); 630eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio mInnerHours24Texts[i] = String.format("%d", HOURS_NUMBERS[i]); 631eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio mMinutesTexts[i] = String.format("%02d", MINUTES_NUMBERS[i]); 632eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio } 633eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio } 634eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 635eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio private void initData() { 636eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio if (mIs24HourMode) { 637eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio mOuterTextHours = mOuterHours24Texts; 638eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio mInnerTextHours = mInnerHours24Texts; 639eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio } else { 640eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio mOuterTextHours = mHours12Texts; 641eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio mInnerTextHours = null; 642eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio } 643eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 644eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio mOuterTextMinutes = mMinutesTexts; 645eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 646eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio final Resources res = getResources(); 647eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 648eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio if (mShowHours) { 649eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio if (mIs24HourMode) { 650eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio mCircleRadiusMultiplier[HOURS] = Float.parseFloat( 651eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio res.getString(R.string.timepicker_circle_radius_multiplier_24HourMode)); 652eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio mNumbersRadiusMultiplier[HOURS] = Float.parseFloat( 653eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio res.getString(R.string.timepicker_numbers_radius_multiplier_outer)); 654eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio mTextSizeMultiplier[HOURS] = Float.parseFloat( 655eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio res.getString(R.string.timepicker_text_size_multiplier_outer)); 656eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 657eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio mNumbersRadiusMultiplier[HOURS_INNER] = Float.parseFloat( 658eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio res.getString(R.string.timepicker_numbers_radius_multiplier_inner)); 659eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio mTextSizeMultiplier[HOURS_INNER] = Float.parseFloat( 660eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio res.getString(R.string.timepicker_text_size_multiplier_inner)); 661eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio } else { 662eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio mCircleRadiusMultiplier[HOURS] = Float.parseFloat( 663eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio res.getString(R.string.timepicker_circle_radius_multiplier)); 664eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio mNumbersRadiusMultiplier[HOURS] = Float.parseFloat( 665eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio res.getString(R.string.timepicker_numbers_radius_multiplier_normal)); 666eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio mTextSizeMultiplier[HOURS] = Float.parseFloat( 667eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio res.getString(R.string.timepicker_text_size_multiplier_normal)); 668eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio } 669eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio } else { 670eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio mCircleRadiusMultiplier[MINUTES] = Float.parseFloat( 671eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio res.getString(R.string.timepicker_circle_radius_multiplier)); 672eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio mNumbersRadiusMultiplier[MINUTES] = Float.parseFloat( 673eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio res.getString(R.string.timepicker_numbers_radius_multiplier_normal)); 674eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio mTextSizeMultiplier[MINUTES] = Float.parseFloat( 675eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio res.getString(R.string.timepicker_text_size_multiplier_normal)); 676eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio } 677eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 678eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio mAnimationRadiusMultiplier[HOURS] = 1; 679eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio mAnimationRadiusMultiplier[HOURS_INNER] = 1; 680eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio mAnimationRadiusMultiplier[MINUTES] = 1; 681eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 682eb1d3798e37572ca515aad572350f5745adf023dAlan Viverette mAlpha[HOURS].setValue(mShowHours ? ALPHA_OPAQUE : ALPHA_TRANSPARENT); 683eb1d3798e37572ca515aad572350f5745adf023dAlan Viverette mAlpha[MINUTES].setValue(mShowHours ? ALPHA_TRANSPARENT : ALPHA_OPAQUE); 684eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 685eb1d3798e37572ca515aad572350f5745adf023dAlan Viverette mAlphaSelector[HOURS][SELECTOR_CIRCLE].setValue( 686eb1d3798e37572ca515aad572350f5745adf023dAlan Viverette mShowHours ? ALPHA_SELECTOR : ALPHA_TRANSPARENT); 687eb1d3798e37572ca515aad572350f5745adf023dAlan Viverette mAlphaSelector[HOURS][SELECTOR_DOT].setValue( 688eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio mShowHours ? ALPHA_OPAQUE : ALPHA_TRANSPARENT); 689eb1d3798e37572ca515aad572350f5745adf023dAlan Viverette mAlphaSelector[HOURS][SELECTOR_LINE].setValue( 690eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio mShowHours ? ALPHA_SELECTOR : ALPHA_TRANSPARENT); 691eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 692eb1d3798e37572ca515aad572350f5745adf023dAlan Viverette mAlphaSelector[MINUTES][SELECTOR_CIRCLE].setValue( 693eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio mShowHours ? ALPHA_TRANSPARENT : ALPHA_SELECTOR); 694eb1d3798e37572ca515aad572350f5745adf023dAlan Viverette mAlphaSelector[MINUTES][SELECTOR_DOT].setValue( 695eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio mShowHours ? ALPHA_TRANSPARENT : ALPHA_OPAQUE); 696eb1d3798e37572ca515aad572350f5745adf023dAlan Viverette mAlphaSelector[MINUTES][SELECTOR_LINE].setValue( 697eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio mShowHours ? ALPHA_TRANSPARENT : ALPHA_SELECTOR); 698eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio } 699eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 700eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio @Override 701eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio protected void onLayout(boolean changed, int left, int top, int right, int bottom) { 702eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio updateLayoutData(); 703eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio } 704eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 705eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio private void updateLayoutData() { 706eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio mXCenter = getWidth() / 2; 707eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio mYCenter = getHeight() / 2; 708eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 709eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio final int min = Math.min(mXCenter, mYCenter); 710eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 711eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio mCircleRadius[HOURS] = min * mCircleRadiusMultiplier[HOURS]; 712eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio mCircleRadius[HOURS_INNER] = min * mCircleRadiusMultiplier[HOURS]; 713eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio mCircleRadius[MINUTES] = min * mCircleRadiusMultiplier[MINUTES]; 714eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 715eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio mMinHypotenuseForInnerNumber = (int) (mCircleRadius[HOURS] 716eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio * mNumbersRadiusMultiplier[HOURS_INNER]) - mSelectionRadius[HOURS]; 717eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio mMaxHypotenuseForOuterNumber = (int) (mCircleRadius[HOURS] 718eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio * mNumbersRadiusMultiplier[HOURS]) + mSelectionRadius[HOURS]; 719eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio mHalfwayHypotenusePoint = (int) (mCircleRadius[HOURS] 720eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio * ((mNumbersRadiusMultiplier[HOURS] + mNumbersRadiusMultiplier[HOURS_INNER]) / 2)); 721eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 722eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio mTextSize[HOURS] = mCircleRadius[HOURS] * mTextSizeMultiplier[HOURS]; 723eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio mTextSize[MINUTES] = mCircleRadius[MINUTES] * mTextSizeMultiplier[MINUTES]; 724eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 725eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio if (mIs24HourMode) { 726eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio mInnerTextSize = mCircleRadius[HOURS] * mTextSizeMultiplier[HOURS_INNER]; 727eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio } 728eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 729eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio calculateGridSizesHours(); 730eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio calculateGridSizesMinutes(); 731eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 732eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio mSelectionRadius[HOURS] = (int) (mCircleRadius[HOURS] * mSelectionRadiusMultiplier); 733eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio mSelectionRadius[HOURS_INNER] = mSelectionRadius[HOURS]; 734eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio mSelectionRadius[MINUTES] = (int) (mCircleRadius[MINUTES] * mSelectionRadiusMultiplier); 735ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette 736ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette mTouchHelper.invalidateRoot(); 737eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio } 738eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 739eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio @Override 740eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio public void onDraw(Canvas canvas) { 7415134478151d8aa3d776f8d4f368dbcdbc501a92aAlan Viverette if (!mInputEnabled) { 7425134478151d8aa3d776f8d4f368dbcdbc501a92aAlan Viverette canvas.saveLayerAlpha(0, 0, getWidth(), getHeight(), mDisabledAlpha); 7435134478151d8aa3d776f8d4f368dbcdbc501a92aAlan Viverette } else { 7445134478151d8aa3d776f8d4f368dbcdbc501a92aAlan Viverette canvas.save(); 7455134478151d8aa3d776f8d4f368dbcdbc501a92aAlan Viverette } 746eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 747eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio calculateGridSizesHours(); 748eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio calculateGridSizesMinutes(); 749eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 750eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio drawCircleBackground(canvas); 751eb1d3798e37572ca515aad572350f5745adf023dAlan Viverette drawSelector(canvas); 752eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 753eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio drawTextElements(canvas, mTextSize[HOURS], mTypeface, mOuterTextHours, 754eb1d3798e37572ca515aad572350f5745adf023dAlan Viverette mTextGridWidths[HOURS], mTextGridHeights[HOURS], mPaint[HOURS], 755eb1d3798e37572ca515aad572350f5745adf023dAlan Viverette mColor[HOURS], mAlpha[HOURS].getValue()); 756eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 757eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio if (mIs24HourMode && mInnerTextHours != null) { 758eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio drawTextElements(canvas, mInnerTextSize, mTypeface, mInnerTextHours, 759eb1d3798e37572ca515aad572350f5745adf023dAlan Viverette mInnerTextGridWidths, mInnerTextGridHeights, mPaint[HOURS], 760eb1d3798e37572ca515aad572350f5745adf023dAlan Viverette mColor[HOURS], mAlpha[HOURS].getValue()); 761eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio } 762eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 763eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio drawTextElements(canvas, mTextSize[MINUTES], mTypeface, mOuterTextMinutes, 764eb1d3798e37572ca515aad572350f5745adf023dAlan Viverette mTextGridWidths[MINUTES], mTextGridHeights[MINUTES], mPaint[MINUTES], 765eb1d3798e37572ca515aad572350f5745adf023dAlan Viverette mColor[MINUTES], mAlpha[MINUTES].getValue()); 766eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 767eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio drawCenter(canvas); 768eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 769eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio if (DEBUG) { 770eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio drawDebug(canvas); 771eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio } 772eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 773eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio canvas.restore(); 774eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio } 775eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 776eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio private void drawCircleBackground(Canvas canvas) { 777eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio canvas.drawCircle(mXCenter, mYCenter, mCircleRadius[HOURS], mPaintBackground); 778eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio } 779eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 780eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio private void drawCenter(Canvas canvas) { 781eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio canvas.drawCircle(mXCenter, mYCenter, CENTER_RADIUS, mPaintCenter); 782eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio } 783eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 784eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio private void drawSelector(Canvas canvas) { 785eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio drawSelector(canvas, mIsOnInnerCircle ? HOURS_INNER : HOURS); 786eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio drawSelector(canvas, MINUTES); 787eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio } 788eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 789eb1d3798e37572ca515aad572350f5745adf023dAlan Viverette private int getMultipliedAlpha(int argb, int alpha) { 790eb1d3798e37572ca515aad572350f5745adf023dAlan Viverette return (int) (Color.alpha(argb) * (alpha / 255.0) + 0.5); 791eb1d3798e37572ca515aad572350f5745adf023dAlan Viverette } 792eb1d3798e37572ca515aad572350f5745adf023dAlan Viverette 793eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio private void drawSelector(Canvas canvas, int index) { 794eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio // Calculate the current radius at which to place the selection circle. 795eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio mLineLength[index] = (int) (mCircleRadius[index] 796eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio * mNumbersRadiusMultiplier[index] * mAnimationRadiusMultiplier[index]); 797eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 798eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio double selectionRadians = Math.toRadians(mSelectionDegrees[index]); 799eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 800eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio int pointX = mXCenter + (int) (mLineLength[index] * Math.sin(selectionRadians)); 801eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio int pointY = mYCenter - (int) (mLineLength[index] * Math.cos(selectionRadians)); 802eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 803eb1d3798e37572ca515aad572350f5745adf023dAlan Viverette int color; 804eb1d3798e37572ca515aad572350f5745adf023dAlan Viverette int alpha; 805eb1d3798e37572ca515aad572350f5745adf023dAlan Viverette Paint paint; 806eb1d3798e37572ca515aad572350f5745adf023dAlan Viverette 807eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio // Draw the selection circle 808eb1d3798e37572ca515aad572350f5745adf023dAlan Viverette color = mColorSelector[index % 2][SELECTOR_CIRCLE]; 809eb1d3798e37572ca515aad572350f5745adf023dAlan Viverette alpha = mAlphaSelector[index % 2][SELECTOR_CIRCLE].getValue(); 810eb1d3798e37572ca515aad572350f5745adf023dAlan Viverette paint = mPaintSelector[index % 2][SELECTOR_CIRCLE]; 811eb1d3798e37572ca515aad572350f5745adf023dAlan Viverette paint.setColor(color); 812eb1d3798e37572ca515aad572350f5745adf023dAlan Viverette paint.setAlpha(getMultipliedAlpha(color, alpha)); 813eb1d3798e37572ca515aad572350f5745adf023dAlan Viverette canvas.drawCircle(pointX, pointY, mSelectionRadius[index], paint); 814eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 815eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio // Draw the dot if needed 816eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio if (mSelectionDegrees[index] % 30 != 0) { 817eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio // We're not on a direct tick 818eb1d3798e37572ca515aad572350f5745adf023dAlan Viverette color = mColorSelector[index % 2][SELECTOR_DOT]; 819eb1d3798e37572ca515aad572350f5745adf023dAlan Viverette alpha = mAlphaSelector[index % 2][SELECTOR_DOT].getValue(); 820eb1d3798e37572ca515aad572350f5745adf023dAlan Viverette paint = mPaintSelector[index % 2][SELECTOR_DOT]; 821eb1d3798e37572ca515aad572350f5745adf023dAlan Viverette paint.setColor(color); 822eb1d3798e37572ca515aad572350f5745adf023dAlan Viverette paint.setAlpha(getMultipliedAlpha(color, alpha)); 823eb1d3798e37572ca515aad572350f5745adf023dAlan Viverette canvas.drawCircle(pointX, pointY, (mSelectionRadius[index] * 2 / 7), paint); 824eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio } else { 825eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio // We're not drawing the dot, so shorten the line to only go as far as the edge of the 826eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio // selection circle 827eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio int lineLength = mLineLength[index] - mSelectionRadius[index]; 828eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio pointX = mXCenter + (int) (lineLength * Math.sin(selectionRadians)); 829eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio pointY = mYCenter - (int) (lineLength * Math.cos(selectionRadians)); 830eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio } 831eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 832eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio // Draw the line 833eb1d3798e37572ca515aad572350f5745adf023dAlan Viverette color = mColorSelector[index % 2][SELECTOR_LINE]; 834eb1d3798e37572ca515aad572350f5745adf023dAlan Viverette alpha = mAlphaSelector[index % 2][SELECTOR_LINE].getValue(); 835eb1d3798e37572ca515aad572350f5745adf023dAlan Viverette paint = mPaintSelector[index % 2][SELECTOR_LINE]; 836eb1d3798e37572ca515aad572350f5745adf023dAlan Viverette paint.setColor(color); 837eb1d3798e37572ca515aad572350f5745adf023dAlan Viverette paint.setAlpha(getMultipliedAlpha(color, alpha)); 838eb1d3798e37572ca515aad572350f5745adf023dAlan Viverette canvas.drawLine(mXCenter, mYCenter, pointX, pointY, paint); 839eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio } 840eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 841eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio private void drawDebug(Canvas canvas) { 842eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio // Draw outer numbers circle 843eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio final float outerRadius = mCircleRadius[HOURS] * mNumbersRadiusMultiplier[HOURS]; 844eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio canvas.drawCircle(mXCenter, mYCenter, outerRadius, mPaintDebug); 845eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 846eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio // Draw inner numbers circle 847eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio final float innerRadius = mCircleRadius[HOURS] * mNumbersRadiusMultiplier[HOURS_INNER]; 848eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio canvas.drawCircle(mXCenter, mYCenter, innerRadius, mPaintDebug); 849eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 850eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio // Draw outer background circle 851eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio canvas.drawCircle(mXCenter, mYCenter, mCircleRadius[HOURS], mPaintDebug); 852eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 853eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio // Draw outer rectangle for circles 854eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio float left = mXCenter - outerRadius; 855eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio float top = mYCenter - outerRadius; 856eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio float right = mXCenter + outerRadius; 857eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio float bottom = mYCenter + outerRadius; 858ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette canvas.drawRect(left, top, right, bottom, mPaintDebug); 859eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 860eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio // Draw outer rectangle for background 861eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio left = mXCenter - mCircleRadius[HOURS]; 862eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio top = mYCenter - mCircleRadius[HOURS]; 863eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio right = mXCenter + mCircleRadius[HOURS]; 864eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio bottom = mYCenter + mCircleRadius[HOURS]; 865ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette canvas.drawRect(left, top, right, bottom, mPaintDebug); 866eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 867eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio // Draw outer view rectangle 868ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette canvas.drawRect(0, 0, getWidth(), getHeight(), mPaintDebug); 869eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 870eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio // Draw selected time 871eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio final String selected = String.format("%02d:%02d", getCurrentHour(), getCurrentMinute()); 872eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 873eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, 874eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio ViewGroup.LayoutParams.WRAP_CONTENT); 875eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio TextView tv = new TextView(getContext()); 876eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio tv.setLayoutParams(lp); 877eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio tv.setText(selected); 878eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio tv.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED); 879eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio Paint paint = tv.getPaint(); 880eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio paint.setColor(DEBUG_TEXT_COLOR); 881eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 882eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio final int width = tv.getMeasuredWidth(); 883eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 884eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio float height = paint.descent() - paint.ascent(); 885eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio float x = mXCenter - width / 2; 886eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio float y = mYCenter + 1.5f * height; 887eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 88867945c11a5e9547f71be91ceb99e7b9ff15a6292Alan Viverette canvas.drawText(selected, x, y, paint); 889eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio } 890eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 891eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio private void calculateGridSizesHours() { 892eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio // Calculate the text positions 893eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio float numbersRadius = mCircleRadius[HOURS] 894eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio * mNumbersRadiusMultiplier[HOURS] * mAnimationRadiusMultiplier[HOURS]; 895eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 896eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio // Calculate the positions for the 12 numbers in the main circle. 897eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio calculateGridSizes(mPaint[HOURS], numbersRadius, mXCenter, mYCenter, 898eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio mTextSize[HOURS], mTextGridHeights[HOURS], mTextGridWidths[HOURS]); 899eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 900eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio // If we have an inner circle, calculate those positions too. 901eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio if (mIs24HourMode) { 902eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio float innerNumbersRadius = mCircleRadius[HOURS_INNER] 903eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio * mNumbersRadiusMultiplier[HOURS_INNER] 904eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio * mAnimationRadiusMultiplier[HOURS_INNER]; 905eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 906eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio calculateGridSizes(mPaint[HOURS], innerNumbersRadius, mXCenter, mYCenter, 907eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio mInnerTextSize, mInnerTextGridHeights, mInnerTextGridWidths); 908eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio } 909eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio } 910eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 911eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio private void calculateGridSizesMinutes() { 912eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio // Calculate the text positions 913eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio float numbersRadius = mCircleRadius[MINUTES] 914eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio * mNumbersRadiusMultiplier[MINUTES] * mAnimationRadiusMultiplier[MINUTES]; 915eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 916eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio // Calculate the positions for the 12 numbers in the main circle. 917eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio calculateGridSizes(mPaint[MINUTES], numbersRadius, mXCenter, mYCenter, 918eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio mTextSize[MINUTES], mTextGridHeights[MINUTES], mTextGridWidths[MINUTES]); 919eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio } 920eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 921eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 922eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio /** 923eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio * Using the trigonometric Unit Circle, calculate the positions that the text will need to be 924eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio * drawn at based on the specified circle radius. Place the values in the textGridHeights and 925eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio * textGridWidths parameters. 926eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio */ 927eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio private static void calculateGridSizes(Paint paint, float numbersRadius, float xCenter, 928eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio float yCenter, float textSize, float[] textGridHeights, float[] textGridWidths) { 929eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio /* 930eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio * The numbers need to be drawn in a 7x7 grid, representing the points on the Unit Circle. 931eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio */ 932eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio final float offset1 = numbersRadius; 933eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio // cos(30) = a / r => r * cos(30) 934eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio final float offset2 = numbersRadius * COSINE_30_DEGREES; 935eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio // sin(30) = o / r => r * sin(30) 936eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio final float offset3 = numbersRadius * SINE_30_DEGREES; 937eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 938eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio paint.setTextSize(textSize); 939eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio // We'll need yTextBase to be slightly lower to account for the text's baseline. 940eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio yCenter -= (paint.descent() + paint.ascent()) / 2; 941eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 942eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio textGridHeights[0] = yCenter - offset1; 943eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio textGridWidths[0] = xCenter - offset1; 944eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio textGridHeights[1] = yCenter - offset2; 945eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio textGridWidths[1] = xCenter - offset2; 946eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio textGridHeights[2] = yCenter - offset3; 947eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio textGridWidths[2] = xCenter - offset3; 948eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio textGridHeights[3] = yCenter; 949eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio textGridWidths[3] = xCenter; 950eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio textGridHeights[4] = yCenter + offset3; 951eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio textGridWidths[4] = xCenter + offset3; 952eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio textGridHeights[5] = yCenter + offset2; 953eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio textGridWidths[5] = xCenter + offset2; 954eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio textGridHeights[6] = yCenter + offset1; 955eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio textGridWidths[6] = xCenter + offset1; 956eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio } 957eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 958eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio /** 959eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio * Draw the 12 text values at the positions specified by the textGrid parameters. 960eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio */ 961eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio private void drawTextElements(Canvas canvas, float textSize, Typeface typeface, String[] texts, 962eb1d3798e37572ca515aad572350f5745adf023dAlan Viverette float[] textGridWidths, float[] textGridHeights, Paint paint, int color, int alpha) { 963eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio paint.setTextSize(textSize); 964eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio paint.setTypeface(typeface); 965eb1d3798e37572ca515aad572350f5745adf023dAlan Viverette paint.setColor(color); 966eb1d3798e37572ca515aad572350f5745adf023dAlan Viverette paint.setAlpha(getMultipliedAlpha(color, alpha)); 967eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio canvas.drawText(texts[0], textGridWidths[3], textGridHeights[0], paint); 968eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio canvas.drawText(texts[1], textGridWidths[4], textGridHeights[1], paint); 969eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio canvas.drawText(texts[2], textGridWidths[5], textGridHeights[2], paint); 970eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio canvas.drawText(texts[3], textGridWidths[6], textGridHeights[3], paint); 971eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio canvas.drawText(texts[4], textGridWidths[5], textGridHeights[4], paint); 972eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio canvas.drawText(texts[5], textGridWidths[4], textGridHeights[5], paint); 973eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio canvas.drawText(texts[6], textGridWidths[3], textGridHeights[6], paint); 974eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio canvas.drawText(texts[7], textGridWidths[2], textGridHeights[5], paint); 975eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio canvas.drawText(texts[8], textGridWidths[1], textGridHeights[4], paint); 976eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio canvas.drawText(texts[9], textGridWidths[0], textGridHeights[3], paint); 977eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio canvas.drawText(texts[10], textGridWidths[1], textGridHeights[2], paint); 978eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio canvas.drawText(texts[11], textGridWidths[2], textGridHeights[1], paint); 979eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio } 980eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 981eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio // Used for animating the hours by changing their radius 982ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette @SuppressWarnings("unused") 983eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio private void setAnimationRadiusMultiplierHours(float animationRadiusMultiplier) { 984eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio mAnimationRadiusMultiplier[HOURS] = animationRadiusMultiplier; 985eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio mAnimationRadiusMultiplier[HOURS_INNER] = animationRadiusMultiplier; 986eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio } 987eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 988eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio // Used for animating the minutes by changing their radius 989ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette @SuppressWarnings("unused") 990eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio private void setAnimationRadiusMultiplierMinutes(float animationRadiusMultiplier) { 991eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio mAnimationRadiusMultiplier[MINUTES] = animationRadiusMultiplier; 992eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio } 993eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 994eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio private static ObjectAnimator getRadiusDisappearAnimator(Object target, 995eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio String radiusPropertyName, InvalidateUpdateListener updateListener, 996eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio float midRadiusMultiplier, float endRadiusMultiplier) { 997eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio Keyframe kf0, kf1, kf2; 998eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio float midwayPoint = 0.2f; 999eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio int duration = 500; 1000eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 1001eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio kf0 = Keyframe.ofFloat(0f, 1); 1002eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio kf1 = Keyframe.ofFloat(midwayPoint, midRadiusMultiplier); 1003eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio kf2 = Keyframe.ofFloat(1f, endRadiusMultiplier); 1004eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio PropertyValuesHolder radiusDisappear = PropertyValuesHolder.ofKeyframe( 1005eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio radiusPropertyName, kf0, kf1, kf2); 1006eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 1007eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder( 1008eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio target, radiusDisappear).setDuration(duration); 1009eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio animator.addUpdateListener(updateListener); 1010eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio return animator; 1011eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio } 1012eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 1013eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio private static ObjectAnimator getRadiusReappearAnimator(Object target, 1014eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio String radiusPropertyName, InvalidateUpdateListener updateListener, 1015eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio float midRadiusMultiplier, float endRadiusMultiplier) { 1016eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio Keyframe kf0, kf1, kf2, kf3; 1017eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio float midwayPoint = 0.2f; 1018eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio int duration = 500; 1019eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 1020eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio // Set up animator for reappearing. 1021eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio float delayMultiplier = 0.25f; 1022eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio float transitionDurationMultiplier = 1f; 1023eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio float totalDurationMultiplier = transitionDurationMultiplier + delayMultiplier; 1024eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio int totalDuration = (int) (duration * totalDurationMultiplier); 1025eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio float delayPoint = (delayMultiplier * duration) / totalDuration; 1026eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio midwayPoint = 1 - (midwayPoint * (1 - delayPoint)); 1027eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 1028eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio kf0 = Keyframe.ofFloat(0f, endRadiusMultiplier); 1029eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio kf1 = Keyframe.ofFloat(delayPoint, endRadiusMultiplier); 1030eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio kf2 = Keyframe.ofFloat(midwayPoint, midRadiusMultiplier); 1031eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio kf3 = Keyframe.ofFloat(1f, 1); 1032eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio PropertyValuesHolder radiusReappear = PropertyValuesHolder.ofKeyframe( 1033eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio radiusPropertyName, kf0, kf1, kf2, kf3); 1034eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 1035eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder( 1036eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio target, radiusReappear).setDuration(totalDuration); 1037eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio animator.addUpdateListener(updateListener); 1038eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio return animator; 1039eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio } 1040eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 1041eb1d3798e37572ca515aad572350f5745adf023dAlan Viverette private static ObjectAnimator getFadeOutAnimator(IntHolder target, int startAlpha, int endAlpha, 1042eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio InvalidateUpdateListener updateListener) { 1043eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio int duration = 500; 1044eb1d3798e37572ca515aad572350f5745adf023dAlan Viverette ObjectAnimator animator = ObjectAnimator.ofInt(target, "value", startAlpha, endAlpha); 1045eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio animator.setDuration(duration); 1046eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio animator.addUpdateListener(updateListener); 1047eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 1048eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio return animator; 1049eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio } 1050eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 1051eb1d3798e37572ca515aad572350f5745adf023dAlan Viverette private static ObjectAnimator getFadeInAnimator(IntHolder target, int startAlpha, int endAlpha, 1052eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio InvalidateUpdateListener updateListener) { 1053eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio Keyframe kf0, kf1, kf2; 1054eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio int duration = 500; 1055eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 1056eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio // Set up animator for reappearing. 1057eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio float delayMultiplier = 0.25f; 1058eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio float transitionDurationMultiplier = 1f; 1059eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio float totalDurationMultiplier = transitionDurationMultiplier + delayMultiplier; 1060eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio int totalDuration = (int) (duration * totalDurationMultiplier); 1061eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio float delayPoint = (delayMultiplier * duration) / totalDuration; 1062eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 1063eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio kf0 = Keyframe.ofInt(0f, startAlpha); 1064eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio kf1 = Keyframe.ofInt(delayPoint, startAlpha); 1065eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio kf2 = Keyframe.ofInt(1f, endAlpha); 1066eb1d3798e37572ca515aad572350f5745adf023dAlan Viverette PropertyValuesHolder fadeIn = PropertyValuesHolder.ofKeyframe("value", kf0, kf1, kf2); 1067eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 1068eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder( 1069eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio target, fadeIn).setDuration(totalDuration); 1070eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio animator.addUpdateListener(updateListener); 1071eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio return animator; 1072eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio } 1073eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 1074eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio private class InvalidateUpdateListener implements ValueAnimator.AnimatorUpdateListener { 1075eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio @Override 1076eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio public void onAnimationUpdate(ValueAnimator animation) { 1077eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio RadialTimePickerView.this.invalidate(); 1078eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio } 1079eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio } 1080eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 1081eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio private void startHoursToMinutesAnimation() { 1082eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio if (mHoursToMinutesAnims.size() == 0) { 1083eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio mHoursToMinutesAnims.add(getRadiusDisappearAnimator(this, 1084eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio "animationRadiusMultiplierHours", mInvalidateUpdateListener, 1085eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio mTransitionMidRadiusMultiplier, mTransitionEndRadiusMultiplier)); 1086eb1d3798e37572ca515aad572350f5745adf023dAlan Viverette mHoursToMinutesAnims.add(getFadeOutAnimator(mAlpha[HOURS], 1087eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio ALPHA_OPAQUE, ALPHA_TRANSPARENT, mInvalidateUpdateListener)); 1088eb1d3798e37572ca515aad572350f5745adf023dAlan Viverette mHoursToMinutesAnims.add(getFadeOutAnimator(mAlphaSelector[HOURS][SELECTOR_CIRCLE], 1089eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio ALPHA_SELECTOR, ALPHA_TRANSPARENT, mInvalidateUpdateListener)); 1090eb1d3798e37572ca515aad572350f5745adf023dAlan Viverette mHoursToMinutesAnims.add(getFadeOutAnimator(mAlphaSelector[HOURS][SELECTOR_DOT], 1091eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio ALPHA_OPAQUE, ALPHA_TRANSPARENT, mInvalidateUpdateListener)); 1092eb1d3798e37572ca515aad572350f5745adf023dAlan Viverette mHoursToMinutesAnims.add(getFadeOutAnimator(mAlphaSelector[HOURS][SELECTOR_LINE], 1093eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio ALPHA_SELECTOR, ALPHA_TRANSPARENT, mInvalidateUpdateListener)); 1094eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 1095eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio mHoursToMinutesAnims.add(getRadiusReappearAnimator(this, 1096eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio "animationRadiusMultiplierMinutes", mInvalidateUpdateListener, 1097eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio mTransitionMidRadiusMultiplier, mTransitionEndRadiusMultiplier)); 1098eb1d3798e37572ca515aad572350f5745adf023dAlan Viverette mHoursToMinutesAnims.add(getFadeInAnimator(mAlpha[MINUTES], 1099eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio ALPHA_TRANSPARENT, ALPHA_OPAQUE, mInvalidateUpdateListener)); 1100eb1d3798e37572ca515aad572350f5745adf023dAlan Viverette mHoursToMinutesAnims.add(getFadeInAnimator(mAlphaSelector[MINUTES][SELECTOR_CIRCLE], 1101eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio ALPHA_TRANSPARENT, ALPHA_SELECTOR, mInvalidateUpdateListener)); 1102eb1d3798e37572ca515aad572350f5745adf023dAlan Viverette mHoursToMinutesAnims.add(getFadeInAnimator(mAlphaSelector[MINUTES][SELECTOR_DOT], 1103eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio ALPHA_TRANSPARENT, ALPHA_OPAQUE, mInvalidateUpdateListener)); 1104eb1d3798e37572ca515aad572350f5745adf023dAlan Viverette mHoursToMinutesAnims.add(getFadeInAnimator(mAlphaSelector[MINUTES][SELECTOR_LINE], 1105eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio ALPHA_TRANSPARENT, ALPHA_SELECTOR, mInvalidateUpdateListener)); 1106eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio } 1107eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 1108eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio if (mTransition != null && mTransition.isRunning()) { 1109eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio mTransition.end(); 1110eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio } 1111eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio mTransition = new AnimatorSet(); 1112eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio mTransition.playTogether(mHoursToMinutesAnims); 1113eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio mTransition.start(); 1114eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio } 1115eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 1116eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio private void startMinutesToHoursAnimation() { 1117eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio if (mMinuteToHoursAnims.size() == 0) { 1118eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio mMinuteToHoursAnims.add(getRadiusDisappearAnimator(this, 1119eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio "animationRadiusMultiplierMinutes", mInvalidateUpdateListener, 1120eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio mTransitionMidRadiusMultiplier, mTransitionEndRadiusMultiplier)); 1121eb1d3798e37572ca515aad572350f5745adf023dAlan Viverette mMinuteToHoursAnims.add(getFadeOutAnimator(mAlpha[MINUTES], 1122eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio ALPHA_OPAQUE, ALPHA_TRANSPARENT, mInvalidateUpdateListener)); 1123eb1d3798e37572ca515aad572350f5745adf023dAlan Viverette mMinuteToHoursAnims.add(getFadeOutAnimator(mAlphaSelector[MINUTES][SELECTOR_CIRCLE], 1124eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio ALPHA_SELECTOR, ALPHA_TRANSPARENT, mInvalidateUpdateListener)); 1125eb1d3798e37572ca515aad572350f5745adf023dAlan Viverette mMinuteToHoursAnims.add(getFadeOutAnimator(mAlphaSelector[MINUTES][SELECTOR_DOT], 1126eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio ALPHA_OPAQUE, ALPHA_TRANSPARENT, mInvalidateUpdateListener)); 1127eb1d3798e37572ca515aad572350f5745adf023dAlan Viverette mMinuteToHoursAnims.add(getFadeOutAnimator(mAlphaSelector[MINUTES][SELECTOR_LINE], 1128eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio ALPHA_SELECTOR, ALPHA_TRANSPARENT, mInvalidateUpdateListener)); 1129eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 1130eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio mMinuteToHoursAnims.add(getRadiusReappearAnimator(this, 1131eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio "animationRadiusMultiplierHours", mInvalidateUpdateListener, 1132eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio mTransitionMidRadiusMultiplier, mTransitionEndRadiusMultiplier)); 1133eb1d3798e37572ca515aad572350f5745adf023dAlan Viverette mMinuteToHoursAnims.add(getFadeInAnimator(mAlpha[HOURS], 1134eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio ALPHA_TRANSPARENT, ALPHA_OPAQUE, mInvalidateUpdateListener)); 1135eb1d3798e37572ca515aad572350f5745adf023dAlan Viverette mMinuteToHoursAnims.add(getFadeInAnimator(mAlphaSelector[HOURS][SELECTOR_CIRCLE], 1136eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio ALPHA_TRANSPARENT, ALPHA_SELECTOR, mInvalidateUpdateListener)); 1137eb1d3798e37572ca515aad572350f5745adf023dAlan Viverette mMinuteToHoursAnims.add(getFadeInAnimator(mAlphaSelector[HOURS][SELECTOR_DOT], 1138eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio ALPHA_TRANSPARENT, ALPHA_OPAQUE, mInvalidateUpdateListener)); 1139eb1d3798e37572ca515aad572350f5745adf023dAlan Viverette mMinuteToHoursAnims.add(getFadeInAnimator(mAlphaSelector[HOURS][SELECTOR_LINE], 1140eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio ALPHA_TRANSPARENT, ALPHA_SELECTOR, mInvalidateUpdateListener)); 1141eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio } 1142eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 1143eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio if (mTransition != null && mTransition.isRunning()) { 1144eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio mTransition.end(); 1145eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio } 1146eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio mTransition = new AnimatorSet(); 1147eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio mTransition.playTogether(mMinuteToHoursAnims); 1148eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio mTransition.start(); 1149eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio } 1150eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 1151eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio private int getDegreesFromXY(float x, float y) { 1152eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio final double hypotenuse = Math.sqrt( 1153eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio (y - mYCenter) * (y - mYCenter) + (x - mXCenter) * (x - mXCenter)); 1154eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 1155eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio // Basic check if we're outside the range of the disk 1156eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio if (hypotenuse > mCircleRadius[HOURS]) { 1157eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio return -1; 1158eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio } 1159eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio // Check 1160eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio if (mIs24HourMode && mShowHours) { 1161eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio if (hypotenuse >= mMinHypotenuseForInnerNumber 1162eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio && hypotenuse <= mHalfwayHypotenusePoint) { 1163eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio mIsOnInnerCircle = true; 1164eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio } else if (hypotenuse <= mMaxHypotenuseForOuterNumber 1165eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio && hypotenuse >= mHalfwayHypotenusePoint) { 1166eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio mIsOnInnerCircle = false; 1167eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio } else { 1168eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio return -1; 1169eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio } 1170eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio } else { 1171eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio final int index = (mShowHours) ? HOURS : MINUTES; 1172eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio final float length = (mCircleRadius[index] * mNumbersRadiusMultiplier[index]); 1173eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio final int distanceToNumber = (int) Math.abs(hypotenuse - length); 1174eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio final int maxAllowedDistance = 1175eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio (int) (mCircleRadius[index] * (1 - mNumbersRadiusMultiplier[index])); 1176eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio if (distanceToNumber > maxAllowedDistance) { 1177eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio return -1; 1178eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio } 1179eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio } 1180eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 1181eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio final float opposite = Math.abs(y - mYCenter); 1182ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette int degrees = (int) (Math.toDegrees(Math.asin(opposite / hypotenuse)) + 0.5); 1183eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 1184eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio // Now we have to translate to the correct quadrant. 1185ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette final boolean rightSide = (x > mXCenter); 1186ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette final boolean topSide = (y < mYCenter); 1187ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette if (rightSide) { 1188ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette if (topSide) { 1189ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette degrees = 90 - degrees; 1190ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette } else { 1191ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette degrees = 90 + degrees; 1192ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette } 1193ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette } else { 1194ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette if (topSide) { 1195ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette degrees = 270 + degrees; 1196ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette } else { 1197ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette degrees = 270 - degrees; 1198ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette } 1199eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio } 1200ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette return degrees; 1201eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio } 1202eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 1203002f918ceae416ba5c382de499ccff12e642c7b5Alan Viverette boolean mChangedDuringTouch = false; 1204002f918ceae416ba5c382de499ccff12e642c7b5Alan Viverette 1205eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio @Override 1206eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio public boolean onTouch(View v, MotionEvent event) { 1207002f918ceae416ba5c382de499ccff12e642c7b5Alan Viverette if (!mInputEnabled) { 1208eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio return true; 1209eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio } 1210eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 1211002f918ceae416ba5c382de499ccff12e642c7b5Alan Viverette final int action = event.getActionMasked(); 1212002f918ceae416ba5c382de499ccff12e642c7b5Alan Viverette if (action == MotionEvent.ACTION_MOVE 1213002f918ceae416ba5c382de499ccff12e642c7b5Alan Viverette || action == MotionEvent.ACTION_UP 1214002f918ceae416ba5c382de499ccff12e642c7b5Alan Viverette || action == MotionEvent.ACTION_DOWN) { 1215002f918ceae416ba5c382de499ccff12e642c7b5Alan Viverette boolean forceSelection = false; 1216002f918ceae416ba5c382de499ccff12e642c7b5Alan Viverette boolean autoAdvance = false; 1217002f918ceae416ba5c382de499ccff12e642c7b5Alan Viverette 1218002f918ceae416ba5c382de499ccff12e642c7b5Alan Viverette if (action == MotionEvent.ACTION_DOWN) { 1219002f918ceae416ba5c382de499ccff12e642c7b5Alan Viverette // This is a new event stream, reset whether the value changed. 1220002f918ceae416ba5c382de499ccff12e642c7b5Alan Viverette mChangedDuringTouch = false; 1221002f918ceae416ba5c382de499ccff12e642c7b5Alan Viverette } else if (action == MotionEvent.ACTION_UP) { 1222002f918ceae416ba5c382de499ccff12e642c7b5Alan Viverette autoAdvance = true; 1223002f918ceae416ba5c382de499ccff12e642c7b5Alan Viverette 1224002f918ceae416ba5c382de499ccff12e642c7b5Alan Viverette // If we saw a down/up pair without the value changing, assume 1225002f918ceae416ba5c382de499ccff12e642c7b5Alan Viverette // this is a single-tap selection and force a change. 1226002f918ceae416ba5c382de499ccff12e642c7b5Alan Viverette if (!mChangedDuringTouch) { 1227002f918ceae416ba5c382de499ccff12e642c7b5Alan Viverette forceSelection = true; 1228eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio } 1229002f918ceae416ba5c382de499ccff12e642c7b5Alan Viverette } 1230eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 1231002f918ceae416ba5c382de499ccff12e642c7b5Alan Viverette mChangedDuringTouch |= handleTouchInput( 1232002f918ceae416ba5c382de499ccff12e642c7b5Alan Viverette event.getX(), event.getY(), forceSelection, autoAdvance); 1233eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio } 1234002f918ceae416ba5c382de499ccff12e642c7b5Alan Viverette 1235002f918ceae416ba5c382de499ccff12e642c7b5Alan Viverette return true; 1236002f918ceae416ba5c382de499ccff12e642c7b5Alan Viverette } 1237002f918ceae416ba5c382de499ccff12e642c7b5Alan Viverette 1238002f918ceae416ba5c382de499ccff12e642c7b5Alan Viverette private boolean handleTouchInput( 1239002f918ceae416ba5c382de499ccff12e642c7b5Alan Viverette float x, float y, boolean forceSelection, boolean autoAdvance) { 1240002f918ceae416ba5c382de499ccff12e642c7b5Alan Viverette // Calling getDegreesFromXY has side effects, so cache 1241002f918ceae416ba5c382de499ccff12e642c7b5Alan Viverette // whether we used to be on the inner circle. 1242002f918ceae416ba5c382de499ccff12e642c7b5Alan Viverette final boolean wasOnInnerCircle = mIsOnInnerCircle; 1243002f918ceae416ba5c382de499ccff12e642c7b5Alan Viverette final int degrees = getDegreesFromXY(x, y); 1244002f918ceae416ba5c382de499ccff12e642c7b5Alan Viverette if (degrees == -1) { 1245002f918ceae416ba5c382de499ccff12e642c7b5Alan Viverette return false; 1246002f918ceae416ba5c382de499ccff12e642c7b5Alan Viverette } 1247002f918ceae416ba5c382de499ccff12e642c7b5Alan Viverette 1248002f918ceae416ba5c382de499ccff12e642c7b5Alan Viverette final int[] selectionDegrees = mSelectionDegrees; 124911a68e18039b6bb2b67c5f7a82fa13d60583b2c3Alan Viverette final int type; 125011a68e18039b6bb2b67c5f7a82fa13d60583b2c3Alan Viverette final int newValue; 125111a68e18039b6bb2b67c5f7a82fa13d60583b2c3Alan Viverette final boolean valueChanged; 1252002f918ceae416ba5c382de499ccff12e642c7b5Alan Viverette 1253002f918ceae416ba5c382de499ccff12e642c7b5Alan Viverette if (mShowHours) { 1254002f918ceae416ba5c382de499ccff12e642c7b5Alan Viverette final int snapDegrees = snapOnly30s(degrees, 0) % 360; 125511a68e18039b6bb2b67c5f7a82fa13d60583b2c3Alan Viverette valueChanged = selectionDegrees[HOURS] != snapDegrees 1256002f918ceae416ba5c382de499ccff12e642c7b5Alan Viverette || selectionDegrees[HOURS_INNER] != snapDegrees 125711a68e18039b6bb2b67c5f7a82fa13d60583b2c3Alan Viverette || wasOnInnerCircle != mIsOnInnerCircle; 1258002f918ceae416ba5c382de499ccff12e642c7b5Alan Viverette 125911a68e18039b6bb2b67c5f7a82fa13d60583b2c3Alan Viverette selectionDegrees[HOURS] = snapDegrees; 126011a68e18039b6bb2b67c5f7a82fa13d60583b2c3Alan Viverette selectionDegrees[HOURS_INNER] = snapDegrees; 126111a68e18039b6bb2b67c5f7a82fa13d60583b2c3Alan Viverette type = HOURS; 126211a68e18039b6bb2b67c5f7a82fa13d60583b2c3Alan Viverette newValue = getCurrentHour(); 1263002f918ceae416ba5c382de499ccff12e642c7b5Alan Viverette } else { 1264002f918ceae416ba5c382de499ccff12e642c7b5Alan Viverette final int snapDegrees = snapPrefer30s(degrees) % 360; 126511a68e18039b6bb2b67c5f7a82fa13d60583b2c3Alan Viverette valueChanged = selectionDegrees[MINUTES] != snapDegrees; 1266002f918ceae416ba5c382de499ccff12e642c7b5Alan Viverette 126711a68e18039b6bb2b67c5f7a82fa13d60583b2c3Alan Viverette selectionDegrees[MINUTES] = snapDegrees; 126811a68e18039b6bb2b67c5f7a82fa13d60583b2c3Alan Viverette type = MINUTES; 126911a68e18039b6bb2b67c5f7a82fa13d60583b2c3Alan Viverette newValue = getCurrentMinute(); 1270002f918ceae416ba5c382de499ccff12e642c7b5Alan Viverette } 1271002f918ceae416ba5c382de499ccff12e642c7b5Alan Viverette 127211a68e18039b6bb2b67c5f7a82fa13d60583b2c3Alan Viverette if (valueChanged || forceSelection || autoAdvance) { 127311a68e18039b6bb2b67c5f7a82fa13d60583b2c3Alan Viverette // Fire the listener even if we just need to auto-advance. 1274002f918ceae416ba5c382de499ccff12e642c7b5Alan Viverette if (mListener != null) { 1275002f918ceae416ba5c382de499ccff12e642c7b5Alan Viverette mListener.onValueSelected(type, newValue, autoAdvance); 1276002f918ceae416ba5c382de499ccff12e642c7b5Alan Viverette } 127711a68e18039b6bb2b67c5f7a82fa13d60583b2c3Alan Viverette 127811a68e18039b6bb2b67c5f7a82fa13d60583b2c3Alan Viverette // Only provide feedback if the value actually changed. 127911a68e18039b6bb2b67c5f7a82fa13d60583b2c3Alan Viverette if (valueChanged || forceSelection) { 128011a68e18039b6bb2b67c5f7a82fa13d60583b2c3Alan Viverette performHapticFeedback(HapticFeedbackConstants.CLOCK_TICK); 128111a68e18039b6bb2b67c5f7a82fa13d60583b2c3Alan Viverette invalidate(); 128211a68e18039b6bb2b67c5f7a82fa13d60583b2c3Alan Viverette } 1283002f918ceae416ba5c382de499ccff12e642c7b5Alan Viverette return true; 1284002f918ceae416ba5c382de499ccff12e642c7b5Alan Viverette } 1285002f918ceae416ba5c382de499ccff12e642c7b5Alan Viverette 1286002f918ceae416ba5c382de499ccff12e642c7b5Alan Viverette return false; 1287eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio } 1288eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 1289eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio @Override 1290ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette public boolean dispatchHoverEvent(MotionEvent event) { 1291ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette // First right-of-refusal goes the touch exploration helper. 1292ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette if (mTouchHelper.dispatchHoverEvent(event)) { 1293eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio return true; 1294eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio } 1295ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette return super.dispatchHoverEvent(event); 1296eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio } 1297eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 1298ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette public void setInputEnabled(boolean inputEnabled) { 1299ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette mInputEnabled = inputEnabled; 1300ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette invalidate(); 1301ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette } 1302ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette 1303ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette private class RadialPickerTouchHelper extends ExploreByTouchHelper { 1304ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette private final Rect mTempRect = new Rect(); 1305ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette 1306ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette private final int TYPE_HOUR = 1; 1307ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette private final int TYPE_MINUTE = 2; 1308ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette 1309ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette private final int SHIFT_TYPE = 0; 1310ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette private final int MASK_TYPE = 0xF; 1311ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette 1312ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette private final int SHIFT_VALUE = 8; 1313ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette private final int MASK_VALUE = 0xFF; 1314ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette 1315ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette /** Increment in which virtual views are exposed for minutes. */ 1316ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette private final int MINUTE_INCREMENT = 5; 1317ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette 1318ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette public RadialPickerTouchHelper() { 1319ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette super(RadialTimePickerView.this); 1320eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio } 1321eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 1322ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette @Override 1323ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) { 1324ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette super.onInitializeAccessibilityNodeInfo(host, info); 1325ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette 1326ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_FORWARD); 1327ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_BACKWARD); 1328eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio } 1329ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette 1330ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette @Override 1331ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette public boolean performAccessibilityAction(View host, int action, Bundle arguments) { 1332ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette if (super.performAccessibilityAction(host, action, arguments)) { 1333ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette return true; 1334eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio } 1335eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 1336ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette switch (action) { 1337ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette case AccessibilityNodeInfo.ACTION_SCROLL_FORWARD: 1338ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette adjustPicker(1); 1339ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette return true; 1340ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette case AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD: 1341ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette adjustPicker(-1); 1342ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette return true; 1343ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette } 1344ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette 1345ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette return false; 1346ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette } 1347ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette 1348ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette private void adjustPicker(int step) { 1349ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette final int stepSize; 1350ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette final int initialValue; 135167945c11a5e9547f71be91ceb99e7b9ff15a6292Alan Viverette final int maxValue; 1352ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette final int minValue; 1353eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio if (mShowHours) { 1354ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette stepSize = DEGREES_FOR_ONE_HOUR; 1355ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette initialValue = getCurrentHour() % 12; 1356ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette 1357eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio if (mIs24HourMode) { 1358eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio maxValue = 23; 1359ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette minValue = 0; 1360eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio } else { 1361eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio maxValue = 12; 1362eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio minValue = 1; 1363eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio } 1364eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio } else { 1365ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette stepSize = DEGREES_FOR_ONE_MINUTE; 1366ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette initialValue = getCurrentMinute(); 1367ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette 1368eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio maxValue = 55; 1369ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette minValue = 0; 1370eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio } 1371ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette 1372ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette final int steppedValue = snapOnly30s(initialValue * stepSize, step) / stepSize; 1373ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette final int clampedValue = MathUtils.constrain(steppedValue, minValue, maxValue); 1374ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette if (mShowHours) { 1375ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette setCurrentHour(clampedValue); 1376ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette } else { 1377ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette setCurrentMinute(clampedValue); 1378ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette } 1379ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette } 1380ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette 1381ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette @Override 1382ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette protected int getVirtualViewAt(float x, float y) { 1383ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette final int id; 1384ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette final int degrees = getDegreesFromXY(x, y); 1385ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette if (degrees != -1) { 1386ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette final int snapDegrees = snapOnly30s(degrees, 0) % 360; 1387ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette if (mShowHours) { 1388ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette final int hour = getHourForDegrees(snapDegrees, mIsOnInnerCircle); 1389ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette id = makeId(TYPE_HOUR, hour); 1390ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette } else { 1391ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette final int current = getCurrentMinute(); 1392ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette final int touched = getMinuteForDegrees(degrees); 1393ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette final int snapped = getMinuteForDegrees(snapDegrees); 1394ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette 1395ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette // If the touched minute is closer to the current minute 1396ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette // than it is to the snapped minute, return current. 1397ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette final int minute; 1398ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette if (Math.abs(current - touched) < Math.abs(snapped - touched)) { 1399ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette minute = current; 1400ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette } else { 1401ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette minute = snapped; 1402ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette } 1403ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette id = makeId(TYPE_MINUTE, minute); 1404ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette } 1405ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette } else { 1406ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette id = INVALID_ID; 1407eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio } 1408ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette 1409ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette return id; 1410ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette } 1411ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette 1412ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette @Override 1413ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette protected void getVisibleVirtualViews(IntArray virtualViewIds) { 1414eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio if (mShowHours) { 1415ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette final int min = mIs24HourMode ? 0 : 1; 1416ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette final int max = mIs24HourMode ? 23 : 12; 1417ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette for (int i = min; i <= max ; i++) { 1418ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette virtualViewIds.add(makeId(TYPE_HOUR, i)); 1419eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio } 1420eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio } else { 1421ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette final int current = getCurrentMinute(); 1422ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette for (int i = 0; i < 60; i += MINUTE_INCREMENT) { 1423ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette virtualViewIds.add(makeId(TYPE_MINUTE, i)); 1424ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette 1425ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette // If the current minute falls between two increments, 1426ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette // insert an extra node for it. 1427ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette if (current > i && current < i + MINUTE_INCREMENT) { 1428ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette virtualViewIds.add(makeId(TYPE_MINUTE, current)); 1429ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette } 1430eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio } 1431eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio } 1432eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio } 1433eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 1434ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette @Override 1435ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette protected void onPopulateEventForVirtualView(int virtualViewId, AccessibilityEvent event) { 1436ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette event.setClassName(getClass().getName()); 1437eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio 1438ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette final int type = getTypeFromId(virtualViewId); 1439ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette final int value = getValueFromId(virtualViewId); 1440ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette final CharSequence description = getVirtualViewDescription(type, value); 1441ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette event.setContentDescription(description); 1442ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette } 1443ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette 1444ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette @Override 1445ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette protected void onPopulateNodeForVirtualView(int virtualViewId, AccessibilityNodeInfo node) { 1446ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette node.setClassName(getClass().getName()); 1447ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette node.addAction(AccessibilityAction.ACTION_CLICK); 1448ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette 1449ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette final int type = getTypeFromId(virtualViewId); 1450ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette final int value = getValueFromId(virtualViewId); 1451ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette final CharSequence description = getVirtualViewDescription(type, value); 1452ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette node.setContentDescription(description); 1453ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette 1454ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette getBoundsForVirtualView(virtualViewId, mTempRect); 1455ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette node.setBoundsInParent(mTempRect); 1456ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette 1457ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette final boolean selected = isVirtualViewSelected(type, value); 1458ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette node.setSelected(selected); 1459ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette } 1460ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette 1461ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette @Override 1462ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette protected boolean onPerformActionForVirtualView(int virtualViewId, int action, 1463ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette Bundle arguments) { 1464ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette if (action == AccessibilityNodeInfo.ACTION_CLICK) { 1465ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette final int type = getTypeFromId(virtualViewId); 1466ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette final int value = getValueFromId(virtualViewId); 1467ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette if (type == TYPE_HOUR) { 1468ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette final int hour = mIs24HourMode ? value : hour12To24(value, mAmOrPm); 1469ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette setCurrentHour(hour); 1470ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette return true; 1471ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette } else if (type == TYPE_MINUTE) { 1472ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette setCurrentMinute(value); 1473ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette return true; 1474ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette } 1475ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette } 1476ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette return false; 1477ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette } 1478ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette 1479ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette private int hour12To24(int hour12, int amOrPm) { 1480ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette int hour24 = hour12; 1481ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette if (hour12 == 12) { 1482ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette if (amOrPm == AM) { 1483ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette hour24 = 0; 1484ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette } 1485ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette } else if (amOrPm == PM) { 1486ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette hour24 += 12; 1487ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette } 1488ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette return hour24; 1489ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette } 1490ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette 1491ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette private void getBoundsForVirtualView(int virtualViewId, Rect bounds) { 1492ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette final float radius; 1493ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette final int type = getTypeFromId(virtualViewId); 1494ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette final int value = getValueFromId(virtualViewId); 1495ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette final float centerRadius; 1496ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette final float degrees; 1497ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette if (type == TYPE_HOUR) { 1498ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette final boolean innerCircle = mIs24HourMode && value > 0 && value <= 12; 1499ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette if (innerCircle) { 1500ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette centerRadius = mCircleRadius[HOURS_INNER] * mNumbersRadiusMultiplier[HOURS_INNER]; 1501ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette radius = mSelectionRadius[HOURS_INNER]; 1502ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette } else { 1503ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette centerRadius = mCircleRadius[HOURS] * mNumbersRadiusMultiplier[HOURS]; 1504ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette radius = mSelectionRadius[HOURS]; 1505ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette } 1506ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette 1507ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette degrees = getDegreesForHour(value); 1508ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette } else if (type == TYPE_MINUTE) { 1509ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette centerRadius = mCircleRadius[MINUTES] * mNumbersRadiusMultiplier[MINUTES]; 1510ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette degrees = getDegreesForMinute(value); 1511ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette radius = mSelectionRadius[MINUTES]; 1512ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette } else { 1513ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette // This should never happen. 1514ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette centerRadius = 0; 1515ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette degrees = 0; 1516ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette radius = 0; 1517ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette } 1518ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette 1519ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette final double radians = Math.toRadians(degrees); 1520ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette final float xCenter = mXCenter + centerRadius * (float) Math.sin(radians); 1521ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette final float yCenter = mYCenter - centerRadius * (float) Math.cos(radians); 1522ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette 1523ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette bounds.set((int) (xCenter - radius), (int) (yCenter - radius), 1524ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette (int) (xCenter + radius), (int) (yCenter + radius)); 1525ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette } 1526ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette 1527ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette private CharSequence getVirtualViewDescription(int type, int value) { 1528ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette final CharSequence description; 1529ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette if (type == TYPE_HOUR || type == TYPE_MINUTE) { 1530ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette description = Integer.toString(value); 1531ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette } else { 1532ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette description = null; 1533ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette } 1534ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette return description; 1535ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette } 1536ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette 1537ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette private boolean isVirtualViewSelected(int type, int value) { 1538ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette final boolean selected; 1539ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette if (type == TYPE_HOUR) { 1540ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette selected = getCurrentHour() == value; 1541ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette } else if (type == TYPE_MINUTE) { 1542ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette selected = getCurrentMinute() == value; 1543ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette } else { 1544ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette selected = false; 1545ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette } 1546ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette return selected; 1547ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette } 1548ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette 1549ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette private int makeId(int type, int value) { 1550ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette return type << SHIFT_TYPE | value << SHIFT_VALUE; 1551ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette } 1552ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette 1553ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette private int getTypeFromId(int id) { 1554ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette return id >>> SHIFT_TYPE & MASK_TYPE; 1555ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette } 1556ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette 1557ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette private int getValueFromId(int id) { 1558ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette return id >>> SHIFT_VALUE & MASK_VALUE; 1559ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette } 1560eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio } 1561eb1d3798e37572ca515aad572350f5745adf023dAlan Viverette 1562eb1d3798e37572ca515aad572350f5745adf023dAlan Viverette private static class IntHolder { 1563eb1d3798e37572ca515aad572350f5745adf023dAlan Viverette private int mValue; 1564eb1d3798e37572ca515aad572350f5745adf023dAlan Viverette 1565eb1d3798e37572ca515aad572350f5745adf023dAlan Viverette public IntHolder(int value) { 1566eb1d3798e37572ca515aad572350f5745adf023dAlan Viverette mValue = value; 1567eb1d3798e37572ca515aad572350f5745adf023dAlan Viverette } 1568eb1d3798e37572ca515aad572350f5745adf023dAlan Viverette 1569eb1d3798e37572ca515aad572350f5745adf023dAlan Viverette public void setValue(int value) { 1570eb1d3798e37572ca515aad572350f5745adf023dAlan Viverette mValue = value; 1571eb1d3798e37572ca515aad572350f5745adf023dAlan Viverette } 1572eb1d3798e37572ca515aad572350f5745adf023dAlan Viverette 1573eb1d3798e37572ca515aad572350f5745adf023dAlan Viverette public int getValue() { 1574eb1d3798e37572ca515aad572350f5745adf023dAlan Viverette return mValue; 1575eb1d3798e37572ca515aad572350f5745adf023dAlan Viverette } 1576eb1d3798e37572ca515aad572350f5745adf023dAlan Viverette } 1577eeff63a5c347f282b5c8c3ae6a0924bf03fbce8fFabrice Di Meglio} 1578