Initial Contribution
This commit is contained in:
332
samples/GlobalTime/src/com/android/globaltime/Clock.java
Normal file
332
samples/GlobalTime/src/com/android/globaltime/Clock.java
Normal file
@@ -0,0 +1,332 @@
|
||||
/*
|
||||
* Copyright (C) 2007 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.globaltime;
|
||||
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Path;
|
||||
import android.graphics.RectF;
|
||||
import android.pim.DateUtils;
|
||||
import android.view.animation.AccelerateDecelerateInterpolator;
|
||||
import android.view.animation.Interpolator;
|
||||
|
||||
/**
|
||||
* A class that draws an analog clock face with information about the current
|
||||
* time in a given city.
|
||||
*/
|
||||
public class Clock {
|
||||
|
||||
static final int MILLISECONDS_PER_MINUTE = 60 * 1000;
|
||||
static final int MILLISECONDS_PER_HOUR = 60 * 60 * 1000;
|
||||
|
||||
private City mCity = null;
|
||||
private long mCitySwitchTime;
|
||||
private long mTime;
|
||||
|
||||
private float mColorRed = 1.0f;
|
||||
private float mColorGreen = 1.0f;
|
||||
private float mColorBlue = 1.0f;
|
||||
|
||||
private long mOldOffset;
|
||||
|
||||
private Interpolator mClockHandInterpolator =
|
||||
new AccelerateDecelerateInterpolator();
|
||||
|
||||
public Clock() {
|
||||
// Empty constructor
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a line to the given Path. The line extends from
|
||||
* radius r0 to radius r1 about the center point (cx, cy),
|
||||
* at an angle given by pos.
|
||||
*
|
||||
* @param path the Path to draw to
|
||||
* @param radius the radius of the outer rim of the clock
|
||||
* @param pos the angle, with 0 and 1 at 12:00
|
||||
* @param cx the X coordinate of the clock center
|
||||
* @param cy the Y coordinate of the clock center
|
||||
* @param r0 the starting radius for the line
|
||||
* @param r1 the ending radius for the line
|
||||
*/
|
||||
private static void drawLine(Path path,
|
||||
float radius, float pos, float cx, float cy, float r0, float r1) {
|
||||
float theta = pos * Shape.TWO_PI - Shape.PI_OVER_TWO;
|
||||
float dx = (float) Math.cos(theta);
|
||||
float dy = (float) Math.sin(theta);
|
||||
float p0x = cx + dx * r0;
|
||||
float p0y = cy + dy * r0;
|
||||
float p1x = cx + dx * r1;
|
||||
float p1y = cy + dy * r1;
|
||||
|
||||
float ox = (p1y - p0y);
|
||||
float oy = -(p1x - p0x);
|
||||
|
||||
float norm = (radius / 2.0f) / (float) Math.sqrt(ox * ox + oy * oy);
|
||||
ox *= norm;
|
||||
oy *= norm;
|
||||
|
||||
path.moveTo(p0x - ox, p0y - oy);
|
||||
path.lineTo(p1x - ox, p1y - oy);
|
||||
path.lineTo(p1x + ox, p1y + oy);
|
||||
path.lineTo(p0x + ox, p0y + oy);
|
||||
path.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a vertical arrow to the given Path.
|
||||
*
|
||||
* @param path the Path to draw to
|
||||
*/
|
||||
private static void drawVArrow(Path path,
|
||||
float cx, float cy, float width, float height) {
|
||||
path.moveTo(cx - width / 2.0f, cy);
|
||||
path.lineTo(cx, cy + height);
|
||||
path.lineTo(cx + width / 2.0f, cy);
|
||||
path.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a horizontal arrow to the given Path.
|
||||
*
|
||||
* @param path the Path to draw to
|
||||
*/
|
||||
private static void drawHArrow(Path path,
|
||||
float cx, float cy, float width, float height) {
|
||||
path.moveTo(cx, cy - height / 2.0f);
|
||||
path.lineTo(cx + width, cy);
|
||||
path.lineTo(cx, cy + height / 2.0f);
|
||||
path.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an offset in milliseconds to be subtracted from the current time
|
||||
* in order to obtain an smooth interpolation between the previously
|
||||
* displayed time and the current time.
|
||||
*/
|
||||
private long getOffset(float lerp) {
|
||||
long doffset = (long) (mCity.getOffset() *
|
||||
(float) MILLISECONDS_PER_HOUR - mOldOffset);
|
||||
int sign;
|
||||
if (doffset < 0) {
|
||||
doffset = -doffset;
|
||||
sign = -1;
|
||||
} else {
|
||||
sign = 1;
|
||||
}
|
||||
|
||||
while (doffset > 12L * MILLISECONDS_PER_HOUR) {
|
||||
doffset -= 12L * MILLISECONDS_PER_HOUR;
|
||||
}
|
||||
if (doffset > 6L * MILLISECONDS_PER_HOUR) {
|
||||
doffset = 12L * MILLISECONDS_PER_HOUR - doffset;
|
||||
sign = -sign;
|
||||
}
|
||||
|
||||
// Interpolate doffset towards 0
|
||||
doffset = (long)((1.0f - lerp)*doffset);
|
||||
|
||||
// Keep the same seconds count
|
||||
long dh = doffset / (MILLISECONDS_PER_HOUR);
|
||||
doffset -= dh * MILLISECONDS_PER_HOUR;
|
||||
long dm = doffset / MILLISECONDS_PER_MINUTE;
|
||||
doffset = sign * (60 * dh + dm) * MILLISECONDS_PER_MINUTE;
|
||||
|
||||
return doffset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the city to be displayed. setCity(null) resets things so the clock
|
||||
* hand animation won't occur next time.
|
||||
*/
|
||||
public void setCity(City city) {
|
||||
if (mCity != city) {
|
||||
if (mCity != null) {
|
||||
mOldOffset =
|
||||
(long) (mCity.getOffset() * (float) MILLISECONDS_PER_HOUR);
|
||||
} else if (city != null) {
|
||||
mOldOffset =
|
||||
(long) (city.getOffset() * (float) MILLISECONDS_PER_HOUR);
|
||||
} else {
|
||||
mOldOffset = 0L; // this will never be used
|
||||
}
|
||||
this.mCitySwitchTime = System.currentTimeMillis();
|
||||
this.mCity = city;
|
||||
}
|
||||
}
|
||||
|
||||
public void setTime(long time) {
|
||||
this.mTime = time;
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws the clock face.
|
||||
*
|
||||
* @param canvas the Canvas to draw to
|
||||
* @param cx the X coordinate of the clock center
|
||||
* @param cy the Y coordinate of the clock center
|
||||
* @param radius the radius of the clock face
|
||||
* @param alpha the translucency of the clock face
|
||||
* @param textAlpha the translucency of the text
|
||||
* @param showCityName if true, display the city name
|
||||
* @param showTime if true, display the time digitally
|
||||
* @param showUpArrow if true, display an up arrow
|
||||
* @param showDownArrow if true, display a down arrow
|
||||
* @param showLeftRightArrows if true, display left and right arrows
|
||||
* @param prefixChars number of characters of the city name to draw in bold
|
||||
*/
|
||||
public void drawClock(Canvas canvas,
|
||||
float cx, float cy, float radius, float alpha, float textAlpha,
|
||||
boolean showCityName, boolean showTime,
|
||||
boolean showUpArrow, boolean showDownArrow, boolean showLeftRightArrows,
|
||||
int prefixChars) {
|
||||
Paint paint = new Paint();
|
||||
paint.setAntiAlias(true);
|
||||
|
||||
int iradius = (int)radius;
|
||||
|
||||
TimeZone tz = mCity.getTimeZone();
|
||||
|
||||
// Compute an interpolated time to animate between the previously
|
||||
// displayed time and the current time
|
||||
float lerp = Math.min(1.0f,
|
||||
(System.currentTimeMillis() - mCitySwitchTime) / 500.0f);
|
||||
lerp = mClockHandInterpolator.getInterpolation(lerp);
|
||||
long doffset = lerp < 1.0f ? getOffset(lerp) : 0L;
|
||||
|
||||
// Determine the interpolated time for the given time zone
|
||||
Calendar cal = Calendar.getInstance(tz);
|
||||
cal.setTimeInMillis(mTime - doffset);
|
||||
int hour = cal.get(Calendar.HOUR_OF_DAY);
|
||||
int minute = cal.get(Calendar.MINUTE);
|
||||
int second = cal.get(Calendar.SECOND);
|
||||
int milli = cal.get(Calendar.MILLISECOND);
|
||||
|
||||
float offset = tz.getRawOffset() / (float) MILLISECONDS_PER_HOUR;
|
||||
float daylightOffset = tz.inDaylightTime(new Date(mTime)) ?
|
||||
tz.getDSTSavings() / (float) MILLISECONDS_PER_HOUR : 0.0f;
|
||||
|
||||
float absOffset = offset < 0 ? -offset : offset;
|
||||
int offsetH = (int) absOffset;
|
||||
int offsetM = (int) (60.0f * (absOffset - offsetH));
|
||||
hour %= 12;
|
||||
|
||||
// Get the city name and digital time strings
|
||||
String cityName = mCity.getName();
|
||||
cal.setTimeInMillis(mTime);
|
||||
String time = DateUtils.timeString(cal.getTimeInMillis()) + " " +
|
||||
DateUtils.getDayOfWeekString(cal.get(Calendar.DAY_OF_WEEK),
|
||||
DateUtils.LENGTH_SHORT) + " " +
|
||||
" (UTC" +
|
||||
(offset >= 0 ? "+" : "-") +
|
||||
offsetH +
|
||||
(offsetM == 0 ? "" : ":" + offsetM) +
|
||||
(daylightOffset == 0 ? "" : "+" + daylightOffset) +
|
||||
")";
|
||||
|
||||
float th = paint.getTextSize();
|
||||
float tw;
|
||||
|
||||
// Set the text color
|
||||
paint.setARGB((int) (textAlpha * 255.0f),
|
||||
(int) (mColorRed * 255.0f),
|
||||
(int) (mColorGreen * 255.0f),
|
||||
(int) (mColorBlue * 255.0f));
|
||||
|
||||
tw = paint.measureText(cityName);
|
||||
if (showCityName) {
|
||||
// Increment prefixChars to include any spaces
|
||||
for (int i = 0; i < prefixChars; i++) {
|
||||
if (cityName.charAt(i) == ' ') {
|
||||
++prefixChars;
|
||||
}
|
||||
}
|
||||
|
||||
// Draw the city name
|
||||
canvas.drawText(cityName, cx - tw / 2, cy - radius - th, paint);
|
||||
// Overstrike the first 'prefixChars' characters
|
||||
canvas.drawText(cityName.substring(0, prefixChars),
|
||||
cx - tw / 2 + 1, cy - radius - th, paint);
|
||||
}
|
||||
tw = paint.measureText(time);
|
||||
if (showTime) {
|
||||
canvas.drawText(time, cx - tw / 2, cy + radius + th + 5, paint);
|
||||
}
|
||||
|
||||
paint.setARGB((int)(alpha * 255.0f),
|
||||
(int)(mColorRed * 255.0f),
|
||||
(int)(mColorGreen * 255.0f),
|
||||
(int)(mColorBlue * 255.0f));
|
||||
|
||||
paint.setStyle(Paint.Style.FILL);
|
||||
canvas.drawOval(new RectF(cx - 2, cy - 2, cx + 2, cy + 2), paint);
|
||||
|
||||
paint.setStyle(Paint.Style.STROKE);
|
||||
paint.setStrokeWidth(radius * 0.12f);
|
||||
|
||||
canvas.drawOval(new RectF(cx - iradius, cy - iradius,
|
||||
cx + iradius, cy + iradius),
|
||||
paint);
|
||||
|
||||
float r0 = radius * 0.1f;
|
||||
float r1 = radius * 0.4f;
|
||||
float r2 = radius * 0.6f;
|
||||
float r3 = radius * 0.65f;
|
||||
float r4 = radius * 0.7f;
|
||||
float r5 = radius * 0.9f;
|
||||
|
||||
Path path = new Path();
|
||||
|
||||
float ss = second + milli / 1000.0f;
|
||||
float mm = minute + ss / 60.0f;
|
||||
float hh = hour + mm / 60.0f;
|
||||
|
||||
// Tics for the hours
|
||||
for (int i = 0; i < 12; i++) {
|
||||
drawLine(path, radius * 0.12f, i / 12.0f, cx, cy, r4, r5);
|
||||
}
|
||||
|
||||
// Hour hand
|
||||
drawLine(path, radius * 0.12f, hh / 12.0f, cx, cy, r0, r1);
|
||||
// Minute hand
|
||||
drawLine(path, radius * 0.12f, mm / 60.0f, cx, cy, r0, r2);
|
||||
// Second hand
|
||||
drawLine(path, radius * 0.036f, ss / 60.0f, cx, cy, r0, r3);
|
||||
|
||||
if (showUpArrow) {
|
||||
drawVArrow(path, cx + radius * 1.13f, cy - radius,
|
||||
radius * 0.15f, -radius * 0.1f);
|
||||
}
|
||||
if (showDownArrow) {
|
||||
drawVArrow(path, cx + radius * 1.13f, cy + radius,
|
||||
radius * 0.15f, radius * 0.1f);
|
||||
}
|
||||
if (showLeftRightArrows) {
|
||||
drawHArrow(path, cx - radius * 1.3f, cy, -radius * 0.1f,
|
||||
radius * 0.15f);
|
||||
drawHArrow(path, cx + radius * 1.3f, cy, radius * 0.1f,
|
||||
radius * 0.15f);
|
||||
}
|
||||
|
||||
paint.setStyle(Paint.Style.FILL);
|
||||
canvas.drawPath(path, paint);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user