AmPmCirclesView.java revision d5ec70d18c6379015acd4725b8804ab79f30bfa0
1/*
2 * Copyright (C) 2013 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.datetimepicker.time;
18
19import android.content.Context;
20import android.content.res.Resources;
21import android.graphics.Canvas;
22import android.graphics.Paint;
23import android.graphics.Typeface;
24import android.graphics.Paint.Align;
25import android.util.Log;
26import android.view.View;
27
28import com.android.datetimepicker.R;
29
30import java.text.DateFormatSymbols;
31
32/**
33 * Draw the two smaller AM and PM circles next to where the larger circle will be.
34 */
35public class AmPmCirclesView extends View {
36    private static final String TAG = "AmPmCirclesView";
37
38    // Alpha level of blue color for selected circle.
39    private static final int SELECTED_ALPHA = 51;
40    // Alpha level of blue color for pressed circle.
41    private static final int PRESSED_ALPHA = 175;
42
43    private final Paint mPaint = new Paint();
44    private int mWhite;
45    private int mAmPmTextColor;
46    private int mBlue;
47    private float mCircleRadiusMultiplier;
48    private float mAmPmCircleRadiusMultiplier;
49    private String mAmText;
50    private String mPmText;
51    private boolean mIsInitialized;
52
53    private static final int AM = TimePickerDialog.AM;
54    private static final int PM = TimePickerDialog.PM;
55
56    private boolean mDrawValuesReady;
57    private int mAmPmCircleRadius;
58    private int mAmXCenter;
59    private int mPmXCenter;
60    private int mAmPmYCenter;
61    private int mAmOrPm;
62    private int mAmOrPmPressed;
63
64    public AmPmCirclesView(Context context) {
65        super(context);
66        mIsInitialized = false;
67    }
68
69    public void initialize(Context context, int amOrPm) {
70        if (mIsInitialized) {
71            Log.e(TAG, "AmPmCirclesView may only be initialized once.");
72            return;
73        }
74
75        Resources res = context.getResources();
76        mWhite = res.getColor(R.color.white);
77        mAmPmTextColor = res.getColor(R.color.ampm_text_color);
78        mBlue = res.getColor(R.color.blue);
79        String typefaceFamily = res.getString(R.string.sans_serif);
80        Typeface tf = Typeface.create(typefaceFamily, Typeface.NORMAL);
81        mPaint.setTypeface(tf);
82        mPaint.setAntiAlias(true);
83        mPaint.setTextAlign(Align.CENTER);
84
85        mCircleRadiusMultiplier =
86                Float.parseFloat(res.getString(R.string.circle_radius_multiplier));
87        mAmPmCircleRadiusMultiplier =
88                Float.parseFloat(res.getString(R.string.ampm_circle_radius_multiplier));
89        String[] amPmTexts = new DateFormatSymbols().getAmPmStrings();
90        mAmText = amPmTexts[0];
91        mPmText = amPmTexts[1];
92
93        setAmOrPm(amOrPm);
94        mAmOrPmPressed = -1;
95
96        mIsInitialized = true;
97    }
98
99    public void setAmOrPm(int amOrPm) {
100        mAmOrPm = amOrPm;
101    }
102
103    public void setAmOrPmPressed(int amOrPmPressed) {
104        mAmOrPmPressed = amOrPmPressed;
105    }
106
107    /**
108     * Calculate whether the coordinates are touching the AM or PM circle.
109     */
110    public int getIsTouchingAmOrPm(float xCoord, float yCoord) {
111        if (!mDrawValuesReady) {
112            return -1;
113        }
114
115        int squaredYDistance = (int) ((yCoord - mAmPmYCenter)*(yCoord - mAmPmYCenter));
116
117        int distanceToAmCenter =
118                (int) Math.sqrt((xCoord - mAmXCenter)*(xCoord - mAmXCenter) + squaredYDistance);
119        if (distanceToAmCenter <= mAmPmCircleRadius) {
120            return AM;
121        }
122
123        int distanceToPmCenter =
124                (int) Math.sqrt((xCoord - mPmXCenter)*(xCoord - mPmXCenter) + squaredYDistance);
125        if (distanceToPmCenter <= mAmPmCircleRadius) {
126            return PM;
127        }
128
129        // Neither was close enough.
130        return -1;
131    }
132
133    @Override
134    public void onDraw(Canvas canvas) {
135        int viewWidth = getWidth();
136        if (viewWidth == 0 || !mIsInitialized) {
137            return;
138        }
139
140        if (!mDrawValuesReady) {
141            int layoutXCenter = getWidth() / 2;
142            int layoutYCenter = getHeight() / 2;
143            int circleRadius =
144                    (int) (Math.min(layoutXCenter, layoutYCenter) * mCircleRadiusMultiplier);
145            mAmPmCircleRadius = (int) (circleRadius * mAmPmCircleRadiusMultiplier);
146            int textSize = mAmPmCircleRadius * 3 / 4;
147            mPaint.setTextSize(textSize);
148
149            // Line up the vertical center of the AM/PM circles with the bottom of the main circle.
150            mAmPmYCenter = layoutYCenter - mAmPmCircleRadius / 2 + circleRadius;
151            // Line up the horizontal edges of the AM/PM circles with the horizontal edges
152            // of the main circle.
153            mAmXCenter = layoutXCenter - circleRadius + mAmPmCircleRadius;
154            mPmXCenter = layoutXCenter + circleRadius - mAmPmCircleRadius;
155
156            mDrawValuesReady = true;
157        }
158
159        // We'll need to draw either a lighter blue (for selection), a darker blue (for touching)
160        // or white (for not selected).
161        int amColor = mWhite;
162        int amAlpha = 255;
163        int pmColor = mWhite;
164        int pmAlpha = 255;
165        if (mAmOrPm == AM) {
166            amColor = mBlue;
167            amAlpha = SELECTED_ALPHA;
168        } else if (mAmOrPm == PM) {
169            pmColor = mBlue;
170            pmAlpha = SELECTED_ALPHA;
171        }
172        if (mAmOrPmPressed == AM) {
173            amColor = mBlue;
174            amAlpha = PRESSED_ALPHA;
175        } else if (mAmOrPmPressed == PM) {
176            pmColor = mBlue;
177            pmAlpha = PRESSED_ALPHA;
178        }
179
180        // Draw the two circles.
181        mPaint.setColor(amColor);
182        mPaint.setAlpha(amAlpha);
183        canvas.drawCircle(mAmXCenter, mAmPmYCenter, mAmPmCircleRadius, mPaint);
184        mPaint.setColor(pmColor);
185        mPaint.setAlpha(pmAlpha);
186        canvas.drawCircle(mPmXCenter, mAmPmYCenter, mAmPmCircleRadius, mPaint);
187
188        // Draw the AM/PM texts on top.
189        mPaint.setColor(mAmPmTextColor);
190        int textYCenter = mAmPmYCenter - (int) (mPaint.descent() + mPaint.ascent()) / 2;
191        canvas.drawText(mAmText, mAmXCenter, textYCenter, mPaint);
192        canvas.drawText(mPmText, mPmXCenter, textYCenter, mPaint);
193    }
194}
195