1a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy/* 2a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy * Copyright (C) 2009 The Android Open Source Project 3a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy * 4a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy * Licensed under the Apache License, Version 2.0 (the "License"); 5a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy * you may not use this file except in compliance with the License. 6a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy * You may obtain a copy of the License at 7a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy * 8a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy * http://www.apache.org/licenses/LICENSE-2.0 9a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy * 10a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy * Unless required by applicable law or agreed to in writing, software 11a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy * distributed under the License is distributed on an "AS IS" BASIS, 12a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy * See the License for the specific language governing permissions and 14a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy * limitations under the License. 15a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy */ 16a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy 17a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guypackage com.android.wallpaper.polarclock; 18a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy 19a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guyimport android.service.wallpaper.WallpaperService; 20a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guyimport android.graphics.Canvas; 21a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guyimport android.graphics.Rect; 22a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guyimport android.graphics.Paint; 23a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guyimport android.graphics.Color; 24a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guyimport android.graphics.RectF; 25a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guyimport android.view.SurfaceHolder; 26a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guyimport android.content.IntentFilter; 27a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guyimport android.content.Intent; 28a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guyimport android.content.BroadcastReceiver; 29a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guyimport android.content.Context; 300e1eb1a99bf6b95cebdcf9a1d855f4d4bc2a733dDianne Hackbornimport android.content.SharedPreferences; 3103e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandlerimport android.content.res.XmlResourceParser; 3203e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler 33a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guyimport android.os.Handler; 34a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guyimport android.os.SystemClock; 35a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guyimport android.text.format.Time; 36913771d67c494d1e311a58febbf8e7b9017e0a3bRomain Guyimport android.util.MathUtils; 372d42794e6237a56d2d7518a8b9dba27e3e818d31Romain Guyimport android.util.Log; 38a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy 3903e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandlerimport java.util.HashMap; 40a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guyimport java.util.TimeZone; 4103e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandlerimport java.io.IOException; 4203e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler 4303e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandlerimport org.xmlpull.v1.XmlPullParserException; 4403e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandlerimport static org.xmlpull.v1.XmlPullParser.*; 4503e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler 4603e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandlerimport com.android.wallpaper.R; 47a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy 48a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guypublic class PolarClockWallpaper extends WallpaperService { 492d42794e6237a56d2d7518a8b9dba27e3e818d31Romain Guy private static final String LOG_TAG = "PolarClock"; 502d42794e6237a56d2d7518a8b9dba27e3e818d31Romain Guy 512d42794e6237a56d2d7518a8b9dba27e3e818d31Romain Guy static final String SHARED_PREFS_NAME = "polar_clock_settings"; 5203e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler 532d42794e6237a56d2d7518a8b9dba27e3e818d31Romain Guy static final String PREF_SHOW_SECONDS = "show_seconds"; 542d42794e6237a56d2d7518a8b9dba27e3e818d31Romain Guy static final String PREF_VARIABLE_LINE_WIDTH = "variable_line_width"; 552d42794e6237a56d2d7518a8b9dba27e3e818d31Romain Guy static final String PREF_PALETTE = "palette"; 564ba7d8c1910fbc29d6f2b15197f06649af8aa15dDaniel Sandler 572d42794e6237a56d2d7518a8b9dba27e3e818d31Romain Guy static final int BACKGROUND_COLOR = 0xffffffff; 5803e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler 5903e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler static abstract class ClockPalette { 6003e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler public static ClockPalette parseXmlPaletteTag(XmlResourceParser xrp) { 6103e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler String kind = xrp.getAttributeValue(null, "kind"); 6203e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler if ("cycling".equals(kind)) { 6303e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler return CyclingClockPalette.parseXmlPaletteTag(xrp); 6403e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler } else { 6503e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler return FixedClockPalette.parseXmlPaletteTag(xrp); 6603e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler } 6703e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler } 6803e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler 6903e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler public abstract int getBackgroundColor(); 7003e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler 7101d49d700e55c3c32b8b1bc2c816be6cc76e6409Daniel Sandler // forAngle should be on [0.0,1.0) but 1.0 must be tolerated 7203e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler public abstract int getSecondColor(float forAngle); 7303e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler 7403e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler public abstract int getMinuteColor(float forAngle); 7503e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler 7603e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler public abstract int getHourColor(float forAngle); 7703e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler 7803e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler public abstract int getDayColor(float forAngle); 7903e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler 8003e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler public abstract int getMonthColor(float forAngle); 8103e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler 8203e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler public abstract String getId(); 8303e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler 8403e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler } 8503e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler 8603e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler static class FixedClockPalette extends ClockPalette { 8703e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler protected String mId; 8803e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler protected int mBackgroundColor; 8903e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler protected int mSecondColor; 9003e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler protected int mMinuteColor; 9103e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler protected int mHourColor; 9203e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler protected int mDayColor; 9303e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler protected int mMonthColor; 9403e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler 9503e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler private static FixedClockPalette sFallbackPalette = null; 9603e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler 9703e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler public static FixedClockPalette getFallback() { 9803e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler if (sFallbackPalette == null) { 9903e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler sFallbackPalette = new FixedClockPalette(); 10003e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler sFallbackPalette.mId = "default"; 10103e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler sFallbackPalette.mBackgroundColor = Color.WHITE; 10203e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler sFallbackPalette.mSecondColor = 10303e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler sFallbackPalette.mMinuteColor = 10403e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler sFallbackPalette.mHourColor = 10503e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler sFallbackPalette.mDayColor = 10603e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler sFallbackPalette.mMonthColor = 10703e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler Color.BLACK; 10803e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler } 10903e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler return sFallbackPalette; 11003e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler } 11103e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler 11203e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler private FixedClockPalette() { } 11303e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler 11403e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler public static ClockPalette parseXmlPaletteTag(XmlResourceParser xrp) { 11503e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler final FixedClockPalette pal = new FixedClockPalette(); 11603e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler pal.mId = xrp.getAttributeValue(null, "id"); 11703e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler String val; 11803e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler if ((val = xrp.getAttributeValue(null, "background")) != null) 11903e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler pal.mBackgroundColor = Color.parseColor(val); 12003e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler if ((val = xrp.getAttributeValue(null, "second")) != null) 12103e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler pal.mSecondColor = Color.parseColor(val); 12203e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler if ((val = xrp.getAttributeValue(null, "minute")) != null) 12303e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler pal.mMinuteColor = Color.parseColor(val); 12403e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler if ((val = xrp.getAttributeValue(null, "hour")) != null) 12503e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler pal.mHourColor = Color.parseColor(val); 12603e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler if ((val = xrp.getAttributeValue(null, "day")) != null) 12703e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler pal.mDayColor = Color.parseColor(val); 12803e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler if ((val = xrp.getAttributeValue(null, "month")) != null) 12903e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler pal.mMonthColor = Color.parseColor(val); 13003e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler return (pal.mId == null) ? null : pal; 13103e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler } 13203e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler 13303e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler @Override 13403e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler public int getBackgroundColor() { 13503e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler return mBackgroundColor; 13603e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler } 13703e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler 13803e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler @Override 13903e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler public int getSecondColor(float forAngle) { 14003e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler return mSecondColor; 14103e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler } 14203e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler 14303e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler @Override 14403e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler public int getMinuteColor(float forAngle) { 14503e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler return mMinuteColor; 14603e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler } 14703e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler 14803e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler @Override 14903e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler public int getHourColor(float forAngle) { 15003e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler return mHourColor; 15103e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler } 15203e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler 15303e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler @Override 15403e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler public int getDayColor(float forAngle) { 15503e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler return mDayColor; 15603e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler } 15703e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler 15803e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler @Override 15903e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler public int getMonthColor(float forAngle) { 16003e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler return mMonthColor; 16103e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler } 16203e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler 16303e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler @Override 16403e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler public String getId() { 16503e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler return mId; 16603e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler } 16703e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler 16803e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler } 16903e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler 17003e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler static class CyclingClockPalette extends ClockPalette { 17103e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler protected String mId; 17203e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler protected int mBackgroundColor; 17303e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler protected float mSaturation; 17403e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler protected float mBrightness; 17503e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler 17603e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler private static final int COLORS_CACHE_COUNT = 720; 17703e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler private final int[] mColors = new int[COLORS_CACHE_COUNT]; 17803e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler 17903e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler private static CyclingClockPalette sFallbackPalette = null; 18003e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler 18103e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler public static CyclingClockPalette getFallback() { 18203e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler if (sFallbackPalette == null) { 18303e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler sFallbackPalette = new CyclingClockPalette(); 18403e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler sFallbackPalette.mId = "default_c"; 18503e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler sFallbackPalette.mBackgroundColor = Color.WHITE; 18603e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler sFallbackPalette.mSaturation = 0.8f; 18703e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler sFallbackPalette.mBrightness = 0.9f; 18803e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler sFallbackPalette.computeIntermediateColors(); 18903e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler } 19003e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler return sFallbackPalette; 19103e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler } 19203e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler 19303e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler private CyclingClockPalette() { } 19403e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler 19503e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler private void computeIntermediateColors() { 19603e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler final int[] colors = mColors; 19703e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler final int count = colors.length; 19803e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler float invCount = 1.0f / (float) COLORS_CACHE_COUNT; 19903e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler for (int i = 0; i < count; i++) { 20003e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler colors[i] = Color.HSBtoColor(i * invCount, mSaturation, mBrightness); 20103e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler } 20203e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler } 20303e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler 20403e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler public static ClockPalette parseXmlPaletteTag(XmlResourceParser xrp) { 20503e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler final CyclingClockPalette pal = new CyclingClockPalette(); 20603e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler pal.mId = xrp.getAttributeValue(null, "id"); 20703e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler String val; 20803e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler if ((val = xrp.getAttributeValue(null, "background")) != null) 20903e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler pal.mBackgroundColor = Color.parseColor(val); 21003e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler if ((val = xrp.getAttributeValue(null, "saturation")) != null) 21103e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler pal.mSaturation = Float.parseFloat(val); 21203e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler if ((val = xrp.getAttributeValue(null, "brightness")) != null) 21303e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler pal.mBrightness = Float.parseFloat(val); 21403e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler if (pal.mId == null) { 21503e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler return null; 21603e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler } else { 21703e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler pal.computeIntermediateColors(); 21803e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler return pal; 21903e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler } 22003e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler } 22103e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler @Override 22203e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler public int getBackgroundColor() { 22303e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler return mBackgroundColor; 22403e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler } 22503e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler 22603e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler @Override 22703e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler public int getSecondColor(float forAngle) { 22801d49d700e55c3c32b8b1bc2c816be6cc76e6409Daniel Sandler if (forAngle >= 1.0f || forAngle < 0.0f) forAngle = 0.0f; 22903e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler return mColors[((int) (forAngle * COLORS_CACHE_COUNT))]; 23003e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler } 23103e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler 23203e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler @Override 23303e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler public int getMinuteColor(float forAngle) { 23401d49d700e55c3c32b8b1bc2c816be6cc76e6409Daniel Sandler if (forAngle >= 1.0f || forAngle < 0.0f) forAngle = 0.0f; 23503e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler return mColors[((int) (forAngle * COLORS_CACHE_COUNT))]; 23603e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler } 23703e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler 23803e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler @Override 23903e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler public int getHourColor(float forAngle) { 24001d49d700e55c3c32b8b1bc2c816be6cc76e6409Daniel Sandler if (forAngle >= 1.0f || forAngle < 0.0f) forAngle = 0.0f; 24103e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler return mColors[((int) (forAngle * COLORS_CACHE_COUNT))]; 24203e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler } 24303e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler 24403e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler @Override 24503e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler public int getDayColor(float forAngle) { 24601d49d700e55c3c32b8b1bc2c816be6cc76e6409Daniel Sandler if (forAngle >= 1.0f || forAngle < 0.0f) forAngle = 0.0f; 24703e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler return mColors[((int) (forAngle * COLORS_CACHE_COUNT))]; 24803e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler } 24903e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler 25003e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler @Override 25103e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler public int getMonthColor(float forAngle) { 25201d49d700e55c3c32b8b1bc2c816be6cc76e6409Daniel Sandler if (forAngle >= 1.0f || forAngle < 0.0f) forAngle = 0.0f; 25303e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler return mColors[((int) (forAngle * COLORS_CACHE_COUNT))]; 25403e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler } 25503e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler 25603e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler @Override 25703e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler public String getId() { 25803e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler return mId; 25903e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler } 26003e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler } 26103e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler 262a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy private final Handler mHandler = new Handler(); 263a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy 264a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy private IntentFilter mFilter; 265a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy 266a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy @Override 267a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy public void onCreate() { 268a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy super.onCreate(); 269a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy 270a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy mFilter = new IntentFilter(); 271a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy mFilter.addAction(Intent.ACTION_TIMEZONE_CHANGED); 272a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy } 273a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy 274a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy @Override 275a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy public void onDestroy() { 276a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy super.onDestroy(); 277a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy } 278a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy 279a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy public Engine onCreateEngine() { 280b8ca9a4b5b8f70306b14d0cd05cbc8e4d1d7e0e5Dianne Hackborn return new ClockEngine(); 281a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy } 282a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy 2832d42794e6237a56d2d7518a8b9dba27e3e818d31Romain Guy class ClockEngine extends Engine implements SharedPreferences.OnSharedPreferenceChangeListener { 2844ba7d8c1910fbc29d6f2b15197f06649af8aa15dDaniel Sandler private static final float SMALL_RING_THICKNESS = 8.0f; 2854ba7d8c1910fbc29d6f2b15197f06649af8aa15dDaniel Sandler private static final float MEDIUM_RING_THICKNESS = 16.0f; 2864ba7d8c1910fbc29d6f2b15197f06649af8aa15dDaniel Sandler private static final float LARGE_RING_THICKNESS = 32.0f; 2874ba7d8c1910fbc29d6f2b15197f06649af8aa15dDaniel Sandler 2884ba7d8c1910fbc29d6f2b15197f06649af8aa15dDaniel Sandler private static final float DEFAULT_RING_THICKNESS = 24.0f; 2894ba7d8c1910fbc29d6f2b15197f06649af8aa15dDaniel Sandler 290a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy private static final float SMALL_GAP = 14.0f; 291a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy private static final float LARGE_GAP = 38.0f; 292a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy 29303e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler private final HashMap<String, ClockPalette> mPalettes = new HashMap<String, ClockPalette>(); 29403e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler private ClockPalette mPalette; 2954ba7d8c1910fbc29d6f2b15197f06649af8aa15dDaniel Sandler 2960e1eb1a99bf6b95cebdcf9a1d855f4d4bc2a733dDianne Hackborn private SharedPreferences mPrefs; 2970e1eb1a99bf6b95cebdcf9a1d855f4d4bc2a733dDianne Hackborn private boolean mShowSeconds; 2984ba7d8c1910fbc29d6f2b15197f06649af8aa15dDaniel Sandler private boolean mVariableLineWidth; 29903e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler 300b8ca9a4b5b8f70306b14d0cd05cbc8e4d1d7e0e5Dianne Hackborn private boolean mWatcherRegistered; 301a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy private Time mCalendar; 302a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy 303a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy private final Paint mPaint = new Paint(); 304a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy private final RectF mRect = new RectF(); 30503e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler 306913771d67c494d1e311a58febbf8e7b9017e0a3bRomain Guy private float mOffsetX; 307a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy 308b8ca9a4b5b8f70306b14d0cd05cbc8e4d1d7e0e5Dianne Hackborn private final BroadcastReceiver mWatcher = new BroadcastReceiver() { 309b8ca9a4b5b8f70306b14d0cd05cbc8e4d1d7e0e5Dianne Hackborn public void onReceive(Context context, Intent intent) { 310b8ca9a4b5b8f70306b14d0cd05cbc8e4d1d7e0e5Dianne Hackborn final String timeZone = intent.getStringExtra("time-zone"); 311b8ca9a4b5b8f70306b14d0cd05cbc8e4d1d7e0e5Dianne Hackborn mCalendar = new Time(TimeZone.getTimeZone(timeZone).getID()); 312b2487598a8abb56463fbb3e58d59d56256dabdd8Dianne Hackborn drawFrame(); 313b8ca9a4b5b8f70306b14d0cd05cbc8e4d1d7e0e5Dianne Hackborn } 314b8ca9a4b5b8f70306b14d0cd05cbc8e4d1d7e0e5Dianne Hackborn }; 31503e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler 316b8ca9a4b5b8f70306b14d0cd05cbc8e4d1d7e0e5Dianne Hackborn private final Runnable mDrawClock = new Runnable() { 317b8ca9a4b5b8f70306b14d0cd05cbc8e4d1d7e0e5Dianne Hackborn public void run() { 318b2487598a8abb56463fbb3e58d59d56256dabdd8Dianne Hackborn drawFrame(); 319b8ca9a4b5b8f70306b14d0cd05cbc8e4d1d7e0e5Dianne Hackborn } 320b8ca9a4b5b8f70306b14d0cd05cbc8e4d1d7e0e5Dianne Hackborn }; 321913771d67c494d1e311a58febbf8e7b9017e0a3bRomain Guy private boolean mVisible; 322a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy 323913771d67c494d1e311a58febbf8e7b9017e0a3bRomain Guy ClockEngine() { 32403e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler XmlResourceParser xrp = getResources().getXml(R.xml.polar_clock_palettes); 32503e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler try { 32603e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler int what = xrp.getEventType(); 32703e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler while (what != END_DOCUMENT) { 32803e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler if (what == START_TAG) { 32903e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler if ("palette".equals(xrp.getName())) { 33003e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler ClockPalette pal = ClockPalette.parseXmlPaletteTag(xrp); 33103e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler if (pal.getId() != null) { 33203e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler mPalettes.put(pal.getId(), pal); 33303e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler } 33403e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler } 33503e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler } 33603e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler what = xrp.next(); 33703e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler } 33803e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler } catch (IOException e) { 3392d42794e6237a56d2d7518a8b9dba27e3e818d31Romain Guy Log.e(LOG_TAG, "An error occured during wallpaper configuration:", e); 34003e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler } catch (XmlPullParserException e) { 3412d42794e6237a56d2d7518a8b9dba27e3e818d31Romain Guy Log.e(LOG_TAG, "An error occured during wallpaper configuration:", e); 34203e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler } finally { 34303e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler xrp.close(); 344a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy } 34503e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler 34603e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler mPalette = CyclingClockPalette.getFallback(); 347a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy } 348a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy 349a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy @Override 350a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy public void onCreate(SurfaceHolder surfaceHolder) { 351a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy super.onCreate(surfaceHolder); 3524ba7d8c1910fbc29d6f2b15197f06649af8aa15dDaniel Sandler 3530e1eb1a99bf6b95cebdcf9a1d855f4d4bc2a733dDianne Hackborn mPrefs = PolarClockWallpaper.this.getSharedPreferences(SHARED_PREFS_NAME, 0); 3540e1eb1a99bf6b95cebdcf9a1d855f4d4bc2a733dDianne Hackborn mPrefs.registerOnSharedPreferenceChangeListener(this); 35503e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler 35603e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler // load up user's settings 3570e1eb1a99bf6b95cebdcf9a1d855f4d4bc2a733dDianne Hackborn onSharedPreferenceChanged(mPrefs, null); 358a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy 359a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy mCalendar = new Time(); 360a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy mCalendar.setToNow(); 361a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy 362a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy final Paint paint = mPaint; 363a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy paint.setAntiAlias(true); 3644ba7d8c1910fbc29d6f2b15197f06649af8aa15dDaniel Sandler paint.setStrokeWidth(DEFAULT_RING_THICKNESS); 365a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy paint.setStrokeCap(Paint.Cap.ROUND); 366a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy paint.setStyle(Paint.Style.STROKE); 3672d42794e6237a56d2d7518a8b9dba27e3e818d31Romain Guy 3682d42794e6237a56d2d7518a8b9dba27e3e818d31Romain Guy if (isPreview()) { 3692d42794e6237a56d2d7518a8b9dba27e3e818d31Romain Guy mOffsetX = 0.5f; 3702d42794e6237a56d2d7518a8b9dba27e3e818d31Romain Guy } 371a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy } 372a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy 373a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy @Override 374b8ca9a4b5b8f70306b14d0cd05cbc8e4d1d7e0e5Dianne Hackborn public void onDestroy() { 375b8ca9a4b5b8f70306b14d0cd05cbc8e4d1d7e0e5Dianne Hackborn super.onDestroy(); 376b8ca9a4b5b8f70306b14d0cd05cbc8e4d1d7e0e5Dianne Hackborn if (mWatcherRegistered) { 377b8ca9a4b5b8f70306b14d0cd05cbc8e4d1d7e0e5Dianne Hackborn mWatcherRegistered = false; 378b8ca9a4b5b8f70306b14d0cd05cbc8e4d1d7e0e5Dianne Hackborn unregisterReceiver(mWatcher); 379b8ca9a4b5b8f70306b14d0cd05cbc8e4d1d7e0e5Dianne Hackborn } 380b8ca9a4b5b8f70306b14d0cd05cbc8e4d1d7e0e5Dianne Hackborn mHandler.removeCallbacks(mDrawClock); 381b8ca9a4b5b8f70306b14d0cd05cbc8e4d1d7e0e5Dianne Hackborn } 382b8ca9a4b5b8f70306b14d0cd05cbc8e4d1d7e0e5Dianne Hackborn 3830e1eb1a99bf6b95cebdcf9a1d855f4d4bc2a733dDianne Hackborn public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, 3840e1eb1a99bf6b95cebdcf9a1d855f4d4bc2a733dDianne Hackborn String key) { 38503e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler 3864ba7d8c1910fbc29d6f2b15197f06649af8aa15dDaniel Sandler boolean changed = false; 38703e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler if (key == null || PREF_SHOW_SECONDS.equals(key)) { 3884ba7d8c1910fbc29d6f2b15197f06649af8aa15dDaniel Sandler mShowSeconds = sharedPreferences.getBoolean( 3894ba7d8c1910fbc29d6f2b15197f06649af8aa15dDaniel Sandler PREF_SHOW_SECONDS, true); 3904ba7d8c1910fbc29d6f2b15197f06649af8aa15dDaniel Sandler changed = true; 3914ba7d8c1910fbc29d6f2b15197f06649af8aa15dDaniel Sandler } 39203e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler if (key == null || PREF_VARIABLE_LINE_WIDTH.equals(key)) { 3934ba7d8c1910fbc29d6f2b15197f06649af8aa15dDaniel Sandler mVariableLineWidth = sharedPreferences.getBoolean( 3944ba7d8c1910fbc29d6f2b15197f06649af8aa15dDaniel Sandler PREF_VARIABLE_LINE_WIDTH, true); 3954ba7d8c1910fbc29d6f2b15197f06649af8aa15dDaniel Sandler changed = true; 3964ba7d8c1910fbc29d6f2b15197f06649af8aa15dDaniel Sandler } 39703e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler if (key == null || PREF_PALETTE.equals(key)) { 39803e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler String paletteId = sharedPreferences.getString( 39903e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler PREF_PALETTE, ""); 40003e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler ClockPalette pal = mPalettes.get(paletteId); 40103e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler if (pal != null) { 40203e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler mPalette = pal; 40303e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler changed = true; 40403e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler } 40503e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler } 4064ba7d8c1910fbc29d6f2b15197f06649af8aa15dDaniel Sandler 4074ba7d8c1910fbc29d6f2b15197f06649af8aa15dDaniel Sandler if (mVisible && changed) { 4084ba7d8c1910fbc29d6f2b15197f06649af8aa15dDaniel Sandler drawFrame(); 4090e1eb1a99bf6b95cebdcf9a1d855f4d4bc2a733dDianne Hackborn } 4100e1eb1a99bf6b95cebdcf9a1d855f4d4bc2a733dDianne Hackborn } 4110e1eb1a99bf6b95cebdcf9a1d855f4d4bc2a733dDianne Hackborn 412b8ca9a4b5b8f70306b14d0cd05cbc8e4d1d7e0e5Dianne Hackborn @Override 413a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy public void onVisibilityChanged(boolean visible) { 414913771d67c494d1e311a58febbf8e7b9017e0a3bRomain Guy mVisible = visible; 415a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy if (visible) { 4162eee327ccceaf0eac8c65e962e1a6ba948b37967Dianne Hackborn if (!mWatcherRegistered) { 4172eee327ccceaf0eac8c65e962e1a6ba948b37967Dianne Hackborn mWatcherRegistered = true; 4182eee327ccceaf0eac8c65e962e1a6ba948b37967Dianne Hackborn registerReceiver(mWatcher, mFilter, null, mHandler); 4192eee327ccceaf0eac8c65e962e1a6ba948b37967Dianne Hackborn } 420a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy mCalendar = new Time(); 421a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy mCalendar.setToNow(); 422a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy } else { 4232eee327ccceaf0eac8c65e962e1a6ba948b37967Dianne Hackborn if (mWatcherRegistered) { 4242eee327ccceaf0eac8c65e962e1a6ba948b37967Dianne Hackborn mWatcherRegistered = false; 4252eee327ccceaf0eac8c65e962e1a6ba948b37967Dianne Hackborn unregisterReceiver(mWatcher); 4262eee327ccceaf0eac8c65e962e1a6ba948b37967Dianne Hackborn } 427a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy mHandler.removeCallbacks(mDrawClock); 428a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy } 429b2487598a8abb56463fbb3e58d59d56256dabdd8Dianne Hackborn drawFrame(); 430a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy } 431a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy 432a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy @Override 433a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy public void onSurfaceChanged(SurfaceHolder holder, int format, int width, int height) { 434a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy super.onSurfaceChanged(holder, format, width, height); 435b2487598a8abb56463fbb3e58d59d56256dabdd8Dianne Hackborn drawFrame(); 436a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy } 437a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy 438a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy @Override 439a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy public void onSurfaceCreated(SurfaceHolder holder) { 440a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy super.onSurfaceCreated(holder); 441a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy } 442a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy 443a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy @Override 444a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy public void onSurfaceDestroyed(SurfaceHolder holder) { 445a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy super.onSurfaceDestroyed(holder); 446b2487598a8abb56463fbb3e58d59d56256dabdd8Dianne Hackborn mVisible = false; 447b2487598a8abb56463fbb3e58d59d56256dabdd8Dianne Hackborn mHandler.removeCallbacks(mDrawClock); 448a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy } 449913771d67c494d1e311a58febbf8e7b9017e0a3bRomain Guy 450913771d67c494d1e311a58febbf8e7b9017e0a3bRomain Guy @Override 45106d2076e512e9345d31cdd1c79c4ad28d7add9bfMarco Nelissen public void onOffsetsChanged(float xOffset, float yOffset, 45206d2076e512e9345d31cdd1c79c4ad28d7add9bfMarco Nelissen float xStep, float yStep, int xPixels, int yPixels) { 453416bf81476daf3fef577678bf2ea86d215d1196bDaniel Sandler if (isPreview()) return; 454416bf81476daf3fef577678bf2ea86d215d1196bDaniel Sandler 455913771d67c494d1e311a58febbf8e7b9017e0a3bRomain Guy mOffsetX = xOffset; 456b2487598a8abb56463fbb3e58d59d56256dabdd8Dianne Hackborn drawFrame(); 457913771d67c494d1e311a58febbf8e7b9017e0a3bRomain Guy } 45803e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler 459b2487598a8abb56463fbb3e58d59d56256dabdd8Dianne Hackborn void drawFrame() { 46003e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler if (mPalette == null) { 4612d42794e6237a56d2d7518a8b9dba27e3e818d31Romain Guy Log.w("PolarClockWallpaper", "no palette?!"); 46203e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler return; 46303e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler } 46403e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler 465a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy final SurfaceHolder holder = getSurfaceHolder(); 466a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy final Rect frame = holder.getSurfaceFrame(); 467a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy final int width = frame.width(); 468a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy final int height = frame.height(); 469a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy 470a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy Canvas c = null; 471a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy try { 472a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy c = holder.lockCanvas(); 473a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy if (c != null) { 474a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy final Time calendar = mCalendar; 475a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy final Paint paint = mPaint; 476a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy 47701d49d700e55c3c32b8b1bc2c816be6cc76e6409Daniel Sandler final long millis = System.currentTimeMillis(); 47801d49d700e55c3c32b8b1bc2c816be6cc76e6409Daniel Sandler calendar.set(millis); 479a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy calendar.normalize(false); 480a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy 481913771d67c494d1e311a58febbf8e7b9017e0a3bRomain Guy int s = width / 2; 482913771d67c494d1e311a58febbf8e7b9017e0a3bRomain Guy int t = height / 2; 483913771d67c494d1e311a58febbf8e7b9017e0a3bRomain Guy 48403e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler c.drawColor(mPalette.getBackgroundColor()); 48503e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler 486913771d67c494d1e311a58febbf8e7b9017e0a3bRomain Guy c.translate(s + MathUtils.lerp(s, -s, mOffsetX), t); 487a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy c.rotate(-90.0f); 488913771d67c494d1e311a58febbf8e7b9017e0a3bRomain Guy if (height < width) { 489913771d67c494d1e311a58febbf8e7b9017e0a3bRomain Guy c.scale(0.9f, 0.9f); 490913771d67c494d1e311a58febbf8e7b9017e0a3bRomain Guy } 491a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy 4924ba7d8c1910fbc29d6f2b15197f06649af8aa15dDaniel Sandler float size = Math.min(width, height) * 0.5f - DEFAULT_RING_THICKNESS; 493a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy final RectF rect = mRect; 494a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy rect.set(-size, -size, size, size); 4950e1eb1a99bf6b95cebdcf9a1d855f4d4bc2a733dDianne Hackborn float angle; 4964ba7d8c1910fbc29d6f2b15197f06649af8aa15dDaniel Sandler 4974ba7d8c1910fbc29d6f2b15197f06649af8aa15dDaniel Sandler float lastRingThickness = DEFAULT_RING_THICKNESS; 49803e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler 4990e1eb1a99bf6b95cebdcf9a1d855f4d4bc2a733dDianne Hackborn if (mShowSeconds) { 5000e1eb1a99bf6b95cebdcf9a1d855f4d4bc2a733dDianne Hackborn // Draw seconds 50101d49d700e55c3c32b8b1bc2c816be6cc76e6409Daniel Sandler angle = (float) (millis % 60000) / 60000.0f; 50201d49d700e55c3c32b8b1bc2c816be6cc76e6409Daniel Sandler //Log.d("PolarClock", "millis=" + millis + ", angle=" + angle); 50303e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler paint.setColor(mPalette.getSecondColor(angle)); 5044ba7d8c1910fbc29d6f2b15197f06649af8aa15dDaniel Sandler 5054ba7d8c1910fbc29d6f2b15197f06649af8aa15dDaniel Sandler if (mVariableLineWidth) { 5064ba7d8c1910fbc29d6f2b15197f06649af8aa15dDaniel Sandler lastRingThickness = SMALL_RING_THICKNESS; 5074ba7d8c1910fbc29d6f2b15197f06649af8aa15dDaniel Sandler paint.setStrokeWidth(lastRingThickness); 5084ba7d8c1910fbc29d6f2b15197f06649af8aa15dDaniel Sandler } 5090e1eb1a99bf6b95cebdcf9a1d855f4d4bc2a733dDianne Hackborn c.drawArc(rect, 0.0f, angle * 360.0f, false, paint); 5100e1eb1a99bf6b95cebdcf9a1d855f4d4bc2a733dDianne Hackborn } 511a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy 512a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy // Draw minutes 5134ba7d8c1910fbc29d6f2b15197f06649af8aa15dDaniel Sandler size -= (SMALL_GAP + lastRingThickness); 514a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy rect.set(-size, -size, size, size); 515a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy 516a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy angle = ((calendar.minute * 60.0f + calendar.second) % 3600) / 3600.0f; 51703e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler paint.setColor(mPalette.getMinuteColor(angle)); 5184ba7d8c1910fbc29d6f2b15197f06649af8aa15dDaniel Sandler 5194ba7d8c1910fbc29d6f2b15197f06649af8aa15dDaniel Sandler if (mVariableLineWidth) { 5204ba7d8c1910fbc29d6f2b15197f06649af8aa15dDaniel Sandler lastRingThickness = MEDIUM_RING_THICKNESS; 5214ba7d8c1910fbc29d6f2b15197f06649af8aa15dDaniel Sandler paint.setStrokeWidth(lastRingThickness); 5224ba7d8c1910fbc29d6f2b15197f06649af8aa15dDaniel Sandler } 523a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy c.drawArc(rect, 0.0f, angle * 360.0f, false, paint); 52403e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler 525a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy // Draw hours 5264ba7d8c1910fbc29d6f2b15197f06649af8aa15dDaniel Sandler size -= (SMALL_GAP + lastRingThickness); 527a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy rect.set(-size, -size, size, size); 528a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy 529a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy angle = ((calendar.hour * 60.0f + calendar.minute) % 1440) / 1440.0f; 53003e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler paint.setColor(mPalette.getHourColor(angle)); 53103e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler 5324ba7d8c1910fbc29d6f2b15197f06649af8aa15dDaniel Sandler if (mVariableLineWidth) { 5334ba7d8c1910fbc29d6f2b15197f06649af8aa15dDaniel Sandler lastRingThickness = LARGE_RING_THICKNESS; 5344ba7d8c1910fbc29d6f2b15197f06649af8aa15dDaniel Sandler paint.setStrokeWidth(lastRingThickness); 5354ba7d8c1910fbc29d6f2b15197f06649af8aa15dDaniel Sandler } 536a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy c.drawArc(rect, 0.0f, angle * 360.0f, false, paint); 537a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy 538a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy // Draw day 5394ba7d8c1910fbc29d6f2b15197f06649af8aa15dDaniel Sandler size -= (LARGE_GAP + lastRingThickness); 540a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy rect.set(-size, -size, size, size); 541a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy 542a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy angle = (calendar.monthDay - 1) / 543a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy (float) (calendar.getActualMaximum(Time.MONTH_DAY) - 1); 54403e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler paint.setColor(mPalette.getDayColor(angle)); 54503e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler 5464ba7d8c1910fbc29d6f2b15197f06649af8aa15dDaniel Sandler if (mVariableLineWidth) { 5474ba7d8c1910fbc29d6f2b15197f06649af8aa15dDaniel Sandler lastRingThickness = MEDIUM_RING_THICKNESS; 5484ba7d8c1910fbc29d6f2b15197f06649af8aa15dDaniel Sandler paint.setStrokeWidth(lastRingThickness); 5494ba7d8c1910fbc29d6f2b15197f06649af8aa15dDaniel Sandler } 550a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy c.drawArc(rect, 0.0f, angle * 360.0f, false, paint); 551a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy 552a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy // Draw month 5534ba7d8c1910fbc29d6f2b15197f06649af8aa15dDaniel Sandler size -= (SMALL_GAP + lastRingThickness); 554a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy rect.set(-size, -size, size, size); 555a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy 55601d49d700e55c3c32b8b1bc2c816be6cc76e6409Daniel Sandler angle = (calendar.month) / 11.0f; // NB: month is already on [0..11] 55703e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler 55803e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler paint.setColor(mPalette.getMonthColor(angle)); 55903e14e59486f497a6daaa6ef4b205eff9e28919eDaniel Sandler 5604ba7d8c1910fbc29d6f2b15197f06649af8aa15dDaniel Sandler if (mVariableLineWidth) { 5614ba7d8c1910fbc29d6f2b15197f06649af8aa15dDaniel Sandler lastRingThickness = LARGE_RING_THICKNESS; 5624ba7d8c1910fbc29d6f2b15197f06649af8aa15dDaniel Sandler paint.setStrokeWidth(lastRingThickness); 5634ba7d8c1910fbc29d6f2b15197f06649af8aa15dDaniel Sandler } 564a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy c.drawArc(rect, 0.0f, angle * 360.0f, false, paint); 565a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy } 566a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy } finally { 567a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy if (c != null) holder.unlockCanvasAndPost(c); 568a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy } 569a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy 570a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy mHandler.removeCallbacks(mDrawClock); 571b2487598a8abb56463fbb3e58d59d56256dabdd8Dianne Hackborn if (mVisible) { 5720e1eb1a99bf6b95cebdcf9a1d855f4d4bc2a733dDianne Hackborn if (mShowSeconds) { 5730e1eb1a99bf6b95cebdcf9a1d855f4d4bc2a733dDianne Hackborn mHandler.postDelayed(mDrawClock, 1000 / 25); 5740e1eb1a99bf6b95cebdcf9a1d855f4d4bc2a733dDianne Hackborn } else { 5750e1eb1a99bf6b95cebdcf9a1d855f4d4bc2a733dDianne Hackborn // If we aren't showing seconds, we don't need to update 5760e1eb1a99bf6b95cebdcf9a1d855f4d4bc2a733dDianne Hackborn // nearly as often. 5770e1eb1a99bf6b95cebdcf9a1d855f4d4bc2a733dDianne Hackborn mHandler.postDelayed(mDrawClock, 2000); 5780e1eb1a99bf6b95cebdcf9a1d855f4d4bc2a733dDianne Hackborn } 579a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy } 580a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy } 581a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy } 582a7cbc26594244e4e5c0cf4889c1b45fa2741831eRomain Guy} 583