summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRomain Guy <romainguy@google.com>2012-10-31 20:31:58 -0700
committerRomain Guy <romainguy@google.com>2012-10-31 20:31:58 -0700
commit3d1728c03a0cd1aaed6bc81c97de27d62c771a6e (patch)
tree3707b6ba1cfb8b11dade485a5132397425ee14ab
parentac14efce4b9575ac1de567073d7088162d4d2eed (diff)
downloadframeworks_base-3d1728c03a0cd1aaed6bc81c97de27d62c771a6e.zip
frameworks_base-3d1728c03a0cd1aaed6bc81c97de27d62c771a6e.tar.gz
frameworks_base-3d1728c03a0cd1aaed6bc81c97de27d62c771a6e.tar.bz2
A new clock widget to create lock screen appwidgets
This new widget replaces DigitalClock. It listens to all the correct system events and offer the ability to customize the formatting patterns in 12-hour and 24-hour modes. It also supports fixed time zones to create world clocks. One more step towards becoming ClockOS! Change-Id: I677e5dfca8cd8c8d1f8c49e54d7507f4d1885bf4
-rw-r--r--api/17.txt34
-rw-r--r--api/current.txt34
-rw-r--r--core/java/android/text/format/DateFormat.java97
-rw-r--r--core/java/android/view/View.java2
-rw-r--r--core/java/android/widget/DigitalClock.java31
-rw-r--r--core/java/android/widget/TextClock.java482
-rwxr-xr-xcore/res/res/values/attrs.xml18
-rw-r--r--core/res/res/values/public.xml3
8 files changed, 651 insertions, 50 deletions
diff --git a/api/17.txt b/api/17.txt
index e26d8f0..fde6302 100644
--- a/api/17.txt
+++ b/api/17.txt
@@ -491,6 +491,8 @@ package android {
field public static final int foreground = 16843017; // 0x1010109
field public static final int foregroundGravity = 16843264; // 0x1010200
field public static final int format = 16843013; // 0x1010105
+ field public static final int format12Hour = 16843722; // 0x10103ca
+ field public static final int format24Hour = 16843723; // 0x10103cb
field public static final int fragment = 16843491; // 0x10102e3
field public static final int fragmentCloseEnterAnimation = 16843495; // 0x10102e7
field public static final int fragmentCloseExitAnimation = 16843496; // 0x10102e8
@@ -1074,6 +1076,7 @@ package android {
field public static final int thumbTextPadding = 16843634; // 0x1010372
field public static final int thumbnail = 16843429; // 0x10102a5
field public static final int tileMode = 16843265; // 0x1010201
+ field public static final int timeZone = 16843724; // 0x10103cc
field public static final int tint = 16843041; // 0x1010121
field public static final int title = 16843233; // 0x10101e1
field public static final int titleCondensed = 16843234; // 0x10101e2
@@ -22300,14 +22303,14 @@ package android.text.format {
public class DateFormat {
ctor public DateFormat();
- method public static final java.lang.CharSequence format(java.lang.CharSequence, long);
- method public static final java.lang.CharSequence format(java.lang.CharSequence, java.util.Date);
- method public static final java.lang.CharSequence format(java.lang.CharSequence, java.util.Calendar);
- method public static final java.text.DateFormat getDateFormat(android.content.Context);
- method public static final char[] getDateFormatOrder(android.content.Context);
- method public static final java.text.DateFormat getLongDateFormat(android.content.Context);
- method public static final java.text.DateFormat getMediumDateFormat(android.content.Context);
- method public static final java.text.DateFormat getTimeFormat(android.content.Context);
+ method public static java.lang.CharSequence format(java.lang.CharSequence, long);
+ method public static java.lang.CharSequence format(java.lang.CharSequence, java.util.Date);
+ method public static java.lang.CharSequence format(java.lang.CharSequence, java.util.Calendar);
+ method public static java.text.DateFormat getDateFormat(android.content.Context);
+ method public static char[] getDateFormatOrder(android.content.Context);
+ method public static java.text.DateFormat getLongDateFormat(android.content.Context);
+ method public static java.text.DateFormat getMediumDateFormat(android.content.Context);
+ method public static java.text.DateFormat getTimeFormat(android.content.Context);
method public static boolean is24HourFormat(android.content.Context);
field public static final char AM_PM = 97; // 0x0061 'a'
field public static final char CAPITAL_AM_PM = 65; // 0x0041 'A'
@@ -29518,6 +29521,21 @@ package android.widget {
field public int span;
}
+ public class TextClock extends android.widget.TextView {
+ ctor public TextClock(android.content.Context);
+ ctor public TextClock(android.content.Context, android.util.AttributeSet);
+ ctor public TextClock(android.content.Context, android.util.AttributeSet, int);
+ method public java.lang.CharSequence getFormat12Hour();
+ method public java.lang.CharSequence getFormat24Hour();
+ method public java.lang.String getTimeZone();
+ method public boolean is24HourModeEnabled();
+ method public void setFormat12Hour(java.lang.CharSequence);
+ method public void setFormat24Hour(java.lang.CharSequence);
+ method public void setTimeZone(java.lang.String);
+ field public static final java.lang.CharSequence DEFAULT_FORMAT_12_HOUR;
+ field public static final java.lang.CharSequence DEFAULT_FORMAT_24_HOUR;
+ }
+
public class TextSwitcher extends android.widget.ViewSwitcher {
ctor public TextSwitcher(android.content.Context);
ctor public TextSwitcher(android.content.Context, android.util.AttributeSet);
diff --git a/api/current.txt b/api/current.txt
index e26d8f0..fde6302 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -491,6 +491,8 @@ package android {
field public static final int foreground = 16843017; // 0x1010109
field public static final int foregroundGravity = 16843264; // 0x1010200
field public static final int format = 16843013; // 0x1010105
+ field public static final int format12Hour = 16843722; // 0x10103ca
+ field public static final int format24Hour = 16843723; // 0x10103cb
field public static final int fragment = 16843491; // 0x10102e3
field public static final int fragmentCloseEnterAnimation = 16843495; // 0x10102e7
field public static final int fragmentCloseExitAnimation = 16843496; // 0x10102e8
@@ -1074,6 +1076,7 @@ package android {
field public static final int thumbTextPadding = 16843634; // 0x1010372
field public static final int thumbnail = 16843429; // 0x10102a5
field public static final int tileMode = 16843265; // 0x1010201
+ field public static final int timeZone = 16843724; // 0x10103cc
field public static final int tint = 16843041; // 0x1010121
field public static final int title = 16843233; // 0x10101e1
field public static final int titleCondensed = 16843234; // 0x10101e2
@@ -22300,14 +22303,14 @@ package android.text.format {
public class DateFormat {
ctor public DateFormat();
- method public static final java.lang.CharSequence format(java.lang.CharSequence, long);
- method public static final java.lang.CharSequence format(java.lang.CharSequence, java.util.Date);
- method public static final java.lang.CharSequence format(java.lang.CharSequence, java.util.Calendar);
- method public static final java.text.DateFormat getDateFormat(android.content.Context);
- method public static final char[] getDateFormatOrder(android.content.Context);
- method public static final java.text.DateFormat getLongDateFormat(android.content.Context);
- method public static final java.text.DateFormat getMediumDateFormat(android.content.Context);
- method public static final java.text.DateFormat getTimeFormat(android.content.Context);
+ method public static java.lang.CharSequence format(java.lang.CharSequence, long);
+ method public static java.lang.CharSequence format(java.lang.CharSequence, java.util.Date);
+ method public static java.lang.CharSequence format(java.lang.CharSequence, java.util.Calendar);
+ method public static java.text.DateFormat getDateFormat(android.content.Context);
+ method public static char[] getDateFormatOrder(android.content.Context);
+ method public static java.text.DateFormat getLongDateFormat(android.content.Context);
+ method public static java.text.DateFormat getMediumDateFormat(android.content.Context);
+ method public static java.text.DateFormat getTimeFormat(android.content.Context);
method public static boolean is24HourFormat(android.content.Context);
field public static final char AM_PM = 97; // 0x0061 'a'
field public static final char CAPITAL_AM_PM = 65; // 0x0041 'A'
@@ -29518,6 +29521,21 @@ package android.widget {
field public int span;
}
+ public class TextClock extends android.widget.TextView {
+ ctor public TextClock(android.content.Context);
+ ctor public TextClock(android.content.Context, android.util.AttributeSet);
+ ctor public TextClock(android.content.Context, android.util.AttributeSet, int);
+ method public java.lang.CharSequence getFormat12Hour();
+ method public java.lang.CharSequence getFormat24Hour();
+ method public java.lang.String getTimeZone();
+ method public boolean is24HourModeEnabled();
+ method public void setFormat12Hour(java.lang.CharSequence);
+ method public void setFormat24Hour(java.lang.CharSequence);
+ method public void setTimeZone(java.lang.String);
+ field public static final java.lang.CharSequence DEFAULT_FORMAT_12_HOUR;
+ field public static final java.lang.CharSequence DEFAULT_FORMAT_24_HOUR;
+ }
+
public class TextSwitcher extends android.widget.ViewSwitcher {
ctor public TextSwitcher(android.content.Context);
ctor public TextSwitcher(android.content.Context, android.util.AttributeSet);
diff --git a/core/java/android/text/format/DateFormat.java b/core/java/android/text/format/DateFormat.java
index c36273e..3c984b5 100644
--- a/core/java/android/text/format/DateFormat.java
+++ b/core/java/android/text/format/DateFormat.java
@@ -249,12 +249,13 @@ public class DateFormat {
synchronized (sLocaleLock) {
sIs24HourLocale = locale;
- sIs24Hour = !value.equals("12");
+ sIs24Hour = value.equals("24");
}
+
+ return sIs24Hour;
}
- boolean b24 = !(value == null || value.equals("12"));
- return b24;
+ return value.equals("24");
}
/**
@@ -263,7 +264,7 @@ public class DateFormat {
* @param context the application context
* @return the {@link java.text.DateFormat} object that properly formats the time.
*/
- public static final java.text.DateFormat getTimeFormat(Context context) {
+ public static java.text.DateFormat getTimeFormat(Context context) {
boolean b24 = is24HourFormat(context);
int res;
@@ -283,7 +284,7 @@ public class DateFormat {
* @param context the application context
* @return the {@link java.text.DateFormat} object that properly formats the date.
*/
- public static final java.text.DateFormat getDateFormat(Context context) {
+ public static java.text.DateFormat getDateFormat(Context context) {
String value = Settings.System.getString(context.getContentResolver(),
Settings.System.DATE_FORMAT);
@@ -353,7 +354,7 @@ public class DateFormat {
* @param context the application context
* @return the {@link java.text.DateFormat} object that formats the date in long form.
*/
- public static final java.text.DateFormat getLongDateFormat(Context context) {
+ public static java.text.DateFormat getLongDateFormat(Context context) {
return java.text.DateFormat.getDateInstance(java.text.DateFormat.LONG);
}
@@ -363,7 +364,7 @@ public class DateFormat {
* @param context the application context
* @return the {@link java.text.DateFormat} object that formats the date in long form.
*/
- public static final java.text.DateFormat getMediumDateFormat(Context context) {
+ public static java.text.DateFormat getMediumDateFormat(Context context) {
return java.text.DateFormat.getDateInstance(java.text.DateFormat.MEDIUM);
}
@@ -376,7 +377,7 @@ public class DateFormat {
* not just the day, month, and year, and not necessarily in the same
* order returned here.
*/
- public static final char[] getDateFormatOrder(Context context) {
+ public static char[] getDateFormatOrder(Context context) {
char[] order = new char[] {DATE, MONTH, YEAR};
String value = getDateFormatString(context);
int index = 0;
@@ -420,7 +421,7 @@ public class DateFormat {
* @param inTimeInMillis in milliseconds since Jan 1, 1970 GMT
* @return a {@link CharSequence} containing the requested text
*/
- public static final CharSequence format(CharSequence inFormat, long inTimeInMillis) {
+ public static CharSequence format(CharSequence inFormat, long inTimeInMillis) {
return format(inFormat, new Date(inTimeInMillis));
}
@@ -431,7 +432,7 @@ public class DateFormat {
* @param inDate the date to format
* @return a {@link CharSequence} containing the requested text
*/
- public static final CharSequence format(CharSequence inFormat, Date inDate) {
+ public static CharSequence format(CharSequence inFormat, Date inDate) {
Calendar c = new GregorianCalendar();
c.setTime(inDate);
@@ -440,13 +441,75 @@ public class DateFormat {
}
/**
+ * Indicates whether the specified format string contains seconds.
+ *
+ * Always returns false if the input format is null.
+ *
+ * @param inFormat the format string, as described in {@link android.text.format.DateFormat}
+ *
+ * @return true if the format string contains {@link #SECONDS}, false otherwise
+ *
+ * @hide
+ */
+ public static boolean hasSeconds(CharSequence inFormat) {
+ if (inFormat == null) return false;
+
+ final int length = inFormat.length();
+
+ int c;
+ int count;
+
+ for (int i = 0; i < length; i += count) {
+ count = 1;
+ c = inFormat.charAt(i);
+
+ if (c == QUOTE) {
+ count = skipQuotedText(inFormat, i, length);
+ } else if (c == SECONDS) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ private static int skipQuotedText(CharSequence s, int i, int len) {
+ if (i + 1 < len && s.charAt(i + 1) == QUOTE) {
+ return 2;
+ }
+
+ int count = 1;
+ // skip leading quote
+ i++;
+
+ while (i < len) {
+ char c = s.charAt(i);
+
+ if (c == QUOTE) {
+ count++;
+ // QUOTEQUOTE -> QUOTE
+ if (i + 1 < len && s.charAt(i + 1) == QUOTE) {
+ i++;
+ } else {
+ break;
+ }
+ } else {
+ i++;
+ count++;
+ }
+ }
+
+ return count;
+ }
+
+ /**
* Given a format string and a {@link java.util.Calendar} object, returns a CharSequence
* containing the requested date.
* @param inFormat the format string, as described in {@link android.text.format.DateFormat}
* @param inDate the date to format
* @return a {@link CharSequence} containing the requested text
*/
- public static final CharSequence format(CharSequence inFormat, Calendar inDate) {
+ public static CharSequence format(CharSequence inFormat, Calendar inDate) {
SpannableStringBuilder s = new SpannableStringBuilder(inFormat);
int c;
int count;
@@ -545,7 +608,7 @@ public class DateFormat {
return s.toString();
}
- private static final String getMonthString(Calendar inDate, int count, int kind) {
+ private static String getMonthString(Calendar inDate, int count, int kind) {
boolean standalone = (kind == STANDALONE_MONTH);
int month = inDate.get(Calendar.MONTH);
@@ -563,7 +626,7 @@ public class DateFormat {
}
}
- private static final String getTimeZoneString(Calendar inDate, int count) {
+ private static String getTimeZoneString(Calendar inDate, int count) {
TimeZone tz = inDate.getTimeZone();
if (count < 2) { // FIXME: shouldn't this be <= 2 ?
@@ -576,7 +639,7 @@ public class DateFormat {
}
}
- private static final String formatZoneOffset(int offset, int count) {
+ private static String formatZoneOffset(int offset, int count) {
offset /= 1000; // milliseconds to seconds
StringBuilder tb = new StringBuilder();
@@ -595,13 +658,13 @@ public class DateFormat {
return tb.toString();
}
- private static final String getYearString(Calendar inDate, int count) {
+ private static String getYearString(Calendar inDate, int count) {
int year = inDate.get(Calendar.YEAR);
return (count <= 2) ? zeroPad(year % 100, 2)
: String.format(Locale.getDefault(), "%d", year);
}
- private static final int appendQuotedText(SpannableStringBuilder s, int i, int len) {
+ private static int appendQuotedText(SpannableStringBuilder s, int i, int len) {
if (i + 1 < len && s.charAt(i + 1) == QUOTE) {
s.delete(i, i + 1);
return 1;
@@ -638,7 +701,7 @@ public class DateFormat {
return count;
}
- private static final String zeroPad(int inValue, int inMinDigits) {
+ private static String zeroPad(int inValue, int inMinDigits) {
return String.format(Locale.getDefault(), "%0" + inMinDigits + "d", inValue);
}
}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 9d0d4f0..d5e1ed3 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -17697,7 +17697,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
boolean mScalingRequired;
/**
- * If set, ViewAncestor doesn't use its lame animation for when the window resizes.
+ * If set, ViewRootImpl doesn't use its lame animation for when the window resizes.
*/
boolean mTurnOffWindowResizeAnim;
diff --git a/core/java/android/widget/DigitalClock.java b/core/java/android/widget/DigitalClock.java
index 3e9107f..c6b6dd6 100644
--- a/core/java/android/widget/DigitalClock.java
+++ b/core/java/android/widget/DigitalClock.java
@@ -17,7 +17,6 @@
package android.widget;
import android.content.Context;
-import android.content.res.Resources;
import android.database.ContentObserver;
import android.os.Handler;
import android.os.SystemClock;
@@ -32,14 +31,12 @@ import java.util.Calendar;
/**
* Like AnalogClock, but digital. Shows seconds.
*
- * FIXME: implement separate views for hours/minutes/seconds, so
- * proportional fonts don't shake rendering
- *
- * @deprecated It is recommended you use a {@link TextView} and {@link DateFormat}
- * to implement the same behavior.
+ * @deprecated It is recommended you use {@link TextClock} instead.
*/
@Deprecated
public class DigitalClock extends TextView {
+ // FIXME: implement separate views for hours/minutes/seconds, so
+ // proportional fonts don't shake rendering
Calendar mCalendar;
private final static String m12 = "h:mm:ss aa";
@@ -86,16 +83,16 @@ public class DigitalClock extends TextView {
* requests a tick on the next hard-second boundary
*/
mTicker = new Runnable() {
- public void run() {
- if (mTickerStopped) return;
- mCalendar.setTimeInMillis(System.currentTimeMillis());
- setText(DateFormat.format(mFormat, mCalendar));
- invalidate();
- long now = SystemClock.uptimeMillis();
- long next = now + (1000 - now % 1000);
- mHandler.postAtTime(mTicker, next);
- }
- };
+ public void run() {
+ if (mTickerStopped) return;
+ mCalendar.setTimeInMillis(System.currentTimeMillis());
+ setText(DateFormat.format(mFormat, mCalendar));
+ invalidate();
+ long now = SystemClock.uptimeMillis();
+ long next = now + (1000 - now % 1000);
+ mHandler.postAtTime(mTicker, next);
+ }
+ };
mTicker.run();
}
@@ -134,12 +131,14 @@ public class DigitalClock extends TextView {
@Override
public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
super.onInitializeAccessibilityEvent(event);
+ //noinspection deprecation
event.setClassName(DigitalClock.class.getName());
}
@Override
public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
super.onInitializeAccessibilityNodeInfo(info);
+ //noinspection deprecation
info.setClassName(DigitalClock.class.getName());
}
}
diff --git a/core/java/android/widget/TextClock.java b/core/java/android/widget/TextClock.java
new file mode 100644
index 0000000..4c46658
--- /dev/null
+++ b/core/java/android/widget/TextClock.java
@@ -0,0 +1,482 @@
+/*
+ * Copyright (C) 2012 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.
+ */
+
+package android.widget;
+
+import android.content.BroadcastReceiver;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.res.TypedArray;
+import android.database.ContentObserver;
+import android.net.Uri;
+import android.os.Handler;
+import android.os.SystemClock;
+import android.provider.Settings;
+import android.text.format.DateFormat;
+import android.util.AttributeSet;
+
+import com.android.internal.R;
+
+import java.util.Calendar;
+import java.util.TimeZone;
+
+import static android.view.ViewDebug.ExportedProperty;
+import static android.widget.RemoteViews.*;
+
+/**
+ * <p><code>TextClock</code> can display the current date and/or time as
+ * a formatted string.</p>
+ *
+ * <p>This view honors the 24-hour format system setting. As such, it is
+ * possible and recommended to provide two different formatting patterns:
+ * one to display the date/time in 24-hour mode and one to display the
+ * date/time in 12-hour mode.</p>
+ *
+ * <p>It is possible to determine whether the system is currently in
+ * 24-hour mode by calling {@link #is24HourModeEnabled()}.</p>
+ *
+ * <p>The rules used by this widget to decide how to format the date and
+ * time are the following:</p>
+ * <ul>
+ * <li>In 24-hour mode:
+ * <ul>
+ * <li>Use the value returned by {@link #getFormat24Hour()} when non-null</li>
+ * <li>Otherwise, use the value returned by {@link #getFormat12Hour()} when non-null</li>
+ * <li>Otherwise, use {@link #DEFAULT_FORMAT_24_HOUR}</li>
+ * </ul>
+ * </li>
+ * <li>In 12-hour mode:
+ * <ul>
+ * <li>Use the value returned by {@link #getFormat12Hour()} when non-null</li>
+ * <li>Otherwise, use the value returned by {@link #getFormat24Hour()} when non-null</li>
+ * <li>Otherwise, use {@link #DEFAULT_FORMAT_12_HOUR}</li>
+ * </ul>
+ * </li>
+ * </ul>
+ *
+ * <p>The {@link CharSequence} instances used as formatting patterns when calling either
+ * {@link #setFormat24Hour(CharSequence)} or {@link #setFormat12Hour(CharSequence)} can
+ * contain styling information. To do so, use a {@link android.text.Spanned} object.</p>
+ *
+ * @attr ref android.R.styleable#TextClock_format12Hour
+ * @attr ref android.R.styleable#TextClock_format24Hour
+ * @attr ref android.R.styleable#TextClock_timeZone
+ */
+@RemoteView
+public class TextClock extends TextView {
+ /**
+ * The default formatting pattern in 12-hour mode. This pattenr is used
+ * if {@link #setFormat12Hour(CharSequence)} is called with a null pattern
+ * or if no pattern was specified when creating an instance of this class.
+ *
+ * This default pattern shows only the time, hours and minutes, and an am/pm
+ * indicator.
+ *
+ * @see #setFormat12Hour(CharSequence)
+ * @see #getFormat12Hour()
+ */
+ public static final CharSequence DEFAULT_FORMAT_12_HOUR = "h:mm aa";
+
+ /**
+ * The default formatting pattern in 24-hour mode. This pattenr is used
+ * if {@link #setFormat24Hour(CharSequence)} is called with a null pattern
+ * or if no pattern was specified when creating an instance of this class.
+ *
+ * This default pattern shows only the time, hours and minutes.
+ *
+ * @see #setFormat24Hour(CharSequence)
+ * @see #getFormat24Hour()
+ */
+ public static final CharSequence DEFAULT_FORMAT_24_HOUR = "k:mm";
+
+ private CharSequence mFormat12 = DEFAULT_FORMAT_12_HOUR;
+ private CharSequence mFormat24 = DEFAULT_FORMAT_24_HOUR;
+
+ @ExportedProperty
+ private CharSequence mFormat;
+ @ExportedProperty
+ private boolean mHasSeconds;
+
+ private boolean mAttached;
+
+ private Calendar mTime;
+ private String mTimeZone;
+
+ private final ContentObserver mFormatChangeObserver = new ContentObserver(new Handler()) {
+ @Override
+ public void onChange(boolean selfChange) {
+ chooseFormat();
+ onTimeChanged();
+ }
+
+ @Override
+ public void onChange(boolean selfChange, Uri uri) {
+ chooseFormat();
+ onTimeChanged();
+ }
+ };
+
+ private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (mTimeZone == null) {
+ if (intent.getAction().equals(Intent.ACTION_TIMEZONE_CHANGED)) {
+ final String timeZone = intent.getStringExtra("time-zone");
+ createTime(timeZone);
+ }
+ onTimeChanged();
+ }
+ }
+ };
+
+ private final Runnable mTicker = new Runnable() {
+ public void run() {
+ onTimeChanged();
+
+ long now = SystemClock.uptimeMillis();
+ long next = now + (1000 - now % 1000);
+
+ getHandler().postAtTime(mTicker, next);
+ }
+ };
+
+ /**
+ * Creates a new clock using the default patterns
+ * {@link #DEFAULT_FORMAT_24_HOUR} and {@link #DEFAULT_FORMAT_12_HOUR}
+ * respectively for the 24-hour and 12-hour modes.
+ *
+ * @param context The Context the view is running in, through which it can
+ * access the current theme, resources, etc.
+ */
+ @SuppressWarnings("UnusedDeclaration")
+ public TextClock(Context context) {
+ super(context);
+ init();
+ }
+
+ /**
+ * Creates a new clock inflated from XML. This object's properties are
+ * intialized from the attributes specified in XML.
+ *
+ * This constructor uses a default style of 0, so the only attribute values
+ * applied are those in the Context's Theme and the given AttributeSet.
+ *
+ * @param context The Context the view is running in, through which it can
+ * access the current theme, resources, etc.
+ * @param attrs The attributes of the XML tag that is inflating the view
+ */
+ @SuppressWarnings("UnusedDeclaration")
+ public TextClock(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ /**
+ * Creates a new clock inflated from XML. This object's properties are
+ * intialized from the attributes specified in XML.
+ *
+ * @param context The Context the view is running in, through which it can
+ * access the current theme, resources, etc.
+ * @param attrs The attributes of the XML tag that is inflating the view
+ * @param defStyle The default style to apply to this view. If 0, no style
+ * will be applied (beyond what is included in the theme). This may
+ * either be an attribute resource, whose value will be retrieved
+ * from the current theme, or an explicit style resource
+ */
+ public TextClock(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+
+ TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.TextClock, defStyle, 0);
+ try {
+ CharSequence format;
+
+ format = a.getText(R.styleable.TextClock_format12Hour);
+ mFormat12 = format == null ? DEFAULT_FORMAT_12_HOUR : format;
+
+ format = a.getText(R.styleable.TextClock_format24Hour);
+ mFormat24 = format == null ? DEFAULT_FORMAT_24_HOUR : format;
+
+ mTimeZone = a.getString(R.styleable.TextClock_timeZone);
+ } finally {
+ a.recycle();
+ }
+
+ init();
+ }
+
+ private void init() {
+ createTime(mTimeZone);
+ // Wait until onAttachedToWindow() to handle the ticker
+ chooseFormat(false);
+ }
+
+ private void createTime(String timeZone) {
+ if (timeZone != null) {
+ mTime = Calendar.getInstance(TimeZone.getTimeZone(timeZone));
+ } else {
+ mTime = Calendar.getInstance();
+ }
+ }
+
+ /**
+ * Returns the formatting pattern used to display the date and/or time
+ * in 12-hour mode. The formatting pattern syntax is described in
+ * {@link DateFormat}.
+ *
+ * @return A {@link CharSequence} or null.
+ *
+ * @see #setFormat12Hour(CharSequence)
+ * @see #is24HourModeEnabled()
+ */
+ @ExportedProperty
+ public CharSequence getFormat12Hour() {
+ return mFormat12;
+ }
+
+ /**
+ * Specifies the formatting pattern used to display the date and/or time
+ * in 12-hour mode. The formatting pattern syntax is described in
+ * {@link DateFormat}.
+ *
+ * If this pattern is set to null, {@link #getFormat24Hour()} will be used
+ * even in 12-hour mode. If both 24-hour and 12-hour formatting patterns
+ * are set to null, {@link #DEFAULT_FORMAT_24_HOUR} and
+ * {@link #DEFAULT_FORMAT_12_HOUR} will be used instead.
+ *
+ * @param format A date/time formatting pattern as described in {@link DateFormat}
+ *
+ * @see #getFormat12Hour()
+ * @see #is24HourModeEnabled()
+ * @see #DEFAULT_FORMAT_12_HOUR
+ * @see DateFormat
+ *
+ * @attr ref android.R.styleable#TextClock_format12Hour
+ */
+ public void setFormat12Hour(CharSequence format) {
+ mFormat12 = format;
+
+ chooseFormat();
+ onTimeChanged();
+ }
+
+ /**
+ * Returns the formatting pattern used to display the date and/or time
+ * in 24-hour mode. The formatting pattern syntax is described in
+ * {@link DateFormat}.
+ *
+ * @return A {@link CharSequence} or null.
+ *
+ * @see #setFormat24Hour(CharSequence)
+ * @see #is24HourModeEnabled()
+ */
+ @ExportedProperty
+ public CharSequence getFormat24Hour() {
+ return mFormat24;
+ }
+
+ /**
+ * Specifies the formatting pattern used to display the date and/or time
+ * in 24-hour mode. The formatting pattern syntax is described in
+ * {@link DateFormat}.
+ *
+ * If this pattern is set to null, {@link #getFormat12Hour()} will be used
+ * even in 24-hour mode. If both 24-hour and 12-hour formatting patterns
+ * are set to null, {@link #DEFAULT_FORMAT_24_HOUR} and
+ * {@link #DEFAULT_FORMAT_12_HOUR} will be used instead.
+ *
+ * @param format A date/time formatting pattern as described in {@link DateFormat}
+ *
+ * @see #getFormat24Hour()
+ * @see #is24HourModeEnabled()
+ * @see #DEFAULT_FORMAT_24_HOUR
+ * @see DateFormat
+ *
+ * @attr ref android.R.styleable#TextClock_format24Hour
+ */
+ public void setFormat24Hour(CharSequence format) {
+ mFormat24 = format;
+
+ chooseFormat();
+ onTimeChanged();
+ }
+
+ /**
+ * Indicates whether the system is currently using the 24-hour mode.
+ *
+ * When the system is in 24-hour mode, this view will use the pattern
+ * returned by {@link #getFormat24Hour()}. In 12-hour mode, the pattern
+ * returned by {@link #getFormat12Hour()} is used instead.
+ *
+ * If either one of the formats is null, the other format is used. If
+ * both formats are null, the default values {@link #DEFAULT_FORMAT_12_HOUR}
+ * and {@link #DEFAULT_FORMAT_24_HOUR} are used instead.
+ *
+ * @return true if time should be displayed in 24-hour format, false if it
+ * should be displayed in 12-hour format.
+ *
+ * @see #setFormat12Hour(CharSequence)
+ * @see #getFormat12Hour()
+ * @see #setFormat24Hour(CharSequence)
+ * @see #getFormat24Hour()
+ */
+ public boolean is24HourModeEnabled() {
+ return DateFormat.is24HourFormat(getContext());
+ }
+
+ /**
+ * Indicates which time zone is currently used by this view.
+ *
+ * @return The ID of the current time zone or null if the default time zone,
+ * as set by the user, must be used
+ *
+ * @see TimeZone
+ * @see java.util.TimeZone#getAvailableIDs()
+ * @see #setTimeZone(String)
+ */
+ public String getTimeZone() {
+ return mTimeZone;
+ }
+
+ /**
+ * Sets the specified time zone to use in this clock. When the time zone
+ * is set through this method, system time zone changes (when the user
+ * sets the time zone in settings for instance) will be ignored.
+ *
+ * @param timeZone The desired time zone's ID as specified in {@link TimeZone}
+ * or null to user the time zone specified by the user
+ * (system time zone)
+ *
+ * @see #getTimeZone()
+ * @see java.util.TimeZone#getAvailableIDs()
+ * @see TimeZone#getTimeZone(String)
+ *
+ * @attr ref android.R.styleable#TextClock_timeZone
+ */
+ public void setTimeZone(String timeZone) {
+ mTimeZone = timeZone;
+
+ createTime(timeZone);
+ onTimeChanged();
+ }
+
+ /**
+ * Selects either one of {@link #getFormat12Hour()} or {@link #getFormat24Hour()}
+ * depending on whether the user has selected 24-hour format.
+ *
+ * Calling this method does not schedule or unschedule the time ticker.
+ */
+ private void chooseFormat() {
+ chooseFormat(true);
+ }
+
+ /**
+ * Selects either one of {@link #getFormat12Hour()} or {@link #getFormat24Hour()}
+ * depending on whether the user has selected 24-hour format.
+ *
+ * @param handleTicker true if calling this method should schedule/unschedule the
+ * time ticker, false otherwise
+ */
+ private void chooseFormat(boolean handleTicker) {
+ final boolean format24Requested = is24HourModeEnabled();
+
+ if (format24Requested) {
+ mFormat = abc(mFormat24, mFormat12, DEFAULT_FORMAT_24_HOUR);
+ } else {
+ mFormat = abc(mFormat12, mFormat24, DEFAULT_FORMAT_12_HOUR);
+ }
+
+ boolean hadSeconds = mHasSeconds;
+ mHasSeconds = DateFormat.hasSeconds(mFormat);
+
+ if (handleTicker) {
+ if (hadSeconds != mHasSeconds) {
+ if (hadSeconds) getHandler().removeCallbacks(mTicker);
+ else mTicker.run();
+ }
+ }
+ }
+
+ /**
+ * Returns a if not null, else return b if not null, else return c.
+ */
+ private static CharSequence abc(CharSequence a, CharSequence b, CharSequence c) {
+ return a == null ? (b == null ? c : b) : a;
+ }
+
+ @Override
+ protected void onAttachedToWindow() {
+ super.onAttachedToWindow();
+
+ if (!mAttached) {
+ mAttached = true;
+
+ registerReceiver();
+ registerObserver();
+
+ createTime(mTimeZone);
+
+ if (mHasSeconds) {
+ mTicker.run();
+ } else {
+ onTimeChanged();
+ }
+ }
+ }
+
+ @Override
+ protected void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+
+ if (mAttached) {
+ unregisterReceiver();
+ unregisterObserver();
+
+ getHandler().removeCallbacks(mTicker);
+
+ mAttached = false;
+ }
+ }
+
+ private void registerReceiver() {
+ final IntentFilter filter = new IntentFilter();
+
+ filter.addAction(Intent.ACTION_TIME_TICK);
+ filter.addAction(Intent.ACTION_TIME_CHANGED);
+ filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
+
+ getContext().registerReceiver(mIntentReceiver, filter, null, getHandler());
+ }
+
+ private void registerObserver() {
+ final ContentResolver resolver = getContext().getContentResolver();
+ resolver.registerContentObserver(Settings.System.CONTENT_URI, true, mFormatChangeObserver);
+ }
+
+ private void unregisterReceiver() {
+ getContext().unregisterReceiver(mIntentReceiver);
+ }
+
+ private void unregisterObserver() {
+ final ContentResolver resolver = getContext().getContentResolver();
+ resolver.unregisterContentObserver(mFormatChangeObserver);
+ }
+
+ private void onTimeChanged() {
+ mTime.setTimeInMillis(System.currentTimeMillis());
+ setText(DateFormat.format(mFormat, mTime));
+ }
+}
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index d186c4a..6505ad0 100755
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -3046,6 +3046,24 @@
<!-- Present the text in ALL CAPS. This may use a small-caps form when available. -->
<attr name="textAllCaps" format="boolean" />
</declare-styleable>
+ <declare-styleable name="TextClock">
+ <!-- Specifies the formatting pattern used to show the time and/or date
+ in 12-hour mode. Please refer to {@link android.text.format.DateFormat}
+ for a complete description of accepted formatting patterns.
+ The default pattern is "h:mm aa". -->
+ <attr name="format12Hour" format="string"/>
+ <!-- Specifies the formatting pattern used to show the time and/or date
+ in 24-hour mode. Please refer to {@link android.text.format.DateFormat}
+ for a complete description of accepted formatting patterns.
+ The default pattern is "k:mm". -->
+ <attr name="format24Hour" format="string"/>
+ <!-- Specifies the time zone to use. When this attribute is specified, the
+ TextClock will ignore the time zone of the system. To use the user's
+ time zone, do not specify this attribute. The default value is the
+ user's time zone. Please refer to {@link java.util.TimeZone} for more
+ information about time zone ids. -->
+ <attr name="timeZone" format="string"/>
+ </declare-styleable>
<declare-styleable name="TextSwitcher">
</declare-styleable>
<declare-styleable name="TextView">
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index d7a480b..06d3110 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2020,6 +2020,9 @@
<public type="attr" name="permissionFlags" id="0x010103c7" />
<public type="attr" name="checkedTextViewStyle" id="0x010103c8" />
<public type="attr" name="showOnLockScreen" id="0x010103c9" />
+ <public type="attr" name="format12Hour" id="0x010103ca" />
+ <public type="attr" name="format24Hour" id="0x010103cb" />
+ <public type="attr" name="timeZone" id="0x010103cc" />
<public type="style" name="Widget.Holo.CheckedTextView" id="0x010301d9" />
<public type="style" name="Widget.Holo.Light.CheckedTextView" id="0x010301da" />