FileDocCategorySizeDatePackage
Clock.javaAPI DocAndroid 1.5 API11512Wed May 06 22:41:08 BST 2009com.android.globaltime

Clock

public class Clock extends Object
A class that draws an analog clock face with information about the current time in a given city.

Fields Summary
static final int
MILLISECONDS_PER_MINUTE
static final int
MILLISECONDS_PER_HOUR
private City
mCity
private long
mCitySwitchTime
private long
mTime
private float
mColorRed
private float
mColorGreen
private float
mColorBlue
private long
mOldOffset
private android.view.animation.Interpolator
mClockHandInterpolator
Constructors Summary
public Clock()


      
        // Empty constructor
    
Methods Summary
public voiddrawClock(android.graphics.Canvas canvas, float cx, float cy, float radius, float alpha, float textAlpha, boolean showCityName, boolean showTime, boolean showUpArrow, boolean showDownArrow, boolean showLeftRightArrows, int prefixChars)
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

        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);
    
private static voiddrawHArrow(android.graphics.Path path, float cx, float cy, float width, float height)
Adds a horizontal arrow to the given Path.

param
path the Path to draw to

        path.moveTo(cx, cy - height / 2.0f);
        path.lineTo(cx + width, cy);
        path.lineTo(cx, cy + height / 2.0f);
        path.close();
    
private static voiddrawLine(android.graphics.Path path, float radius, float pos, float cx, float cy, float r0, float r1)
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

        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();
    
private static voiddrawVArrow(android.graphics.Path path, float cx, float cy, float width, float height)
Adds a vertical arrow to the given Path.

param
path the Path to draw to

        path.moveTo(cx - width / 2.0f, cy);
        path.lineTo(cx, cy + height);
        path.lineTo(cx + width / 2.0f, cy);
        path.close();
    
private longgetOffset(float lerp)
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.

        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;
    
public voidsetCity(City city)
Set the city to be displayed. setCity(null) resets things so the clock hand animation won't occur next time.

        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 voidsetTime(long time)

        this.mTime = time;