Set up polar clock color palettes in an XML file.
Instead of a checkbox for "color cycling" vs "palette", we
now have cycling and fixed color palettes. That way you can
easily create a "dark" cycling palette that uses a different
HSB base and background color.
Includes a handful of palettes.
Change-Id: I01042bc9640c0a31c3779de425abbeeb4480c687
diff --git a/res/values/arrays.xml b/res/values/arrays.xml
new file mode 100644
index 0000000..d9c9df8
--- /dev/null
+++ b/res/values/arrays.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+* Copyright (C) 2008 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string-array name="polar_clock_palette_names">
+ <item>@string/palette_gray</item>
+ <item>@string/palette_white_c</item>
+ <item>@string/palette_black_c</item>
+ <item>@string/palette_matrix</item>
+ <item>@string/palette_halloween</item>
+ <item>@string/palette_violet</item>
+ <item>@string/palette_oceanic</item>
+ <item>@string/palette_zenburn</item>
+ </string-array>
+ <string-array name="polar_clock_palette_ids">
+ <item>palette_gray</item>
+ <item>palette_white_c</item>
+ <item>palette_black_c</item>
+ <item>palette_matrix</item>
+ <item>palette_halloween</item>
+ <item>palette_violet</item>
+ <item>palette_oceanic</item>
+ <item>palette_zenburn</item>
+ </string-array>
+</resources>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 12fbdfa..166d33b 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -41,8 +41,26 @@
<string name="clock_settings">Polar clock settings</string>
<!-- Polar clock: label for "show seconds" pref -->
<string name="show_seconds">Show seconds</string>
- <!-- Polar clock: label for "cycle colors" pref -->
- <string name="cycle_colors">Cycle ring colors</string>
<!-- Polar clock: label for "variable widths" pref -->
<string name="variable_line_width">Vary ring widths</string>
+ <!-- Polar clock: label for "palette" pref -->
+ <string name="palette">Color palette</string>
+
+ <!-- Polar clock: palette name -->
+ <string name="palette_gray">Iron</string>
+ <!-- Polar clock: palette name -->
+ <string name="palette_violet">Midnight</string>
+ <!-- Polar clock: palette name -->
+ <string name="palette_matrix">Green Screen</string>
+ <!-- Polar clock: palette name -->
+ <string name="palette_white_c">Polar Bear (dynamic)</string>
+ <!-- Polar clock: palette name -->
+ <string name="palette_black_c">Black Hole (dynamic)</string>
+ <!-- Polar clock: palette name -->
+ <string name="palette_halloween">Pumpkin Pie</string>
+ <!-- Polar clock: palette name -->
+ <string name="palette_zenburn">Alien Fruit Salad</string>
+ <!-- Polar clock: palette name -->
+ <string name="palette_oceanic">Blue Laser</string>
+
</resources>
diff --git a/res/xml/polar_clock_palettes.xml b/res/xml/polar_clock_palettes.xml
new file mode 100644
index 0000000..c77d113
--- /dev/null
+++ b/res/xml/polar_clock_palettes.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<palettes>
+ <!-- basic white polar clock with color-cycling rings -->
+ <palette kind="cycling"
+ id="palette_white_c"
+ background="#FFFFFFFF"
+ saturation="0.8" brightness="0.9" />
+ <!-- same as above, but on black -->
+ <palette kind="cycling"
+ id="palette_black_c"
+ background="#FF000000"
+ saturation="1.0" brightness="0.25" />
+ <!-- a nice gray color scheme with an orange seconds ring -->
+ <palette kind="fixed"
+ id="palette_gray"
+ background="#FF555555"
+ second="#FFCC8800" minute="#FF333333" hour="#FF000000"
+ day="#FF999999" month="#FF777777" />
+ <!-- smooth black with a purple cast -->
+ <palette kind="fixed"
+ id="palette_violet"
+ background="#FF181020"
+ second="#FF602070" minute="#603050" hour="#FF040008"
+ day="#FF706080" month="#FF403050" />
+ <!-- green on black -->
+ <palette kind="fixed"
+ id="palette_matrix"
+ background="#FF002200"
+ second="#FF00FF00" minute="#FF00BB00" hour="#FF007700"
+ day="#FF00AA00" month="#FF006600" />
+ <!-- orange -->
+ <palette kind="fixed"
+ id="palette_halloween"
+ background="#FF884400"
+ second="#FFFFFF00" minute="#FFFF8800" hour="#FFFF8800"
+ day="#FF000000" month="#FF000000" />
+ <!-- based on Zenburn by Jani Nurminen -->
+ <palette kind="fixed"
+ id="palette_zenburn"
+ background="#FF3f3f3f"
+ second="#FF8aCCCF" minute="#FFCB9292" hour="#FFCCDC90"
+ day="#FFDCA3A3" month="#FF7f9f7f" />
+ <!-- electric blue -->
+ <palette kind="fixed"
+ id="palette_oceanic"
+ background="#FF000066"
+ second="#FF6666FF" minute="#FF0000FF" hour="#FF0000AA"
+ day="#FF000033" month="#FF000011" />
+</palettes>
diff --git a/res/xml/polar_clock_prefs.xml b/res/xml/polar_clock_prefs.xml
index ae96458..d0a0d20 100644
--- a/res/xml/polar_clock_prefs.xml
+++ b/res/xml/polar_clock_prefs.xml
@@ -25,15 +25,15 @@
android:persistent="true"
/>
<CheckBoxPreference
- android:key="cycle_colors"
- android:title="@string/cycle_colors"
- android:defaultValue="false"
- android:persistent="true"
- />
- <CheckBoxPreference
android:key="variable_line_width"
android:title="@string/variable_line_width"
android:defaultValue="true"
android:persistent="true"
/>
+ <ListPreference
+ android:key="palette"
+ android:title="@string/palette"
+ android:entries="@array/polar_clock_palette_names"
+ android:entryValues="@array/polar_clock_palette_ids"
+ />
</PreferenceScreen>
diff --git a/src/com/android/wallpaper/polarclock/PolarClockWallpaper.java b/src/com/android/wallpaper/polarclock/PolarClockWallpaper.java
index 724f224..5b4a060 100644
--- a/src/com/android/wallpaper/polarclock/PolarClockWallpaper.java
+++ b/src/com/android/wallpaper/polarclock/PolarClockWallpaper.java
@@ -28,22 +28,231 @@
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.SharedPreferences;
+import android.content.res.XmlResourceParser;
+import android.preference.ListPreference;
+
import android.os.Handler;
import android.os.SystemClock;
import android.text.format.Time;
import android.util.MathUtils;
+import java.util.HashMap;
import java.util.TimeZone;
+import java.io.IOException;
+
+import org.xmlpull.v1.XmlPullParserException;
+import static org.xmlpull.v1.XmlPullParser.*;
+
+import com.android.wallpaper.R;
public class PolarClockWallpaper extends WallpaperService {
public static final String SHARED_PREFS_NAME = "polar_clock_settings";
-
+
public static final String PREF_SHOW_SECONDS = "show_seconds";
public static final String PREF_VARIABLE_LINE_WIDTH = "variable_line_width";
- public static final String PREF_CYCLE_COLORS = "cycle_colors";
+ public static final String PREF_PALETTE = "palette";
public static final int BACKGROUND_COLOR = 0xffffffff;
-
+
+ static abstract class ClockPalette {
+ public static ClockPalette parseXmlPaletteTag(XmlResourceParser xrp) {
+ String kind = xrp.getAttributeValue(null, "kind");
+ if ("cycling".equals(kind)) {
+ return CyclingClockPalette.parseXmlPaletteTag(xrp);
+ } else {
+ return FixedClockPalette.parseXmlPaletteTag(xrp);
+ }
+ }
+
+ public abstract int getBackgroundColor();
+
+ public abstract int getSecondColor(float forAngle);
+
+ public abstract int getMinuteColor(float forAngle);
+
+ public abstract int getHourColor(float forAngle);
+
+ public abstract int getDayColor(float forAngle);
+
+ public abstract int getMonthColor(float forAngle);
+
+ public abstract String getId();
+
+ }
+
+ static class FixedClockPalette extends ClockPalette {
+ protected String mId;
+ protected int mBackgroundColor;
+ protected int mSecondColor;
+ protected int mMinuteColor;
+ protected int mHourColor;
+ protected int mDayColor;
+ protected int mMonthColor;
+
+ private static FixedClockPalette sFallbackPalette = null;
+
+ public static FixedClockPalette getFallback() {
+ if (sFallbackPalette == null) {
+ sFallbackPalette = new FixedClockPalette();
+ sFallbackPalette.mId = "default";
+ sFallbackPalette.mBackgroundColor = Color.WHITE;
+ sFallbackPalette.mSecondColor =
+ sFallbackPalette.mMinuteColor =
+ sFallbackPalette.mHourColor =
+ sFallbackPalette.mDayColor =
+ sFallbackPalette.mMonthColor =
+ Color.BLACK;
+ }
+ return sFallbackPalette;
+ }
+
+ private FixedClockPalette() { }
+
+ @Override
+ public static ClockPalette parseXmlPaletteTag(XmlResourceParser xrp) {
+ final FixedClockPalette pal = new FixedClockPalette();
+ pal.mId = xrp.getAttributeValue(null, "id");
+ String val;
+ if ((val = xrp.getAttributeValue(null, "background")) != null)
+ pal.mBackgroundColor = Color.parseColor(val);
+ if ((val = xrp.getAttributeValue(null, "second")) != null)
+ pal.mSecondColor = Color.parseColor(val);
+ if ((val = xrp.getAttributeValue(null, "minute")) != null)
+ pal.mMinuteColor = Color.parseColor(val);
+ if ((val = xrp.getAttributeValue(null, "hour")) != null)
+ pal.mHourColor = Color.parseColor(val);
+ if ((val = xrp.getAttributeValue(null, "day")) != null)
+ pal.mDayColor = Color.parseColor(val);
+ if ((val = xrp.getAttributeValue(null, "month")) != null)
+ pal.mMonthColor = Color.parseColor(val);
+ return (pal.mId == null) ? null : pal;
+ }
+
+ @Override
+ public int getBackgroundColor() {
+ return mBackgroundColor;
+ }
+
+ @Override
+ public int getSecondColor(float forAngle) {
+ return mSecondColor;
+ }
+
+ @Override
+ public int getMinuteColor(float forAngle) {
+ return mMinuteColor;
+ }
+
+ @Override
+ public int getHourColor(float forAngle) {
+ return mHourColor;
+ }
+
+ @Override
+ public int getDayColor(float forAngle) {
+ return mDayColor;
+ }
+
+ @Override
+ public int getMonthColor(float forAngle) {
+ return mMonthColor;
+ }
+
+ @Override
+ public String getId() {
+ return mId;
+ }
+
+ }
+
+ static class CyclingClockPalette extends ClockPalette {
+ protected String mId;
+ protected int mBackgroundColor;
+ protected float mSaturation;
+ protected float mBrightness;
+
+ private static final int COLORS_CACHE_COUNT = 720;
+ private final int[] mColors = new int[COLORS_CACHE_COUNT];
+
+ private static CyclingClockPalette sFallbackPalette = null;
+
+ public static CyclingClockPalette getFallback() {
+ if (sFallbackPalette == null) {
+ sFallbackPalette = new CyclingClockPalette();
+ sFallbackPalette.mId = "default_c";
+ sFallbackPalette.mBackgroundColor = Color.WHITE;
+ sFallbackPalette.mSaturation = 0.8f;
+ sFallbackPalette.mBrightness = 0.9f;
+ sFallbackPalette.computeIntermediateColors();
+ }
+ return sFallbackPalette;
+ }
+
+ private CyclingClockPalette() { }
+
+ private void computeIntermediateColors() {
+ final int[] colors = mColors;
+ final int count = colors.length;
+ float invCount = 1.0f / (float) COLORS_CACHE_COUNT;
+ for (int i = 0; i < count; i++) {
+ colors[i] = Color.HSBtoColor(i * invCount, mSaturation, mBrightness);
+ }
+ }
+
+ @Override
+ public static ClockPalette parseXmlPaletteTag(XmlResourceParser xrp) {
+ final CyclingClockPalette pal = new CyclingClockPalette();
+ pal.mId = xrp.getAttributeValue(null, "id");
+ String val;
+ if ((val = xrp.getAttributeValue(null, "background")) != null)
+ pal.mBackgroundColor = Color.parseColor(val);
+ if ((val = xrp.getAttributeValue(null, "saturation")) != null)
+ pal.mSaturation = Float.parseFloat(val);
+ if ((val = xrp.getAttributeValue(null, "brightness")) != null)
+ pal.mBrightness = Float.parseFloat(val);
+ if (pal.mId == null) {
+ return null;
+ } else {
+ pal.computeIntermediateColors();
+ return pal;
+ }
+ }
+ @Override
+ public int getBackgroundColor() {
+ return mBackgroundColor;
+ }
+
+ @Override
+ public int getSecondColor(float forAngle) {
+ return mColors[((int) (forAngle * COLORS_CACHE_COUNT))];
+ }
+
+ @Override
+ public int getMinuteColor(float forAngle) {
+ return mColors[((int) (forAngle * COLORS_CACHE_COUNT))];
+ }
+
+ @Override
+ public int getHourColor(float forAngle) {
+ return mColors[((int) (forAngle * COLORS_CACHE_COUNT))];
+ }
+
+ @Override
+ public int getDayColor(float forAngle) {
+ return mColors[((int) (forAngle * COLORS_CACHE_COUNT))];
+ }
+
+ @Override
+ public int getMonthColor(float forAngle) {
+ return mColors[((int) (forAngle * COLORS_CACHE_COUNT))];
+ }
+
+ @Override
+ public String getId() {
+ return mId;
+ }
+ }
+
private final Handler mHandler = new Handler();
private IntentFilter mFilter;
@@ -67,9 +276,6 @@
class ClockEngine extends Engine
implements SharedPreferences.OnSharedPreferenceChangeListener {
- private static final float SATURATION = 0.8f;
- private static final float BRIGHTNESS = 0.9f;
-
private static final float SMALL_RING_THICKNESS = 8.0f;
private static final float MEDIUM_RING_THICKNESS = 16.0f;
private static final float LARGE_RING_THICKNESS = 32.0f;
@@ -79,44 +285,20 @@
private static final float SMALL_GAP = 14.0f;
private static final float LARGE_GAP = 38.0f;
- private static final int COLORS_CACHE_COUNT = 720;
-
- class ColorPalette {
- ColorPalette(String name, int bg, int s, int m, int h, int d, int o) {
- this.name = name; this.bg = bg;
- second = s; minute = m; hour = h; day = d; month = o;
- }
- public final String name;
- public final int bg;
- public final int second;
- public final int minute;
- public final int hour;
- public final int day;
- public final int month;
- }
-
- // XXX: make this an array of named palettes, selectable in prefs
- // via a spinner (bonus points: move to XML)
- private final ColorPalette mPalette = new ColorPalette(
- "MutedAndroid",
- 0xFF555555,
- 0xFF00FF00, 0xFF333333, 0xFF000000,
- 0xFF888888, 0xFFAAAAAA
- );
+ private final HashMap<String, ClockPalette> mPalettes = new HashMap<String, ClockPalette>();
+ private ClockPalette mPalette;
private SharedPreferences mPrefs;
private boolean mShowSeconds;
private boolean mVariableLineWidth;
- private boolean mCycleColors;
-
+
private boolean mWatcherRegistered;
private float mStartTime;
private Time mCalendar;
private final Paint mPaint = new Paint();
private final RectF mRect = new RectF();
- private final int[] mColors = new int[COLORS_CACHE_COUNT];
-
+
private float mOffsetX;
private final BroadcastReceiver mWatcher = new BroadcastReceiver() {
@@ -126,7 +308,7 @@
drawFrame();
}
};
-
+
private final Runnable mDrawClock = new Runnable() {
public void run() {
drawFrame();
@@ -135,13 +317,29 @@
private boolean mVisible;
ClockEngine() {
- final int[] colors = mColors;
- final int count = colors.length;
-
- float invCount = 1.0f / (float) COLORS_CACHE_COUNT;
- for (int i = 0; i < count; i++) {
- colors[i] = Color.HSBtoColor(i * invCount, SATURATION, BRIGHTNESS);
+ XmlResourceParser xrp = getResources().getXml(R.xml.polar_clock_palettes);
+ try {
+ int what = xrp.getEventType();
+ while (what != END_DOCUMENT) {
+ if (what == START_TAG) {
+ if ("palette".equals(xrp.getName())) {
+ ClockPalette pal = ClockPalette.parseXmlPaletteTag(xrp);
+ if (pal.getId() != null) {
+ mPalettes.put(pal.getId(), pal);
+ }
+ }
+ }
+ what = xrp.next();
+ }
+ } catch (IOException e) {
+ // XXX: Log?
+ } catch (XmlPullParserException e) {
+ // XXX: Log?
+ } finally {
+ xrp.close();
}
+
+ mPalette = CyclingClockPalette.getFallback();
}
@Override
@@ -150,6 +348,8 @@
mPrefs = PolarClockWallpaper.this.getSharedPreferences(SHARED_PREFS_NAME, 0);
mPrefs.registerOnSharedPreferenceChangeListener(this);
+
+ // load up user's settings
onSharedPreferenceChanged(mPrefs, null);
mCalendar = new Time();
@@ -175,23 +375,27 @@
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences,
String key) {
-
+
boolean changed = false;
- if (null == key || PREF_SHOW_SECONDS.equals(key)) {
+ if (key == null || PREF_SHOW_SECONDS.equals(key)) {
mShowSeconds = sharedPreferences.getBoolean(
PREF_SHOW_SECONDS, true);
changed = true;
}
- if (null == key || PREF_CYCLE_COLORS.equals(key)) {
- mCycleColors = sharedPreferences.getBoolean(
- PREF_CYCLE_COLORS, false);
- changed = true;
- }
- if (null == key || PREF_VARIABLE_LINE_WIDTH.equals(key)) {
+ if (key == null || PREF_VARIABLE_LINE_WIDTH.equals(key)) {
mVariableLineWidth = sharedPreferences.getBoolean(
PREF_VARIABLE_LINE_WIDTH, true);
changed = true;
}
+ if (key == null || PREF_PALETTE.equals(key)) {
+ String paletteId = sharedPreferences.getString(
+ PREF_PALETTE, "");
+ ClockPalette pal = mPalettes.get(paletteId);
+ if (pal != null) {
+ mPalette = pal;
+ changed = true;
+ }
+ }
if (mVisible && changed) {
drawFrame();
@@ -242,8 +446,13 @@
mOffsetX = xOffset;
drawFrame();
}
-
+
void drawFrame() {
+ if (mPalette == null) {
+ android.util.Log.w("PolarClockWallpaper", "no palette?!");
+ return;
+ }
+
final SurfaceHolder holder = getSurfaceHolder();
final Rect frame = holder.getSurfaceFrame();
final int width = frame.width();
@@ -255,7 +464,6 @@
if (c != null) {
final Time calendar = mCalendar;
final Paint paint = mPaint;
- final int[] colors = mColors;
calendar.setToNow();
calendar.normalize(false);
@@ -263,11 +471,8 @@
int s = width / 2;
int t = height / 2;
- if (mCycleColors) {
- c.drawColor(BACKGROUND_COLOR);
- } else {
- c.drawColor(mPalette.bg);
- }
+ c.drawColor(mPalette.getBackgroundColor());
+
c.translate(s + MathUtils.lerp(s, -s, mOffsetX), t);
c.rotate(-90.0f);
if (height < width) {
@@ -280,16 +485,13 @@
float angle;
float lastRingThickness = DEFAULT_RING_THICKNESS;
-
+
if (mShowSeconds) {
// Draw seconds
angle = ((mStartTime + SystemClock.elapsedRealtime()) % 60000) / 60000.0f;
if (angle < 0) angle = -angle;
- if (mCycleColors) {
- paint.setColor(colors[((int) (angle * COLORS_CACHE_COUNT))]);
- } else {
- paint.setColor(mPalette.second);
- }
+
+ paint.setColor(mPalette.getSecondColor(angle));
if (mVariableLineWidth) {
lastRingThickness = SMALL_RING_THICKNESS;
@@ -303,28 +505,21 @@
rect.set(-size, -size, size, size);
angle = ((calendar.minute * 60.0f + calendar.second) % 3600) / 3600.0f;
- if (mCycleColors) {
- paint.setColor(colors[((int) (angle * COLORS_CACHE_COUNT))]);
- } else {
- paint.setColor(mPalette.minute);
- }
+ paint.setColor(mPalette.getMinuteColor(angle));
if (mVariableLineWidth) {
lastRingThickness = MEDIUM_RING_THICKNESS;
paint.setStrokeWidth(lastRingThickness);
}
c.drawArc(rect, 0.0f, angle * 360.0f, false, paint);
-
+
// Draw hours
size -= (SMALL_GAP + lastRingThickness);
rect.set(-size, -size, size, size);
angle = ((calendar.hour * 60.0f + calendar.minute) % 1440) / 1440.0f;
- if (mCycleColors) {
- paint.setColor(colors[((int) (angle * COLORS_CACHE_COUNT))]);
- } else {
- paint.setColor(mPalette.hour);
- }
+ paint.setColor(mPalette.getHourColor(angle));
+
if (mVariableLineWidth) {
lastRingThickness = LARGE_RING_THICKNESS;
paint.setStrokeWidth(lastRingThickness);
@@ -337,11 +532,8 @@
angle = (calendar.monthDay - 1) /
(float) (calendar.getActualMaximum(Time.MONTH_DAY) - 1);
- if (mCycleColors) {
- paint.setColor(colors[((int) (angle * COLORS_CACHE_COUNT))]);
- } else {
- paint.setColor(mPalette.day);
- }
+ paint.setColor(mPalette.getDayColor(angle));
+
if (mVariableLineWidth) {
lastRingThickness = MEDIUM_RING_THICKNESS;
paint.setStrokeWidth(lastRingThickness);
@@ -353,11 +545,9 @@
rect.set(-size, -size, size, size);
angle = (calendar.month - 1) / 11.0f;
- if (mCycleColors) {
- paint.setColor(colors[((int) (angle * COLORS_CACHE_COUNT))]);
- } else {
- paint.setColor(mPalette.month);
- }
+
+ paint.setColor(mPalette.getMonthColor(angle));
+
if (mVariableLineWidth) {
lastRingThickness = LARGE_RING_THICKNESS;
paint.setStrokeWidth(lastRingThickness);