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