13d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy/*
23d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy * Copyright (C) 2012 The Android Open Source Project
33d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy *
43d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy * Licensed under the Apache License, Version 2.0 (the "License");
53d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy * you may not use this file except in compliance with the License.
63d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy * You may obtain a copy of the License at
73d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy *
83d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy *      http://www.apache.org/licenses/LICENSE-2.0
93d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy *
103d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy * Unless required by applicable law or agreed to in writing, software
113d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy * distributed under the License is distributed on an "AS IS" BASIS,
123d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
133d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy * See the License for the specific language governing permissions and
143d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy * limitations under the License.
153d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy */
163d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
173d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guypackage android.widget;
183d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
1994a6d15ede149189bba9e5f474ed853c98230e75Siva Velusamyimport android.annotation.NonNull;
209c4a707912da2c954b2d3d1311b8a691ded8aa16Selim Cinekimport android.app.ActivityManager;
213d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guyimport android.content.BroadcastReceiver;
223d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guyimport android.content.ContentResolver;
233d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guyimport android.content.Context;
243d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guyimport android.content.Intent;
253d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guyimport android.content.IntentFilter;
263d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guyimport android.content.res.TypedArray;
273d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guyimport android.database.ContentObserver;
283d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guyimport android.net.Uri;
293d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guyimport android.os.Handler;
303d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guyimport android.os.SystemClock;
319c4a707912da2c954b2d3d1311b8a691ded8aa16Selim Cinekimport android.os.UserHandle;
323d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guyimport android.provider.Settings;
333d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guyimport android.text.format.DateFormat;
343d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guyimport android.util.AttributeSet;
35a9cfe677eec0324a94509c6a5d29cec5b8a7a7cfRomain Guyimport android.view.RemotableViewMethod;
3694a6d15ede149189bba9e5f474ed853c98230e75Siva Velusamyimport android.view.ViewHierarchyEncoder;
373d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
383d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guyimport com.android.internal.R;
393d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
403d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guyimport java.util.Calendar;
413d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guyimport java.util.TimeZone;
423d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
43cdafd37f3148dfc6f44f2e5de8b31adb6bf9e476Elliott Hughesimport libcore.icu.LocaleData;
44cdafd37f3148dfc6f44f2e5de8b31adb6bf9e476Elliott Hughes
453d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guyimport static android.view.ViewDebug.ExportedProperty;
463d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guyimport static android.widget.RemoteViews.*;
473d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
483d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy/**
493d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy * <p><code>TextClock</code> can display the current date and/or time as
503d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy * a formatted string.</p>
51cdafd37f3148dfc6f44f2e5de8b31adb6bf9e476Elliott Hughes *
523d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy * <p>This view honors the 24-hour format system setting. As such, it is
533d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy * possible and recommended to provide two different formatting patterns:
543d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy * one to display the date/time in 24-hour mode and one to display the
55cdafd37f3148dfc6f44f2e5de8b31adb6bf9e476Elliott Hughes * date/time in 12-hour mode. Most callers will want to use the defaults,
56cdafd37f3148dfc6f44f2e5de8b31adb6bf9e476Elliott Hughes * though, which will be appropriate for the user's locale.</p>
57cdafd37f3148dfc6f44f2e5de8b31adb6bf9e476Elliott Hughes *
583d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy * <p>It is possible to determine whether the system is currently in
593d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy * 24-hour mode by calling {@link #is24HourModeEnabled()}.</p>
60cdafd37f3148dfc6f44f2e5de8b31adb6bf9e476Elliott Hughes *
613d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy * <p>The rules used by this widget to decide how to format the date and
623d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy * time are the following:</p>
633d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy * <ul>
643d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy *     <li>In 24-hour mode:
653d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy *         <ul>
663d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy *             <li>Use the value returned by {@link #getFormat24Hour()} when non-null</li>
673d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy *             <li>Otherwise, use the value returned by {@link #getFormat12Hour()} when non-null</li>
68cdafd37f3148dfc6f44f2e5de8b31adb6bf9e476Elliott Hughes *             <li>Otherwise, use a default value appropriate for the user's locale, such as {@code h:mm a}</li>
693d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy *         </ul>
703d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy *     </li>
713d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy *     <li>In 12-hour mode:
723d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy *         <ul>
733d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy *             <li>Use the value returned by {@link #getFormat12Hour()} when non-null</li>
743d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy *             <li>Otherwise, use the value returned by {@link #getFormat24Hour()} when non-null</li>
75cdafd37f3148dfc6f44f2e5de8b31adb6bf9e476Elliott Hughes *             <li>Otherwise, use a default value appropriate for the user's locale, such as {@code HH:mm}</li>
763d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy *         </ul>
773d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy *     </li>
783d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy * </ul>
79cdafd37f3148dfc6f44f2e5de8b31adb6bf9e476Elliott Hughes *
803d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy * <p>The {@link CharSequence} instances used as formatting patterns when calling either
813d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy * {@link #setFormat24Hour(CharSequence)} or {@link #setFormat12Hour(CharSequence)} can
82cdafd37f3148dfc6f44f2e5de8b31adb6bf9e476Elliott Hughes * contain styling information. To do so, use a {@link android.text.Spanned} object.
83cdafd37f3148dfc6f44f2e5de8b31adb6bf9e476Elliott Hughes * Note that if you customize these strings, it is your responsibility to supply strings
84cdafd37f3148dfc6f44f2e5de8b31adb6bf9e476Elliott Hughes * appropriate for formatting dates and/or times in the user's locale.</p>
85cdafd37f3148dfc6f44f2e5de8b31adb6bf9e476Elliott Hughes *
863d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy * @attr ref android.R.styleable#TextClock_format12Hour
873d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy * @attr ref android.R.styleable#TextClock_format24Hour
883d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy * @attr ref android.R.styleable#TextClock_timeZone
893d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy */
903d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy@RemoteView
913d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guypublic class TextClock extends TextView {
923d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    /**
93cdafd37f3148dfc6f44f2e5de8b31adb6bf9e476Elliott Hughes     * The default formatting pattern in 12-hour mode. This pattern is used
943d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * if {@link #setFormat12Hour(CharSequence)} is called with a null pattern
953d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * or if no pattern was specified when creating an instance of this class.
96cdafd37f3148dfc6f44f2e5de8b31adb6bf9e476Elliott Hughes     *
973d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * This default pattern shows only the time, hours and minutes, and an am/pm
983d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * indicator.
993d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     *
1003d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * @see #setFormat12Hour(CharSequence)
1013d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * @see #getFormat12Hour()
10209b1994c4d3c47bfa41374a4d420eb5110b9a48aRomain Guy     *
103cdafd37f3148dfc6f44f2e5de8b31adb6bf9e476Elliott Hughes     * @deprecated Let the system use locale-appropriate defaults instead.
1043d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     */
105cdafd37f3148dfc6f44f2e5de8b31adb6bf9e476Elliott Hughes    public static final CharSequence DEFAULT_FORMAT_12_HOUR = "h:mm a";
1063d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
1073d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    /**
108cdafd37f3148dfc6f44f2e5de8b31adb6bf9e476Elliott Hughes     * The default formatting pattern in 24-hour mode. This pattern is used
1093d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * if {@link #setFormat24Hour(CharSequence)} is called with a null pattern
1103d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * or if no pattern was specified when creating an instance of this class.
1113d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     *
1123d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * This default pattern shows only the time, hours and minutes.
113cdafd37f3148dfc6f44f2e5de8b31adb6bf9e476Elliott Hughes     *
114cdafd37f3148dfc6f44f2e5de8b31adb6bf9e476Elliott Hughes     * @see #setFormat24Hour(CharSequence)
115cdafd37f3148dfc6f44f2e5de8b31adb6bf9e476Elliott Hughes     * @see #getFormat24Hour()
11609b1994c4d3c47bfa41374a4d420eb5110b9a48aRomain Guy     *
117cdafd37f3148dfc6f44f2e5de8b31adb6bf9e476Elliott Hughes     * @deprecated Let the system use locale-appropriate defaults instead.
1183d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     */
119cdafd37f3148dfc6f44f2e5de8b31adb6bf9e476Elliott Hughes    public static final CharSequence DEFAULT_FORMAT_24_HOUR = "H:mm";
1203d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
121cdafd37f3148dfc6f44f2e5de8b31adb6bf9e476Elliott Hughes    private CharSequence mFormat12;
122cdafd37f3148dfc6f44f2e5de8b31adb6bf9e476Elliott Hughes    private CharSequence mFormat24;
12325ffc7ad950d9b2857abe9cb66ed53aed7a18ecfDan Sandler    private CharSequence mDescFormat12;
12425ffc7ad950d9b2857abe9cb66ed53aed7a18ecfDan Sandler    private CharSequence mDescFormat24;
1253d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
1263d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    @ExportedProperty
1273d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    private CharSequence mFormat;
1283d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    @ExportedProperty
1293d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    private boolean mHasSeconds;
1303d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
13125ffc7ad950d9b2857abe9cb66ed53aed7a18ecfDan Sandler    private CharSequence mDescFormat;
13225ffc7ad950d9b2857abe9cb66ed53aed7a18ecfDan Sandler
133e12cd3bb3b855a8c51273d11a6ca14f829bb27bdErik Wolsheimer    private boolean mRegistered;
1343d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
1353d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    private Calendar mTime;
1363d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    private String mTimeZone;
1373d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
1389c4a707912da2c954b2d3d1311b8a691ded8aa16Selim Cinek    private boolean mShowCurrentUserTime;
1399c4a707912da2c954b2d3d1311b8a691ded8aa16Selim Cinek
140d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck    private ContentObserver mFormatChangeObserver;
141d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck    private class FormatChangeObserver extends ContentObserver {
142d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck
143d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck        public FormatChangeObserver(Handler handler) {
144d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck            super(handler);
145d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck        }
146d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck
1473d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        @Override
1483d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        public void onChange(boolean selfChange) {
1493d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy            chooseFormat();
1503d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy            onTimeChanged();
1513d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        }
1523d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
1533d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        @Override
1543d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        public void onChange(boolean selfChange, Uri uri) {
1553d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy            chooseFormat();
1563d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy            onTimeChanged();
1573d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        }
1583d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    };
1593d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
1603d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
1613d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        @Override
1623d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        public void onReceive(Context context, Intent intent) {
163a76f7db323598f78512bbbdf2fb89248c9e317e5Romain Guy            if (mTimeZone == null && Intent.ACTION_TIMEZONE_CHANGED.equals(intent.getAction())) {
164a76f7db323598f78512bbbdf2fb89248c9e317e5Romain Guy                final String timeZone = intent.getStringExtra("time-zone");
165a76f7db323598f78512bbbdf2fb89248c9e317e5Romain Guy                createTime(timeZone);
1663d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy            }
167a76f7db323598f78512bbbdf2fb89248c9e317e5Romain Guy            onTimeChanged();
1683d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        }
1693d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    };
1703d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
1713d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    private final Runnable mTicker = new Runnable() {
1723d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        public void run() {
1733d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy            onTimeChanged();
1743d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
1753d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy            long now = SystemClock.uptimeMillis();
1763d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy            long next = now + (1000 - now % 1000);
1773d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
1783d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy            getHandler().postAtTime(mTicker, next);
1793d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        }
1803d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    };
1813d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
1823d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    /**
18309b1994c4d3c47bfa41374a4d420eb5110b9a48aRomain Guy     * Creates a new clock using the default patterns for the current locale.
184cdafd37f3148dfc6f44f2e5de8b31adb6bf9e476Elliott Hughes     *
1853d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * @param context The Context the view is running in, through which it can
1863d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     *        access the current theme, resources, etc.
1873d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     */
1883d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    @SuppressWarnings("UnusedDeclaration")
1893d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    public TextClock(Context context) {
1903d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        super(context);
1913d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        init();
1923d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    }
1933d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
1943d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    /**
1953d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * Creates a new clock inflated from XML. This object's properties are
1963d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * intialized from the attributes specified in XML.
197cdafd37f3148dfc6f44f2e5de8b31adb6bf9e476Elliott Hughes     *
1983d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * This constructor uses a default style of 0, so the only attribute values
1993d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * applied are those in the Context's Theme and the given AttributeSet.
2003d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     *
2013d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * @param context The Context the view is running in, through which it can
2023d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     *        access the current theme, resources, etc.
2033d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * @param attrs The attributes of the XML tag that is inflating the view
2043d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     */
2053d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    @SuppressWarnings("UnusedDeclaration")
2063d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    public TextClock(Context context, AttributeSet attrs) {
2073d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        this(context, attrs, 0);
2083d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    }
2093d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
2103d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    /**
2113d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * Creates a new clock inflated from XML. This object's properties are
2123d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * intialized from the attributes specified in XML.
2133d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     *
2143d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * @param context The Context the view is running in, through which it can
2153d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     *        access the current theme, resources, etc.
2163d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * @param attrs The attributes of the XML tag that is inflating the view
217617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette     * @param defStyleAttr An attribute in the current theme that contains a
218617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette     *        reference to a style resource that supplies default values for
219617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette     *        the view. Can be 0 to not look for defaults.
2203d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     */
221617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette    public TextClock(Context context, AttributeSet attrs, int defStyleAttr) {
222617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette        this(context, attrs, defStyleAttr, 0);
223617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette    }
224617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette
225617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette    public TextClock(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
226617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette        super(context, attrs, defStyleAttr, defStyleRes);
2273d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
228617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette        final TypedArray a = context.obtainStyledAttributes(
229617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette                attrs, R.styleable.TextClock, defStyleAttr, defStyleRes);
2303d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        try {
231cdafd37f3148dfc6f44f2e5de8b31adb6bf9e476Elliott Hughes            mFormat12 = a.getText(R.styleable.TextClock_format12Hour);
232cdafd37f3148dfc6f44f2e5de8b31adb6bf9e476Elliott Hughes            mFormat24 = a.getText(R.styleable.TextClock_format24Hour);
2333d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy            mTimeZone = a.getString(R.styleable.TextClock_timeZone);
2343d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        } finally {
2353d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy            a.recycle();
2363d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        }
2373d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
2383d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        init();
2393d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    }
2403d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
2413d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    private void init() {
242cdafd37f3148dfc6f44f2e5de8b31adb6bf9e476Elliott Hughes        if (mFormat12 == null || mFormat24 == null) {
243cdafd37f3148dfc6f44f2e5de8b31adb6bf9e476Elliott Hughes            LocaleData ld = LocaleData.get(getContext().getResources().getConfiguration().locale);
244cdafd37f3148dfc6f44f2e5de8b31adb6bf9e476Elliott Hughes            if (mFormat12 == null) {
245f7d5e0a53e168f2acc17b098bdd4b927fa1b1d6cElliott Hughes                mFormat12 = ld.timeFormat_hm;
246cdafd37f3148dfc6f44f2e5de8b31adb6bf9e476Elliott Hughes            }
247cdafd37f3148dfc6f44f2e5de8b31adb6bf9e476Elliott Hughes            if (mFormat24 == null) {
248f7d5e0a53e168f2acc17b098bdd4b927fa1b1d6cElliott Hughes                mFormat24 = ld.timeFormat_Hm;
249cdafd37f3148dfc6f44f2e5de8b31adb6bf9e476Elliott Hughes            }
250cdafd37f3148dfc6f44f2e5de8b31adb6bf9e476Elliott Hughes        }
251cdafd37f3148dfc6f44f2e5de8b31adb6bf9e476Elliott Hughes
2523d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        createTime(mTimeZone);
253e12cd3bb3b855a8c51273d11a6ca14f829bb27bdErik Wolsheimer        // Wait until registering for events to handle the ticker
2543d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        chooseFormat(false);
2553d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    }
2563d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
2573d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    private void createTime(String timeZone) {
2583d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        if (timeZone != null) {
2593d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy            mTime = Calendar.getInstance(TimeZone.getTimeZone(timeZone));
2603d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        } else {
2613d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy            mTime = Calendar.getInstance();
2623d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        }
2633d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    }
2643d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
2653d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    /**
2663d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * Returns the formatting pattern used to display the date and/or time
2673d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * in 12-hour mode. The formatting pattern syntax is described in
2683d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * {@link DateFormat}.
269cdafd37f3148dfc6f44f2e5de8b31adb6bf9e476Elliott Hughes     *
2703d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * @return A {@link CharSequence} or null.
271cdafd37f3148dfc6f44f2e5de8b31adb6bf9e476Elliott Hughes     *
272cdafd37f3148dfc6f44f2e5de8b31adb6bf9e476Elliott Hughes     * @see #setFormat12Hour(CharSequence)
273cdafd37f3148dfc6f44f2e5de8b31adb6bf9e476Elliott Hughes     * @see #is24HourModeEnabled()
2743d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     */
2753d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    @ExportedProperty
2763d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    public CharSequence getFormat12Hour() {
2773d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        return mFormat12;
2783d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    }
2793d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
2803d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    /**
28109b1994c4d3c47bfa41374a4d420eb5110b9a48aRomain Guy     * <p>Specifies the formatting pattern used to display the date and/or time
2823d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * in 12-hour mode. The formatting pattern syntax is described in
28309b1994c4d3c47bfa41374a4d420eb5110b9a48aRomain Guy     * {@link DateFormat}.</p>
2843d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     *
28509b1994c4d3c47bfa41374a4d420eb5110b9a48aRomain Guy     * <p>If this pattern is set to null, {@link #getFormat24Hour()} will be used
2863d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * even in 12-hour mode. If both 24-hour and 12-hour formatting patterns
28709b1994c4d3c47bfa41374a4d420eb5110b9a48aRomain Guy     * are set to null, the default pattern for the current locale will be used
28809b1994c4d3c47bfa41374a4d420eb5110b9a48aRomain Guy     * instead.</p>
28909b1994c4d3c47bfa41374a4d420eb5110b9a48aRomain Guy     *
29009b1994c4d3c47bfa41374a4d420eb5110b9a48aRomain Guy     * <p><strong>Note:</strong> if styling is not needed, it is highly recommended
29109b1994c4d3c47bfa41374a4d420eb5110b9a48aRomain Guy     * you supply a format string generated by
29209b1994c4d3c47bfa41374a4d420eb5110b9a48aRomain Guy     * {@link DateFormat#getBestDateTimePattern(java.util.Locale, String)}. This method
29309b1994c4d3c47bfa41374a4d420eb5110b9a48aRomain Guy     * takes care of generating a format string adapted to the desired locale.</p>
29409b1994c4d3c47bfa41374a4d420eb5110b9a48aRomain Guy     *
2953d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     *
2963d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * @param format A date/time formatting pattern as described in {@link DateFormat}
297cdafd37f3148dfc6f44f2e5de8b31adb6bf9e476Elliott Hughes     *
2983d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * @see #getFormat12Hour()
2993d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * @see #is24HourModeEnabled()
30009b1994c4d3c47bfa41374a4d420eb5110b9a48aRomain Guy     * @see DateFormat#getBestDateTimePattern(java.util.Locale, String)
3013d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * @see DateFormat
302cdafd37f3148dfc6f44f2e5de8b31adb6bf9e476Elliott Hughes     *
3033d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * @attr ref android.R.styleable#TextClock_format12Hour
3043d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     */
305a9cfe677eec0324a94509c6a5d29cec5b8a7a7cfRomain Guy    @RemotableViewMethod
3063d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    public void setFormat12Hour(CharSequence format) {
3073d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        mFormat12 = format;
3083d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
3093d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        chooseFormat();
3103d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        onTimeChanged();
3113d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    }
3123d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
3133d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    /**
31425ffc7ad950d9b2857abe9cb66ed53aed7a18ecfDan Sandler     * Like setFormat12Hour, but for the content description.
31525ffc7ad950d9b2857abe9cb66ed53aed7a18ecfDan Sandler     * @hide
31625ffc7ad950d9b2857abe9cb66ed53aed7a18ecfDan Sandler     */
31725ffc7ad950d9b2857abe9cb66ed53aed7a18ecfDan Sandler    public void setContentDescriptionFormat12Hour(CharSequence format) {
31825ffc7ad950d9b2857abe9cb66ed53aed7a18ecfDan Sandler        mDescFormat12 = format;
31925ffc7ad950d9b2857abe9cb66ed53aed7a18ecfDan Sandler
32025ffc7ad950d9b2857abe9cb66ed53aed7a18ecfDan Sandler        chooseFormat();
32125ffc7ad950d9b2857abe9cb66ed53aed7a18ecfDan Sandler        onTimeChanged();
32225ffc7ad950d9b2857abe9cb66ed53aed7a18ecfDan Sandler    }
32325ffc7ad950d9b2857abe9cb66ed53aed7a18ecfDan Sandler
32425ffc7ad950d9b2857abe9cb66ed53aed7a18ecfDan Sandler    /**
3253d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * Returns the formatting pattern used to display the date and/or time
3263d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * in 24-hour mode. The formatting pattern syntax is described in
3273d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * {@link DateFormat}.
3283d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     *
3293d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * @return A {@link CharSequence} or null.
3303d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     *
3313d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * @see #setFormat24Hour(CharSequence)
3323d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * @see #is24HourModeEnabled()
3333d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     */
3343d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    @ExportedProperty
3353d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    public CharSequence getFormat24Hour() {
3363d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        return mFormat24;
3373d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    }
3383d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
3393d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    /**
34009b1994c4d3c47bfa41374a4d420eb5110b9a48aRomain Guy     * <p>Specifies the formatting pattern used to display the date and/or time
3413d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * in 24-hour mode. The formatting pattern syntax is described in
34209b1994c4d3c47bfa41374a4d420eb5110b9a48aRomain Guy     * {@link DateFormat}.</p>
34309b1994c4d3c47bfa41374a4d420eb5110b9a48aRomain Guy     *
34409b1994c4d3c47bfa41374a4d420eb5110b9a48aRomain Guy     * <p>If this pattern is set to null, {@link #getFormat24Hour()} will be used
34509b1994c4d3c47bfa41374a4d420eb5110b9a48aRomain Guy     * even in 12-hour mode. If both 24-hour and 12-hour formatting patterns
34609b1994c4d3c47bfa41374a4d420eb5110b9a48aRomain Guy     * are set to null, the default pattern for the current locale will be used
34709b1994c4d3c47bfa41374a4d420eb5110b9a48aRomain Guy     * instead.</p>
348cdafd37f3148dfc6f44f2e5de8b31adb6bf9e476Elliott Hughes     *
34909b1994c4d3c47bfa41374a4d420eb5110b9a48aRomain Guy     * <p><strong>Note:</strong> if styling is not needed, it is highly recommended
35009b1994c4d3c47bfa41374a4d420eb5110b9a48aRomain Guy     * you supply a format string generated by
35109b1994c4d3c47bfa41374a4d420eb5110b9a48aRomain Guy     * {@link DateFormat#getBestDateTimePattern(java.util.Locale, String)}. This method
35209b1994c4d3c47bfa41374a4d420eb5110b9a48aRomain Guy     * takes care of generating a format string adapted to the desired locale.</p>
3533d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     *
3543d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * @param format A date/time formatting pattern as described in {@link DateFormat}
3553d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     *
3563d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * @see #getFormat24Hour()
357cdafd37f3148dfc6f44f2e5de8b31adb6bf9e476Elliott Hughes     * @see #is24HourModeEnabled()
35809b1994c4d3c47bfa41374a4d420eb5110b9a48aRomain Guy     * @see DateFormat#getBestDateTimePattern(java.util.Locale, String)
3593d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * @see DateFormat
3603d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     *
3613d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * @attr ref android.R.styleable#TextClock_format24Hour
3623d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     */
363a9cfe677eec0324a94509c6a5d29cec5b8a7a7cfRomain Guy    @RemotableViewMethod
3643d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    public void setFormat24Hour(CharSequence format) {
3653d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        mFormat24 = format;
3663d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
3673d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        chooseFormat();
3683d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        onTimeChanged();
3693d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    }
3703d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
3713d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    /**
37225ffc7ad950d9b2857abe9cb66ed53aed7a18ecfDan Sandler     * Like setFormat24Hour, but for the content description.
37325ffc7ad950d9b2857abe9cb66ed53aed7a18ecfDan Sandler     * @hide
37425ffc7ad950d9b2857abe9cb66ed53aed7a18ecfDan Sandler     */
37525ffc7ad950d9b2857abe9cb66ed53aed7a18ecfDan Sandler    public void setContentDescriptionFormat24Hour(CharSequence format) {
37625ffc7ad950d9b2857abe9cb66ed53aed7a18ecfDan Sandler        mDescFormat24 = format;
37725ffc7ad950d9b2857abe9cb66ed53aed7a18ecfDan Sandler
37825ffc7ad950d9b2857abe9cb66ed53aed7a18ecfDan Sandler        chooseFormat();
37925ffc7ad950d9b2857abe9cb66ed53aed7a18ecfDan Sandler        onTimeChanged();
38025ffc7ad950d9b2857abe9cb66ed53aed7a18ecfDan Sandler    }
38125ffc7ad950d9b2857abe9cb66ed53aed7a18ecfDan Sandler
38225ffc7ad950d9b2857abe9cb66ed53aed7a18ecfDan Sandler    /**
3839c4a707912da2c954b2d3d1311b8a691ded8aa16Selim Cinek     * Sets whether this clock should always track the current user and not the user of the
3849c4a707912da2c954b2d3d1311b8a691ded8aa16Selim Cinek     * current process. This is used for single instance processes like the systemUI who need
3859c4a707912da2c954b2d3d1311b8a691ded8aa16Selim Cinek     * to display time for different users.
3869c4a707912da2c954b2d3d1311b8a691ded8aa16Selim Cinek     *
3879c4a707912da2c954b2d3d1311b8a691ded8aa16Selim Cinek     * @hide
3889c4a707912da2c954b2d3d1311b8a691ded8aa16Selim Cinek     */
3899c4a707912da2c954b2d3d1311b8a691ded8aa16Selim Cinek    public void setShowCurrentUserTime(boolean showCurrentUserTime) {
3909c4a707912da2c954b2d3d1311b8a691ded8aa16Selim Cinek        mShowCurrentUserTime = showCurrentUserTime;
3919c4a707912da2c954b2d3d1311b8a691ded8aa16Selim Cinek
3929c4a707912da2c954b2d3d1311b8a691ded8aa16Selim Cinek        chooseFormat();
3939c4a707912da2c954b2d3d1311b8a691ded8aa16Selim Cinek        onTimeChanged();
3949c4a707912da2c954b2d3d1311b8a691ded8aa16Selim Cinek        unregisterObserver();
3959c4a707912da2c954b2d3d1311b8a691ded8aa16Selim Cinek        registerObserver();
3969c4a707912da2c954b2d3d1311b8a691ded8aa16Selim Cinek    }
3979c4a707912da2c954b2d3d1311b8a691ded8aa16Selim Cinek
3989c4a707912da2c954b2d3d1311b8a691ded8aa16Selim Cinek    /**
3993d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * Indicates whether the system is currently using the 24-hour mode.
400cdafd37f3148dfc6f44f2e5de8b31adb6bf9e476Elliott Hughes     *
4013d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * When the system is in 24-hour mode, this view will use the pattern
4023d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * returned by {@link #getFormat24Hour()}. In 12-hour mode, the pattern
4033d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * returned by {@link #getFormat12Hour()} is used instead.
404cdafd37f3148dfc6f44f2e5de8b31adb6bf9e476Elliott Hughes     *
4053d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * If either one of the formats is null, the other format is used. If
40609b1994c4d3c47bfa41374a4d420eb5110b9a48aRomain Guy     * both formats are null, the default formats for the current locale are used.
407cdafd37f3148dfc6f44f2e5de8b31adb6bf9e476Elliott Hughes     *
4083d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * @return true if time should be displayed in 24-hour format, false if it
4093d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     *         should be displayed in 12-hour format.
410cdafd37f3148dfc6f44f2e5de8b31adb6bf9e476Elliott Hughes     *
4113d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * @see #setFormat12Hour(CharSequence)
412cdafd37f3148dfc6f44f2e5de8b31adb6bf9e476Elliott Hughes     * @see #getFormat12Hour()
4133d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * @see #setFormat24Hour(CharSequence)
414cdafd37f3148dfc6f44f2e5de8b31adb6bf9e476Elliott Hughes     * @see #getFormat24Hour()
4153d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     */
4163d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    public boolean is24HourModeEnabled() {
4179c4a707912da2c954b2d3d1311b8a691ded8aa16Selim Cinek        if (mShowCurrentUserTime) {
4189c4a707912da2c954b2d3d1311b8a691ded8aa16Selim Cinek            return DateFormat.is24HourFormat(getContext(), ActivityManager.getCurrentUser());
4199c4a707912da2c954b2d3d1311b8a691ded8aa16Selim Cinek        } else {
4209c4a707912da2c954b2d3d1311b8a691ded8aa16Selim Cinek            return DateFormat.is24HourFormat(getContext());
4219c4a707912da2c954b2d3d1311b8a691ded8aa16Selim Cinek        }
4223d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    }
4233d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
4243d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    /**
4253d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * Indicates which time zone is currently used by this view.
426cdafd37f3148dfc6f44f2e5de8b31adb6bf9e476Elliott Hughes     *
4273d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * @return The ID of the current time zone or null if the default time zone,
4283d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     *         as set by the user, must be used
4293d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     *
4303d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * @see TimeZone
4313d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * @see java.util.TimeZone#getAvailableIDs()
432cdafd37f3148dfc6f44f2e5de8b31adb6bf9e476Elliott Hughes     * @see #setTimeZone(String)
4333d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     */
4343d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    public String getTimeZone() {
4353d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        return mTimeZone;
4363d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    }
4373d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
4383d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    /**
4393d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * Sets the specified time zone to use in this clock. When the time zone
4403d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * is set through this method, system time zone changes (when the user
4413d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * sets the time zone in settings for instance) will be ignored.
4423d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     *
4433d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * @param timeZone The desired time zone's ID as specified in {@link TimeZone}
4443d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     *                 or null to user the time zone specified by the user
4453d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     *                 (system time zone)
4463d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     *
4473d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * @see #getTimeZone()
4483d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * @see java.util.TimeZone#getAvailableIDs()
4493d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * @see TimeZone#getTimeZone(String)
4503d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     *
4513d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * @attr ref android.R.styleable#TextClock_timeZone
4523d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     */
453a9cfe677eec0324a94509c6a5d29cec5b8a7a7cfRomain Guy    @RemotableViewMethod
4543d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    public void setTimeZone(String timeZone) {
4553d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        mTimeZone = timeZone;
4563d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
4573d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        createTime(timeZone);
4583d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        onTimeChanged();
4593d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    }
4603d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
4613d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    /**
4623d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * Selects either one of {@link #getFormat12Hour()} or {@link #getFormat24Hour()}
4633d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * depending on whether the user has selected 24-hour format.
464cdafd37f3148dfc6f44f2e5de8b31adb6bf9e476Elliott Hughes     *
4653d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * Calling this method does not schedule or unschedule the time ticker.
4663d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     */
4673d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    private void chooseFormat() {
4683d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        chooseFormat(true);
4693d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    }
4703d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
4713d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    /**
47206c5f8a768bcd4f7b6441f7525bd5c639399fc76Jeff Sharkey     * Returns the current format string. Always valid after constructor has
47306c5f8a768bcd4f7b6441f7525bd5c639399fc76Jeff Sharkey     * finished, and will never be {@code null}.
47406c5f8a768bcd4f7b6441f7525bd5c639399fc76Jeff Sharkey     *
47506c5f8a768bcd4f7b6441f7525bd5c639399fc76Jeff Sharkey     * @hide
47606c5f8a768bcd4f7b6441f7525bd5c639399fc76Jeff Sharkey     */
47706c5f8a768bcd4f7b6441f7525bd5c639399fc76Jeff Sharkey    public CharSequence getFormat() {
47806c5f8a768bcd4f7b6441f7525bd5c639399fc76Jeff Sharkey        return mFormat;
47906c5f8a768bcd4f7b6441f7525bd5c639399fc76Jeff Sharkey    }
48006c5f8a768bcd4f7b6441f7525bd5c639399fc76Jeff Sharkey
48106c5f8a768bcd4f7b6441f7525bd5c639399fc76Jeff Sharkey    /**
4823d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * Selects either one of {@link #getFormat12Hour()} or {@link #getFormat24Hour()}
4833d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * depending on whether the user has selected 24-hour format.
484cdafd37f3148dfc6f44f2e5de8b31adb6bf9e476Elliott Hughes     *
4853d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * @param handleTicker true if calling this method should schedule/unschedule the
4863d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     *                     time ticker, false otherwise
4873d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     */
4883d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    private void chooseFormat(boolean handleTicker) {
4893d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        final boolean format24Requested = is24HourModeEnabled();
4903d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
491cdafd37f3148dfc6f44f2e5de8b31adb6bf9e476Elliott Hughes        LocaleData ld = LocaleData.get(getContext().getResources().getConfiguration().locale);
492cdafd37f3148dfc6f44f2e5de8b31adb6bf9e476Elliott Hughes
4933d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        if (format24Requested) {
494f7d5e0a53e168f2acc17b098bdd4b927fa1b1d6cElliott Hughes            mFormat = abc(mFormat24, mFormat12, ld.timeFormat_Hm);
49525ffc7ad950d9b2857abe9cb66ed53aed7a18ecfDan Sandler            mDescFormat = abc(mDescFormat24, mDescFormat12, mFormat);
4963d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        } else {
497f7d5e0a53e168f2acc17b098bdd4b927fa1b1d6cElliott Hughes            mFormat = abc(mFormat12, mFormat24, ld.timeFormat_hm);
49825ffc7ad950d9b2857abe9cb66ed53aed7a18ecfDan Sandler            mDescFormat = abc(mDescFormat12, mDescFormat24, mFormat);
4993d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        }
5003d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
5013d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        boolean hadSeconds = mHasSeconds;
5023d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        mHasSeconds = DateFormat.hasSeconds(mFormat);
5033d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
504e12cd3bb3b855a8c51273d11a6ca14f829bb27bdErik Wolsheimer        if (handleTicker && mRegistered && hadSeconds != mHasSeconds) {
505a76f7db323598f78512bbbdf2fb89248c9e317e5Romain Guy            if (hadSeconds) getHandler().removeCallbacks(mTicker);
506a76f7db323598f78512bbbdf2fb89248c9e317e5Romain Guy            else mTicker.run();
5073d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        }
5083d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    }
5093d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
5103d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    /**
5113d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * Returns a if not null, else return b if not null, else return c.
5123d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     */
5133d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    private static CharSequence abc(CharSequence a, CharSequence b, CharSequence c) {
5143d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        return a == null ? (b == null ? c : b) : a;
5153d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    }
5163d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
5173d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    @Override
518e12cd3bb3b855a8c51273d11a6ca14f829bb27bdErik Wolsheimer    public void onVisibilityAggregated(boolean isVisible) {
519e12cd3bb3b855a8c51273d11a6ca14f829bb27bdErik Wolsheimer        if (!mRegistered && isVisible) {
520e12cd3bb3b855a8c51273d11a6ca14f829bb27bdErik Wolsheimer            mRegistered = true;
5213d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
5223d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy            registerReceiver();
5233d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy            registerObserver();
5243d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
5253d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy            createTime(mTimeZone);
5263d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
5273d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy            if (mHasSeconds) {
5283d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy                mTicker.run();
5293d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy            } else {
5303d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy                onTimeChanged();
5313d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy            }
532e12cd3bb3b855a8c51273d11a6ca14f829bb27bdErik Wolsheimer        } else if (mRegistered && !isVisible) {
5333d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy            unregisterReceiver();
5343d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy            unregisterObserver();
5353d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
5363d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy            getHandler().removeCallbacks(mTicker);
5373d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
538e12cd3bb3b855a8c51273d11a6ca14f829bb27bdErik Wolsheimer            mRegistered = false;
5393d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        }
5403d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    }
5413d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
5423d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    private void registerReceiver() {
5433d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        final IntentFilter filter = new IntentFilter();
5443d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
5453d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        filter.addAction(Intent.ACTION_TIME_TICK);
5463d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        filter.addAction(Intent.ACTION_TIME_CHANGED);
5473d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
5483d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
5495a33106d7eb1a7fd22eaa6bdaace25aa09af7b61Oleksandr Peletskyi        // OK, this is gross but needed. This class is supported by the
5505a33106d7eb1a7fd22eaa6bdaace25aa09af7b61Oleksandr Peletskyi        // remote views mechanism and as a part of that the remote views
5515a33106d7eb1a7fd22eaa6bdaace25aa09af7b61Oleksandr Peletskyi        // can be inflated by a context for another user without the app
5525a33106d7eb1a7fd22eaa6bdaace25aa09af7b61Oleksandr Peletskyi        // having interact users permission - just for loading resources.
5535a33106d7eb1a7fd22eaa6bdaace25aa09af7b61Oleksandr Peletskyi        // For example, when adding widgets from a managed profile to the
5545a33106d7eb1a7fd22eaa6bdaace25aa09af7b61Oleksandr Peletskyi        // home screen. Therefore, we register the receiver as the user
5555a33106d7eb1a7fd22eaa6bdaace25aa09af7b61Oleksandr Peletskyi        // the app is running as not the one the context is for.
5565a33106d7eb1a7fd22eaa6bdaace25aa09af7b61Oleksandr Peletskyi        getContext().registerReceiverAsUser(mIntentReceiver, android.os.Process.myUserHandle(),
5575a33106d7eb1a7fd22eaa6bdaace25aa09af7b61Oleksandr Peletskyi                filter, null, getHandler());
5583d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    }
5593d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
5603d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    private void registerObserver() {
561e12cd3bb3b855a8c51273d11a6ca14f829bb27bdErik Wolsheimer        if (mRegistered) {
562d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck            if (mFormatChangeObserver == null) {
563d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck                mFormatChangeObserver = new FormatChangeObserver(getHandler());
564d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck            }
565d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck            final ContentResolver resolver = getContext().getContentResolver();
566d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck            if (mShowCurrentUserTime) {
567d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck                resolver.registerContentObserver(Settings.System.CONTENT_URI, true,
568d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck                        mFormatChangeObserver, UserHandle.USER_ALL);
569d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck            } else {
570d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck                resolver.registerContentObserver(Settings.System.CONTENT_URI, true,
571d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck                        mFormatChangeObserver);
572d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck            }
5739c4a707912da2c954b2d3d1311b8a691ded8aa16Selim Cinek        }
5743d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    }
5753d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
5763d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    private void unregisterReceiver() {
5773d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        getContext().unregisterReceiver(mIntentReceiver);
5783d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    }
5793d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
5803d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    private void unregisterObserver() {
581d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck        if (mFormatChangeObserver != null) {
582d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck            final ContentResolver resolver = getContext().getContentResolver();
583d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck            resolver.unregisterContentObserver(mFormatChangeObserver);
584d0374c6b25c3ad8e638827bd8190553f80d9bf22John Reck        }
5853d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    }
5863d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
5873d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    private void onTimeChanged() {
5883d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        mTime.setTimeInMillis(System.currentTimeMillis());
5893d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        setText(DateFormat.format(mFormat, mTime));
59025ffc7ad950d9b2857abe9cb66ed53aed7a18ecfDan Sandler        setContentDescription(DateFormat.format(mDescFormat, mTime));
5913d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    }
59294a6d15ede149189bba9e5f474ed853c98230e75Siva Velusamy
59394a6d15ede149189bba9e5f474ed853c98230e75Siva Velusamy    /** @hide */
59494a6d15ede149189bba9e5f474ed853c98230e75Siva Velusamy    @Override
59594a6d15ede149189bba9e5f474ed853c98230e75Siva Velusamy    protected void encodeProperties(@NonNull ViewHierarchyEncoder stream) {
59694a6d15ede149189bba9e5f474ed853c98230e75Siva Velusamy        super.encodeProperties(stream);
59794a6d15ede149189bba9e5f474ed853c98230e75Siva Velusamy
59894a6d15ede149189bba9e5f474ed853c98230e75Siva Velusamy        CharSequence s = getFormat12Hour();
59994a6d15ede149189bba9e5f474ed853c98230e75Siva Velusamy        stream.addProperty("format12Hour", s == null ? null : s.toString());
60094a6d15ede149189bba9e5f474ed853c98230e75Siva Velusamy
60194a6d15ede149189bba9e5f474ed853c98230e75Siva Velusamy        s = getFormat24Hour();
60294a6d15ede149189bba9e5f474ed853c98230e75Siva Velusamy        stream.addProperty("format24Hour", s == null ? null : s.toString());
60394a6d15ede149189bba9e5f474ed853c98230e75Siva Velusamy        stream.addProperty("format", mFormat == null ? null : mFormat.toString());
60494a6d15ede149189bba9e5f474ed853c98230e75Siva Velusamy        stream.addProperty("hasSeconds", mHasSeconds);
60594a6d15ede149189bba9e5f474ed853c98230e75Siva Velusamy    }
6063d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy}
607