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
193d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guyimport android.content.BroadcastReceiver;
203d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guyimport android.content.ContentResolver;
213d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guyimport android.content.Context;
223d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guyimport android.content.Intent;
233d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guyimport android.content.IntentFilter;
243d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guyimport android.content.res.TypedArray;
253d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guyimport android.database.ContentObserver;
263d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guyimport android.net.Uri;
273d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guyimport android.os.Handler;
283d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guyimport android.os.SystemClock;
293d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guyimport android.provider.Settings;
303d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guyimport android.text.format.DateFormat;
313d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guyimport android.util.AttributeSet;
32a9cfe677eec0324a94509c6a5d29cec5b8a7a7cfRomain Guyimport android.view.RemotableViewMethod;
333d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
343d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guyimport com.android.internal.R;
353d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
363d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guyimport java.util.Calendar;
373d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guyimport java.util.TimeZone;
383d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
393d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guyimport static android.view.ViewDebug.ExportedProperty;
403d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guyimport static android.widget.RemoteViews.*;
413d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
423d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy/**
433d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy * <p><code>TextClock</code> can display the current date and/or time as
443d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy * a formatted string.</p>
453d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy *
463d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy * <p>This view honors the 24-hour format system setting. As such, it is
473d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy * possible and recommended to provide two different formatting patterns:
483d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy * one to display the date/time in 24-hour mode and one to display the
493d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy * date/time in 12-hour mode.</p>
503d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy *
513d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy * <p>It is possible to determine whether the system is currently in
523d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy * 24-hour mode by calling {@link #is24HourModeEnabled()}.</p>
533d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy *
543d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy * <p>The rules used by this widget to decide how to format the date and
553d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy * time are the following:</p>
563d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy * <ul>
573d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy *     <li>In 24-hour mode:
583d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy *         <ul>
593d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy *             <li>Use the value returned by {@link #getFormat24Hour()} when non-null</li>
603d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy *             <li>Otherwise, use the value returned by {@link #getFormat12Hour()} when non-null</li>
613d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy *             <li>Otherwise, use {@link #DEFAULT_FORMAT_24_HOUR}</li>
623d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy *         </ul>
633d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy *     </li>
643d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy *     <li>In 12-hour mode:
653d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy *         <ul>
663d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy *             <li>Use the value returned by {@link #getFormat12Hour()} when non-null</li>
673d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy *             <li>Otherwise, use the value returned by {@link #getFormat24Hour()} when non-null</li>
683d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy *             <li>Otherwise, use {@link #DEFAULT_FORMAT_12_HOUR}</li>
693d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy *         </ul>
703d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy *     </li>
713d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy * </ul>
723d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy *
733d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy * <p>The {@link CharSequence} instances used as formatting patterns when calling either
743d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy * {@link #setFormat24Hour(CharSequence)} or {@link #setFormat12Hour(CharSequence)} can
753d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy * contain styling information. To do so, use a {@link android.text.Spanned} object.</p>
763d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy *
773d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy * @attr ref android.R.styleable#TextClock_format12Hour
783d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy * @attr ref android.R.styleable#TextClock_format24Hour
793d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy * @attr ref android.R.styleable#TextClock_timeZone
803d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy */
813d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy@RemoteView
823d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guypublic class TextClock extends TextView {
833d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    /**
843d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * The default formatting pattern in 12-hour mode. This pattenr is used
853d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * if {@link #setFormat12Hour(CharSequence)} is called with a null pattern
863d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * or if no pattern was specified when creating an instance of this class.
873d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     *
883d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * This default pattern shows only the time, hours and minutes, and an am/pm
893d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * indicator.
903d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     *
913d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * @see #setFormat12Hour(CharSequence)
923d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * @see #getFormat12Hour()
933d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     */
943d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    public static final CharSequence DEFAULT_FORMAT_12_HOUR = "h:mm aa";
953d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
963d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    /**
973d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * The default formatting pattern in 24-hour mode. This pattenr is used
983d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * if {@link #setFormat24Hour(CharSequence)} is called with a null pattern
993d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * or if no pattern was specified when creating an instance of this class.
1003d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     *
1013d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * This default pattern shows only the time, hours and minutes.
1023d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     *
1033d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * @see #setFormat24Hour(CharSequence)
1043d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * @see #getFormat24Hour()
1053d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     */
1063d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    public static final CharSequence DEFAULT_FORMAT_24_HOUR = "k:mm";
1073d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
1083d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    private CharSequence mFormat12 = DEFAULT_FORMAT_12_HOUR;
1093d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    private CharSequence mFormat24 = DEFAULT_FORMAT_24_HOUR;
1103d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
1113d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    @ExportedProperty
1123d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    private CharSequence mFormat;
1133d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    @ExportedProperty
1143d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    private boolean mHasSeconds;
1153d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
1163d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    private boolean mAttached;
1173d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
1183d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    private Calendar mTime;
1193d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    private String mTimeZone;
1203d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
1213d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    private final ContentObserver mFormatChangeObserver = new ContentObserver(new Handler()) {
1223d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        @Override
1233d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        public void onChange(boolean selfChange) {
1243d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy            chooseFormat();
1253d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy            onTimeChanged();
1263d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        }
1273d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
1283d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        @Override
1293d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        public void onChange(boolean selfChange, Uri uri) {
1303d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy            chooseFormat();
1313d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy            onTimeChanged();
1323d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        }
1333d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    };
1343d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
1353d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
1363d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        @Override
1373d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        public void onReceive(Context context, Intent intent) {
138a76f7db323598f78512bbbdf2fb89248c9e317e5Romain Guy            if (mTimeZone == null && Intent.ACTION_TIMEZONE_CHANGED.equals(intent.getAction())) {
139a76f7db323598f78512bbbdf2fb89248c9e317e5Romain Guy                final String timeZone = intent.getStringExtra("time-zone");
140a76f7db323598f78512bbbdf2fb89248c9e317e5Romain Guy                createTime(timeZone);
1413d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy            }
142a76f7db323598f78512bbbdf2fb89248c9e317e5Romain Guy            onTimeChanged();
1433d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        }
1443d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    };
1453d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
1463d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    private final Runnable mTicker = new Runnable() {
1473d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        public void run() {
1483d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy            onTimeChanged();
1493d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
1503d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy            long now = SystemClock.uptimeMillis();
1513d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy            long next = now + (1000 - now % 1000);
1523d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
1533d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy            getHandler().postAtTime(mTicker, next);
1543d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        }
1553d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    };
1563d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
1573d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    /**
1583d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * Creates a new clock using the default patterns
1593d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * {@link #DEFAULT_FORMAT_24_HOUR} and {@link #DEFAULT_FORMAT_12_HOUR}
1603d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * respectively for the 24-hour and 12-hour modes.
1613d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     *
1623d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * @param context The Context the view is running in, through which it can
1633d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     *        access the current theme, resources, etc.
1643d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     */
1653d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    @SuppressWarnings("UnusedDeclaration")
1663d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    public TextClock(Context context) {
1673d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        super(context);
1683d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        init();
1693d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    }
1703d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
1713d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    /**
1723d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * Creates a new clock inflated from XML. This object's properties are
1733d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * intialized from the attributes specified in XML.
1743d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     *
1753d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * This constructor uses a default style of 0, so the only attribute values
1763d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * applied are those in the Context's Theme and the given AttributeSet.
1773d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     *
1783d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * @param context The Context the view is running in, through which it can
1793d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     *        access the current theme, resources, etc.
1803d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * @param attrs The attributes of the XML tag that is inflating the view
1813d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     */
1823d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    @SuppressWarnings("UnusedDeclaration")
1833d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    public TextClock(Context context, AttributeSet attrs) {
1843d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        this(context, attrs, 0);
1853d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    }
1863d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
1873d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    /**
1883d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * Creates a new clock inflated from XML. This object's properties are
1893d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * intialized from the attributes specified in XML.
1903d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     *
1913d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * @param context The Context the view is running in, through which it can
1923d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     *        access the current theme, resources, etc.
1933d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * @param attrs The attributes of the XML tag that is inflating the view
1943d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * @param defStyle The default style to apply to this view. If 0, no style
1953d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     *        will be applied (beyond what is included in the theme). This may
1963d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     *        either be an attribute resource, whose value will be retrieved
1973d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     *        from the current theme, or an explicit style resource
1983d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     */
1993d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    public TextClock(Context context, AttributeSet attrs, int defStyle) {
2003d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        super(context, attrs, defStyle);
2013d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
2023d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.TextClock, defStyle, 0);
2033d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        try {
2043d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy            CharSequence format;
2053d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
2063d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy            format = a.getText(R.styleable.TextClock_format12Hour);
2073d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy            mFormat12 = format == null ? DEFAULT_FORMAT_12_HOUR : format;
2083d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
2093d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy            format = a.getText(R.styleable.TextClock_format24Hour);
2103d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy            mFormat24 = format == null ? DEFAULT_FORMAT_24_HOUR : format;
2113d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
2123d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy            mTimeZone = a.getString(R.styleable.TextClock_timeZone);
2133d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        } finally {
2143d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy            a.recycle();
2153d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        }
2163d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
2173d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        init();
2183d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    }
2193d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
2203d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    private void init() {
2213d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        createTime(mTimeZone);
2223d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        // Wait until onAttachedToWindow() to handle the ticker
2233d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        chooseFormat(false);
2243d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    }
2253d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
2263d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    private void createTime(String timeZone) {
2273d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        if (timeZone != null) {
2283d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy            mTime = Calendar.getInstance(TimeZone.getTimeZone(timeZone));
2293d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        } else {
2303d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy            mTime = Calendar.getInstance();
2313d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        }
2323d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    }
2333d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
2343d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    /**
2353d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * Returns the formatting pattern used to display the date and/or time
2363d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * in 12-hour mode. The formatting pattern syntax is described in
2373d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * {@link DateFormat}.
2383d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     *
2393d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * @return A {@link CharSequence} or null.
2403d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     *
2413d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * @see #setFormat12Hour(CharSequence)
2423d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * @see #is24HourModeEnabled()
2433d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     */
2443d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    @ExportedProperty
2453d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    public CharSequence getFormat12Hour() {
2463d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        return mFormat12;
2473d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    }
2483d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
2493d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    /**
2503d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * Specifies the formatting pattern used to display the date and/or time
2513d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * in 12-hour mode. The formatting pattern syntax is described in
2523d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * {@link DateFormat}.
2533d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     *
2543d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * If this pattern is set to null, {@link #getFormat24Hour()} will be used
2553d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * even in 12-hour mode. If both 24-hour and 12-hour formatting patterns
2563d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * are set to null, {@link #DEFAULT_FORMAT_24_HOUR} and
2573d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * {@link #DEFAULT_FORMAT_12_HOUR} will be used instead.
2583d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     *
2593d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * @param format A date/time formatting pattern as described in {@link DateFormat}
2603d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     *
2613d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * @see #getFormat12Hour()
2623d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * @see #is24HourModeEnabled()
2633d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * @see #DEFAULT_FORMAT_12_HOUR
2643d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * @see DateFormat
2653d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     *
2663d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * @attr ref android.R.styleable#TextClock_format12Hour
2673d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     */
268a9cfe677eec0324a94509c6a5d29cec5b8a7a7cfRomain Guy    @RemotableViewMethod
2693d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    public void setFormat12Hour(CharSequence format) {
2703d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        mFormat12 = format;
2713d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
2723d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        chooseFormat();
2733d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        onTimeChanged();
2743d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    }
2753d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
2763d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    /**
2773d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * Returns the formatting pattern used to display the date and/or time
2783d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * in 24-hour mode. The formatting pattern syntax is described in
2793d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * {@link DateFormat}.
2803d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     *
2813d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * @return A {@link CharSequence} or null.
2823d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     *
2833d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * @see #setFormat24Hour(CharSequence)
2843d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * @see #is24HourModeEnabled()
2853d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     */
2863d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    @ExportedProperty
2873d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    public CharSequence getFormat24Hour() {
2883d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        return mFormat24;
2893d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    }
2903d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
2913d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    /**
2923d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * Specifies the formatting pattern used to display the date and/or time
2933d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * in 24-hour mode. The formatting pattern syntax is described in
2943d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * {@link DateFormat}.
2953d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     *
2963d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * If this pattern is set to null, {@link #getFormat12Hour()} will be used
2973d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * even in 24-hour mode. If both 24-hour and 12-hour formatting patterns
2983d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * are set to null, {@link #DEFAULT_FORMAT_24_HOUR} and
2993d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * {@link #DEFAULT_FORMAT_12_HOUR} will be used instead.
3003d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     *
3013d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * @param format A date/time formatting pattern as described in {@link DateFormat}
3023d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     *
3033d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * @see #getFormat24Hour()
3043d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * @see #is24HourModeEnabled()
3053d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * @see #DEFAULT_FORMAT_24_HOUR
3063d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * @see DateFormat
3073d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     *
3083d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * @attr ref android.R.styleable#TextClock_format24Hour
3093d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     */
310a9cfe677eec0324a94509c6a5d29cec5b8a7a7cfRomain Guy    @RemotableViewMethod
3113d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    public void setFormat24Hour(CharSequence format) {
3123d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        mFormat24 = format;
3133d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
3143d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        chooseFormat();
3153d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        onTimeChanged();
3163d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    }
3173d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
3183d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    /**
3193d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * Indicates whether the system is currently using the 24-hour mode.
3203d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     *
3213d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * When the system is in 24-hour mode, this view will use the pattern
3223d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * returned by {@link #getFormat24Hour()}. In 12-hour mode, the pattern
3233d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * returned by {@link #getFormat12Hour()} is used instead.
3243d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     *
3253d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * If either one of the formats is null, the other format is used. If
3263d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * both formats are null, the default values {@link #DEFAULT_FORMAT_12_HOUR}
3273d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * and {@link #DEFAULT_FORMAT_24_HOUR} are used instead.
3283d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     *
3293d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * @return true if time should be displayed in 24-hour format, false if it
3303d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     *         should be displayed in 12-hour format.
3313d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     *
3323d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * @see #setFormat12Hour(CharSequence)
3333d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * @see #getFormat12Hour()
3343d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * @see #setFormat24Hour(CharSequence)
3353d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * @see #getFormat24Hour()
3363d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     */
3373d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    public boolean is24HourModeEnabled() {
3383d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        return DateFormat.is24HourFormat(getContext());
3393d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    }
3403d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
3413d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    /**
3423d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * Indicates which time zone is currently used by this view.
3433d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     *
3443d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * @return The ID of the current time zone or null if the default time zone,
3453d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     *         as set by the user, must be used
3463d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     *
3473d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * @see TimeZone
3483d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * @see java.util.TimeZone#getAvailableIDs()
3493d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * @see #setTimeZone(String)
3503d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     */
3513d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    public String getTimeZone() {
3523d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        return mTimeZone;
3533d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    }
3543d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
3553d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    /**
3563d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * Sets the specified time zone to use in this clock. When the time zone
3573d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * is set through this method, system time zone changes (when the user
3583d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * sets the time zone in settings for instance) will be ignored.
3593d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     *
3603d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * @param timeZone The desired time zone's ID as specified in {@link TimeZone}
3613d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     *                 or null to user the time zone specified by the user
3623d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     *                 (system time zone)
3633d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     *
3643d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * @see #getTimeZone()
3653d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * @see java.util.TimeZone#getAvailableIDs()
3663d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * @see TimeZone#getTimeZone(String)
3673d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     *
3683d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * @attr ref android.R.styleable#TextClock_timeZone
3693d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     */
370a9cfe677eec0324a94509c6a5d29cec5b8a7a7cfRomain Guy    @RemotableViewMethod
3713d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    public void setTimeZone(String timeZone) {
3723d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        mTimeZone = timeZone;
3733d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
3743d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        createTime(timeZone);
3753d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        onTimeChanged();
3763d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    }
3773d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
3783d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    /**
3793d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * Selects either one of {@link #getFormat12Hour()} or {@link #getFormat24Hour()}
3803d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * depending on whether the user has selected 24-hour format.
3813d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     *
3823d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * Calling this method does not schedule or unschedule the time ticker.
3833d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     */
3843d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    private void chooseFormat() {
3853d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        chooseFormat(true);
3863d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    }
3873d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
3883d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    /**
3893d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * Selects either one of {@link #getFormat12Hour()} or {@link #getFormat24Hour()}
3903d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * depending on whether the user has selected 24-hour format.
3913d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     *
3923d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * @param handleTicker true if calling this method should schedule/unschedule the
3933d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     *                     time ticker, false otherwise
3943d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     */
3953d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    private void chooseFormat(boolean handleTicker) {
3963d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        final boolean format24Requested = is24HourModeEnabled();
3973d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
3983d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        if (format24Requested) {
3993d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy            mFormat = abc(mFormat24, mFormat12, DEFAULT_FORMAT_24_HOUR);
4003d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        } else {
4013d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy            mFormat = abc(mFormat12, mFormat24, DEFAULT_FORMAT_12_HOUR);
4023d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        }
4033d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
4043d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        boolean hadSeconds = mHasSeconds;
4053d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        mHasSeconds = DateFormat.hasSeconds(mFormat);
4063d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
407a76f7db323598f78512bbbdf2fb89248c9e317e5Romain Guy        if (handleTicker && mAttached && hadSeconds != mHasSeconds) {
408a76f7db323598f78512bbbdf2fb89248c9e317e5Romain Guy            if (hadSeconds) getHandler().removeCallbacks(mTicker);
409a76f7db323598f78512bbbdf2fb89248c9e317e5Romain Guy            else mTicker.run();
4103d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        }
4113d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    }
4123d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
4133d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    /**
4143d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * Returns a if not null, else return b if not null, else return c.
4153d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     */
4163d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    private static CharSequence abc(CharSequence a, CharSequence b, CharSequence c) {
4173d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        return a == null ? (b == null ? c : b) : a;
4183d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    }
4193d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
4203d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    @Override
4213d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    protected void onAttachedToWindow() {
4223d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        super.onAttachedToWindow();
4233d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
4243d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        if (!mAttached) {
4253d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy            mAttached = true;
4263d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
4273d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy            registerReceiver();
4283d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy            registerObserver();
4293d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
4303d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy            createTime(mTimeZone);
4313d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
4323d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy            if (mHasSeconds) {
4333d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy                mTicker.run();
4343d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy            } else {
4353d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy                onTimeChanged();
4363d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy            }
4373d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        }
4383d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    }
4393d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
4403d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    @Override
4413d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    protected void onDetachedFromWindow() {
4423d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        super.onDetachedFromWindow();
4433d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
4443d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        if (mAttached) {
4453d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy            unregisterReceiver();
4463d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy            unregisterObserver();
4473d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
4483d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy            getHandler().removeCallbacks(mTicker);
4493d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
4503d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy            mAttached = false;
4513d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        }
4523d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    }
4533d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
4543d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    private void registerReceiver() {
4553d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        final IntentFilter filter = new IntentFilter();
4563d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
4573d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        filter.addAction(Intent.ACTION_TIME_TICK);
4583d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        filter.addAction(Intent.ACTION_TIME_CHANGED);
4593d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
4603d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
4613d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        getContext().registerReceiver(mIntentReceiver, filter, null, getHandler());
4623d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    }
4633d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
4643d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    private void registerObserver() {
4653d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        final ContentResolver resolver = getContext().getContentResolver();
4663d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        resolver.registerContentObserver(Settings.System.CONTENT_URI, true, mFormatChangeObserver);
4673d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    }
4683d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
4693d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    private void unregisterReceiver() {
4703d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        getContext().unregisterReceiver(mIntentReceiver);
4713d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    }
4723d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
4733d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    private void unregisterObserver() {
4743d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        final ContentResolver resolver = getContext().getContentResolver();
4753d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        resolver.unregisterContentObserver(mFormatChangeObserver);
4763d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    }
4773d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
4783d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    private void onTimeChanged() {
4793d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        mTime.setTimeInMillis(System.currentTimeMillis());
4803d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        setText(DateFormat.format(mFormat, mTime));
4813d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    }
4823d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy}
483