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