PolarClockWallpaper.java revision 2eee327ccceaf0eac8c65e962e1a6ba948b37967
1/*
2 * Copyright (C) 2009 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.wallpaper.polarclock;
18
19import android.service.wallpaper.WallpaperService;
20import android.graphics.Canvas;
21import android.graphics.Rect;
22import android.graphics.Paint;
23import android.graphics.Color;
24import android.graphics.RectF;
25import android.view.SurfaceHolder;
26import android.content.IntentFilter;
27import android.content.Intent;
28import android.content.BroadcastReceiver;
29import android.content.Context;
30import android.os.Handler;
31import android.os.SystemClock;
32import android.text.format.Time;
33
34import java.util.TimeZone;
35
36public class PolarClockWallpaper extends WallpaperService {
37    private final Handler mHandler = new Handler();
38    private final Runnable mDrawClock = new Runnable() {
39        public void run() {
40            mEngine.drawFrame(true);
41        }
42    };
43
44    private boolean mWatcherRegistered;
45    private TimeWatcher mWatcher;
46    private IntentFilter mFilter;
47    private ClockEngine mEngine;
48
49    @Override
50    public void onCreate() {
51        super.onCreate();
52
53        mFilter = new IntentFilter();
54        mFilter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
55
56        mWatcher = new TimeWatcher();
57    }
58
59    @Override
60    public void onDestroy() {
61        super.onDestroy();
62        if (mWatcherRegistered) {
63            mWatcherRegistered = false;
64            unregisterReceiver(mWatcher);
65        }
66        mHandler.removeCallbacks(mDrawClock);
67    }
68
69    public Engine onCreateEngine() {
70        mEngine = new ClockEngine();
71        return mEngine;
72    }
73
74    class TimeWatcher extends BroadcastReceiver {
75        public void onReceive(Context context, Intent intent) {
76            final String timeZone = intent.getStringExtra("time-zone");
77            mEngine.mCalendar = new Time(TimeZone.getTimeZone(timeZone).getID());
78            mEngine.drawFrame(true);
79        }
80    }
81
82    class ClockEngine extends Engine {
83        private static final float SATURATION = 0.8f;
84        private static final float BRIGHTNESS = 0.9f;
85
86        private static final float RING_THICKNESS = 24.0f;
87        private static final float SMALL_GAP = 14.0f;
88        private static final float LARGE_GAP = 38.0f;
89
90        private static final int COLORS_CACHE_COUNT = 720;
91
92        private float mStartTime;
93        private Time mCalendar;
94
95        private final Paint mPaint = new Paint();
96        private final RectF mRect = new RectF();
97        private final int[] mColors;
98
99        ClockEngine() {
100            mColors = new int[COLORS_CACHE_COUNT];
101
102            final int[] colors = mColors;
103            final int count = colors.length;
104
105            for (int i = 0; i < count; i++) {
106                colors[i] = Color.HSBtoColor(i / (float) COLORS_CACHE_COUNT, SATURATION, BRIGHTNESS);
107            }
108        }
109
110        @Override
111        public void onCreate(SurfaceHolder surfaceHolder) {
112            super.onCreate(surfaceHolder);
113
114            mCalendar = new Time();
115            mCalendar.setToNow();
116            mStartTime = mCalendar.second * 1000.0f;
117
118            final Paint paint = mPaint;
119            paint.setAntiAlias(true);
120            paint.setStrokeWidth(RING_THICKNESS);
121            paint.setStrokeCap(Paint.Cap.ROUND);
122            paint.setStyle(Paint.Style.STROKE);
123        }
124
125        @Override
126        public void onVisibilityChanged(boolean visible) {
127            if (visible) {
128                if (!mWatcherRegistered) {
129                    mWatcherRegistered = true;
130                    registerReceiver(mWatcher, mFilter, null, mHandler);
131                }
132                mCalendar = new Time();
133                mCalendar.setToNow();
134                mStartTime = mCalendar.second * 1000.0f;
135            } else {
136                if (mWatcherRegistered) {
137                    mWatcherRegistered = false;
138                    unregisterReceiver(mWatcher);
139                }
140                mHandler.removeCallbacks(mDrawClock);
141            }
142            drawFrame(visible);
143        }
144
145        @Override
146        public void onSurfaceChanged(SurfaceHolder holder, int format, int width, int height) {
147            super.onSurfaceChanged(holder, format, width, height);
148            drawFrame(true);
149        }
150
151        @Override
152        public void onSurfaceCreated(SurfaceHolder holder) {
153            super.onSurfaceCreated(holder);
154        }
155
156        @Override
157        public void onSurfaceDestroyed(SurfaceHolder holder) {
158            super.onSurfaceDestroyed(holder);
159            drawFrame(false);
160        }
161
162        void drawFrame(boolean redraw) {
163            final SurfaceHolder holder = getSurfaceHolder();
164            final Rect frame = holder.getSurfaceFrame();
165            final int width = frame.width();
166            final int height = frame.height();
167
168            Canvas c = null;
169            try {
170                c = holder.lockCanvas();
171                if (c != null) {
172                    final Time calendar = mCalendar;
173                    final Paint paint = mPaint;
174                    final int[] colors = mColors;
175
176                    calendar.setToNow();
177                    calendar.normalize(false);
178
179                    c.drawColor(0xffffffff);
180                    c.translate(width / 2.0f, height/ 2.0f);
181                    c.rotate(-90.0f);
182
183                    // Draw seconds
184                    float size = width / 2.0f / 2.0f - RING_THICKNESS;
185                    final RectF rect = mRect;
186                    rect.set(-size, -size, size, size);
187
188                    float angle = ((mStartTime + SystemClock.elapsedRealtime()) % 60000) / 60000.0f;
189                    paint.setColor(colors[((int) (angle * COLORS_CACHE_COUNT))]);
190                    c.drawArc(rect, 0.0f, angle * 360.0f, false, paint);
191
192                    // Draw minutes
193                    size -= (SMALL_GAP + RING_THICKNESS);
194                    rect.set(-size, -size, size, size);
195
196                    angle = ((calendar.minute * 60.0f + calendar.second) % 3600) / 3600.0f;
197                    paint.setColor(colors[((int) (angle * COLORS_CACHE_COUNT))]);
198                    c.drawArc(rect, 0.0f, angle * 360.0f, false, paint);
199
200                    // Draw hours
201                    size -= (SMALL_GAP + RING_THICKNESS);
202                    rect.set(-size, -size, size, size);
203
204                    angle = ((calendar.hour * 60.0f + calendar.minute) % 1440) / 1440.0f;
205                    paint.setColor(colors[((int) (angle * COLORS_CACHE_COUNT))]);
206                    c.drawArc(rect, 0.0f, angle * 360.0f, false, paint);
207
208                    // Draw day
209                    size -= (LARGE_GAP + RING_THICKNESS);
210                    rect.set(-size, -size, size, size);
211
212                    angle = (calendar.monthDay - 1) /
213                            (float) (calendar.getActualMaximum(Time.MONTH_DAY) - 1);
214                    paint.setColor(colors[((int) (angle * COLORS_CACHE_COUNT))]);
215                    c.drawArc(rect, 0.0f, angle * 360.0f, false, paint);
216
217                    // Draw month
218                    size -= (SMALL_GAP + RING_THICKNESS);
219                    rect.set(-size, -size, size, size);
220
221                    angle = (calendar.month - 1) / 11.0f;
222                    paint.setColor(colors[((int) (angle * COLORS_CACHE_COUNT))]);
223                    c.drawArc(rect, 0.0f, angle * 360.0f, false, paint);
224                }
225            } finally {
226                if (c != null) holder.unlockCanvasAndPost(c);
227            }
228
229            mHandler.removeCallbacks(mDrawClock);
230            if (redraw) {
231                mHandler.postDelayed(mDrawClock, 1000 / 25);
232            }
233        }
234    }
235}
236