TextClock.java revision 3d1728c03a0cd1aaed6bc81c97de27d62c771a6e
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;
323d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
333d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guyimport com.android.internal.R;
343d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
353d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guyimport java.util.Calendar;
363d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guyimport java.util.TimeZone;
373d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
383d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guyimport static android.view.ViewDebug.ExportedProperty;
393d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guyimport static android.widget.RemoteViews.*;
403d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
413d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy/**
423d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy * <p><code>TextClock</code> can display the current date and/or time as
433d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy * a formatted string.</p>
443d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy *
453d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy * <p>This view honors the 24-hour format system setting. As such, it is
463d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy * possible and recommended to provide two different formatting patterns:
473d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy * one to display the date/time in 24-hour mode and one to display the
483d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy * date/time in 12-hour mode.</p>
493d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy *
503d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy * <p>It is possible to determine whether the system is currently in
513d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy * 24-hour mode by calling {@link #is24HourModeEnabled()}.</p>
523d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy *
533d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy * <p>The rules used by this widget to decide how to format the date and
543d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy * time are the following:</p>
553d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy * <ul>
563d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy *     <li>In 24-hour mode:
573d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy *         <ul>
583d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy *             <li>Use the value returned by {@link #getFormat24Hour()} when non-null</li>
593d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy *             <li>Otherwise, use the value returned by {@link #getFormat12Hour()} when non-null</li>
603d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy *             <li>Otherwise, use {@link #DEFAULT_FORMAT_24_HOUR}</li>
613d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy *         </ul>
623d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy *     </li>
633d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy *     <li>In 12-hour mode:
643d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy *         <ul>
653d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy *             <li>Use the value returned by {@link #getFormat12Hour()} when non-null</li>
663d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy *             <li>Otherwise, use the value returned by {@link #getFormat24Hour()} when non-null</li>
673d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy *             <li>Otherwise, use {@link #DEFAULT_FORMAT_12_HOUR}</li>
683d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy *         </ul>
693d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy *     </li>
703d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy * </ul>
713d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy *
723d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy * <p>The {@link CharSequence} instances used as formatting patterns when calling either
733d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy * {@link #setFormat24Hour(CharSequence)} or {@link #setFormat12Hour(CharSequence)} can
743d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy * contain styling information. To do so, use a {@link android.text.Spanned} object.</p>
753d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy *
763d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy * @attr ref android.R.styleable#TextClock_format12Hour
773d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy * @attr ref android.R.styleable#TextClock_format24Hour
783d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy * @attr ref android.R.styleable#TextClock_timeZone
793d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy */
803d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy@RemoteView
813d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guypublic class TextClock extends TextView {
823d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    /**
833d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * The default formatting pattern in 12-hour mode. This pattenr is used
843d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * if {@link #setFormat12Hour(CharSequence)} is called with a null pattern
853d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * or if no pattern was specified when creating an instance of this class.
863d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     *
873d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * This default pattern shows only the time, hours and minutes, and an am/pm
883d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * indicator.
893d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     *
903d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * @see #setFormat12Hour(CharSequence)
913d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * @see #getFormat12Hour()
923d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     */
933d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    public static final CharSequence DEFAULT_FORMAT_12_HOUR = "h:mm aa";
943d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
953d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    /**
963d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * The default formatting pattern in 24-hour mode. This pattenr is used
973d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * if {@link #setFormat24Hour(CharSequence)} is called with a null pattern
983d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * or if no pattern was specified when creating an instance of this class.
993d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     *
1003d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * This default pattern shows only the time, hours and minutes.
1013d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     *
1023d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * @see #setFormat24Hour(CharSequence)
1033d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * @see #getFormat24Hour()
1043d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     */
1053d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    public static final CharSequence DEFAULT_FORMAT_24_HOUR = "k:mm";
1063d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
1073d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    private CharSequence mFormat12 = DEFAULT_FORMAT_12_HOUR;
1083d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    private CharSequence mFormat24 = DEFAULT_FORMAT_24_HOUR;
1093d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
1103d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    @ExportedProperty
1113d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    private CharSequence mFormat;
1123d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    @ExportedProperty
1133d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    private boolean mHasSeconds;
1143d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
1153d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    private boolean mAttached;
1163d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
1173d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    private Calendar mTime;
1183d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    private String mTimeZone;
1193d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
1203d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    private final ContentObserver mFormatChangeObserver = new ContentObserver(new Handler()) {
1213d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        @Override
1223d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        public void onChange(boolean selfChange) {
1233d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy            chooseFormat();
1243d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy            onTimeChanged();
1253d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        }
1263d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
1273d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        @Override
1283d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        public void onChange(boolean selfChange, Uri uri) {
1293d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy            chooseFormat();
1303d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy            onTimeChanged();
1313d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        }
1323d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    };
1333d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
1343d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
1353d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        @Override
1363d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        public void onReceive(Context context, Intent intent) {
1373d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy            if (mTimeZone == null) {
1383d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy                if (intent.getAction().equals(Intent.ACTION_TIMEZONE_CHANGED)) {
1393d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy                    final String timeZone = intent.getStringExtra("time-zone");
1403d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy                    createTime(timeZone);
1413d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy                }
1423d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy                onTimeChanged();
1433d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy            }
1443d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        }
1453d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    };
1463d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
1473d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    private final Runnable mTicker = new Runnable() {
1483d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        public void run() {
1493d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy            onTimeChanged();
1503d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
1513d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy            long now = SystemClock.uptimeMillis();
1523d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy            long next = now + (1000 - now % 1000);
1533d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
1543d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy            getHandler().postAtTime(mTicker, next);
1553d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        }
1563d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    };
1573d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
1583d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    /**
1593d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * Creates a new clock using the default patterns
1603d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * {@link #DEFAULT_FORMAT_24_HOUR} and {@link #DEFAULT_FORMAT_12_HOUR}
1613d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * respectively for the 24-hour and 12-hour modes.
1623d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     *
1633d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * @param context The Context the view is running in, through which it can
1643d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     *        access the current theme, resources, etc.
1653d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     */
1663d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    @SuppressWarnings("UnusedDeclaration")
1673d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    public TextClock(Context context) {
1683d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        super(context);
1693d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        init();
1703d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    }
1713d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
1723d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    /**
1733d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * Creates a new clock inflated from XML. This object's properties are
1743d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * intialized from the attributes specified in XML.
1753d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     *
1763d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * This constructor uses a default style of 0, so the only attribute values
1773d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * applied are those in the Context's Theme and the given AttributeSet.
1783d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     *
1793d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * @param context The Context the view is running in, through which it can
1803d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     *        access the current theme, resources, etc.
1813d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * @param attrs The attributes of the XML tag that is inflating the view
1823d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     */
1833d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    @SuppressWarnings("UnusedDeclaration")
1843d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    public TextClock(Context context, AttributeSet attrs) {
1853d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        this(context, attrs, 0);
1863d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    }
1873d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
1883d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    /**
1893d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * Creates a new clock inflated from XML. This object's properties are
1903d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * intialized from the attributes specified in XML.
1913d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     *
1923d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * @param context The Context the view is running in, through which it can
1933d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     *        access the current theme, resources, etc.
1943d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * @param attrs The attributes of the XML tag that is inflating the view
1953d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * @param defStyle The default style to apply to this view. If 0, no style
1963d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     *        will be applied (beyond what is included in the theme). This may
1973d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     *        either be an attribute resource, whose value will be retrieved
1983d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     *        from the current theme, or an explicit style resource
1993d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     */
2003d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    public TextClock(Context context, AttributeSet attrs, int defStyle) {
2013d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        super(context, attrs, defStyle);
2023d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
2033d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.TextClock, defStyle, 0);
2043d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        try {
2053d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy            CharSequence format;
2063d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
2073d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy            format = a.getText(R.styleable.TextClock_format12Hour);
2083d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy            mFormat12 = format == null ? DEFAULT_FORMAT_12_HOUR : format;
2093d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
2103d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy            format = a.getText(R.styleable.TextClock_format24Hour);
2113d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy            mFormat24 = format == null ? DEFAULT_FORMAT_24_HOUR : format;
2123d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
2133d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy            mTimeZone = a.getString(R.styleable.TextClock_timeZone);
2143d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        } finally {
2153d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy            a.recycle();
2163d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        }
2173d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
2183d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        init();
2193d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    }
2203d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
2213d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    private void init() {
2223d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        createTime(mTimeZone);
2233d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        // Wait until onAttachedToWindow() to handle the ticker
2243d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        chooseFormat(false);
2253d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    }
2263d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
2273d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    private void createTime(String timeZone) {
2283d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        if (timeZone != null) {
2293d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy            mTime = Calendar.getInstance(TimeZone.getTimeZone(timeZone));
2303d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        } else {
2313d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy            mTime = Calendar.getInstance();
2323d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        }
2333d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    }
2343d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
2353d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    /**
2363d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * Returns the formatting pattern used to display the date and/or time
2373d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * in 12-hour mode. The formatting pattern syntax is described in
2383d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * {@link DateFormat}.
2393d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     *
2403d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * @return A {@link CharSequence} or null.
2413d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     *
2423d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * @see #setFormat12Hour(CharSequence)
2433d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * @see #is24HourModeEnabled()
2443d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     */
2453d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    @ExportedProperty
2463d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    public CharSequence getFormat12Hour() {
2473d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        return mFormat12;
2483d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    }
2493d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
2503d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    /**
2513d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * Specifies the formatting pattern used to display the date and/or time
2523d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * in 12-hour mode. The formatting pattern syntax is described in
2533d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * {@link DateFormat}.
2543d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     *
2553d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * If this pattern is set to null, {@link #getFormat24Hour()} will be used
2563d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * even in 12-hour mode. If both 24-hour and 12-hour formatting patterns
2573d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * are set to null, {@link #DEFAULT_FORMAT_24_HOUR} and
2583d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * {@link #DEFAULT_FORMAT_12_HOUR} will be used instead.
2593d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     *
2603d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * @param format A date/time formatting pattern as described in {@link DateFormat}
2613d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     *
2623d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * @see #getFormat12Hour()
2633d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * @see #is24HourModeEnabled()
2643d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * @see #DEFAULT_FORMAT_12_HOUR
2653d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * @see DateFormat
2663d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     *
2673d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * @attr ref android.R.styleable#TextClock_format12Hour
2683d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     */
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     */
3103d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    public void setFormat24Hour(CharSequence format) {
3113d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        mFormat24 = format;
3123d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
3133d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        chooseFormat();
3143d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        onTimeChanged();
3153d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    }
3163d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
3173d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    /**
3183d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * Indicates whether the system is currently using the 24-hour mode.
3193d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     *
3203d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * When the system is in 24-hour mode, this view will use the pattern
3213d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * returned by {@link #getFormat24Hour()}. In 12-hour mode, the pattern
3223d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * returned by {@link #getFormat12Hour()} is used instead.
3233d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     *
3243d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * If either one of the formats is null, the other format is used. If
3253d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * both formats are null, the default values {@link #DEFAULT_FORMAT_12_HOUR}
3263d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * and {@link #DEFAULT_FORMAT_24_HOUR} are used instead.
3273d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     *
3283d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * @return true if time should be displayed in 24-hour format, false if it
3293d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     *         should be displayed in 12-hour format.
3303d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     *
3313d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * @see #setFormat12Hour(CharSequence)
3323d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * @see #getFormat12Hour()
3333d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * @see #setFormat24Hour(CharSequence)
3343d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * @see #getFormat24Hour()
3353d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     */
3363d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    public boolean is24HourModeEnabled() {
3373d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        return DateFormat.is24HourFormat(getContext());
3383d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    }
3393d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
3403d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    /**
3413d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * Indicates which time zone is currently used by this view.
3423d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     *
3433d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * @return The ID of the current time zone or null if the default time zone,
3443d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     *         as set by the user, must be used
3453d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     *
3463d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * @see TimeZone
3473d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * @see java.util.TimeZone#getAvailableIDs()
3483d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * @see #setTimeZone(String)
3493d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     */
3503d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    public String getTimeZone() {
3513d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        return mTimeZone;
3523d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    }
3533d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
3543d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    /**
3553d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * Sets the specified time zone to use in this clock. When the time zone
3563d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * is set through this method, system time zone changes (when the user
3573d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * sets the time zone in settings for instance) will be ignored.
3583d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     *
3593d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * @param timeZone The desired time zone's ID as specified in {@link TimeZone}
3603d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     *                 or null to user the time zone specified by the user
3613d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     *                 (system time zone)
3623d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     *
3633d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * @see #getTimeZone()
3643d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * @see java.util.TimeZone#getAvailableIDs()
3653d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * @see TimeZone#getTimeZone(String)
3663d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     *
3673d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * @attr ref android.R.styleable#TextClock_timeZone
3683d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     */
3693d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    public void setTimeZone(String timeZone) {
3703d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        mTimeZone = timeZone;
3713d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
3723d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        createTime(timeZone);
3733d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        onTimeChanged();
3743d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    }
3753d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
3763d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    /**
3773d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * Selects either one of {@link #getFormat12Hour()} or {@link #getFormat24Hour()}
3783d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * depending on whether the user has selected 24-hour format.
3793d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     *
3803d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * Calling this method does not schedule or unschedule the time ticker.
3813d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     */
3823d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    private void chooseFormat() {
3833d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        chooseFormat(true);
3843d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    }
3853d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
3863d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    /**
3873d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * Selects either one of {@link #getFormat12Hour()} or {@link #getFormat24Hour()}
3883d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * depending on whether the user has selected 24-hour format.
3893d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     *
3903d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * @param handleTicker true if calling this method should schedule/unschedule the
3913d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     *                     time ticker, false otherwise
3923d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     */
3933d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    private void chooseFormat(boolean handleTicker) {
3943d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        final boolean format24Requested = is24HourModeEnabled();
3953d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
3963d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        if (format24Requested) {
3973d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy            mFormat = abc(mFormat24, mFormat12, DEFAULT_FORMAT_24_HOUR);
3983d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        } else {
3993d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy            mFormat = abc(mFormat12, mFormat24, DEFAULT_FORMAT_12_HOUR);
4003d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        }
4013d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
4023d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        boolean hadSeconds = mHasSeconds;
4033d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        mHasSeconds = DateFormat.hasSeconds(mFormat);
4043d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
4053d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        if (handleTicker) {
4063d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy            if (hadSeconds != mHasSeconds) {
4073d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy                if (hadSeconds) getHandler().removeCallbacks(mTicker);
4083d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy                else mTicker.run();
4093d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy            }
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