blob: ad85e9a450b761e219fa1e22996b5d45672cfee4 [file] [log] [blame]
Jim Miller109f1fd2012-09-19 20:44:16 -07001/*
2 * Copyright (C) 2012 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Jim Miller5ecd8112013-01-09 18:50:26 -080017package com.android.keyguard;
Jim Miller109f1fd2012-09-19 20:44:16 -070018
19import android.content.BroadcastReceiver;
20import android.content.Context;
21import android.content.Intent;
22import android.content.IntentFilter;
23import android.database.ContentObserver;
24import android.graphics.Typeface;
25import android.os.Handler;
Amith Yamasanicd757062012-10-19 18:23:52 -070026import android.os.UserHandle;
Jim Miller109f1fd2012-09-19 20:44:16 -070027import android.provider.Settings;
28import android.text.format.DateFormat;
29import android.util.AttributeSet;
30import android.view.View;
31import android.widget.RelativeLayout;
32import android.widget.TextView;
33
34import java.lang.ref.WeakReference;
35import java.text.DateFormatSymbols;
36import java.util.Calendar;
Jim Miller109f1fd2012-09-19 20:44:16 -070037
38/**
39 * Displays the time
40 */
41public class ClockView extends RelativeLayout {
Christian Robertson24de6052012-09-25 21:40:28 -070042 private static final String ANDROID_CLOCK_FONT_FILE = "/system/fonts/AndroidClock.ttf";
Jim Miller109f1fd2012-09-19 20:44:16 -070043 private final static String M12 = "h:mm";
Jim Millerc801b212013-04-02 16:03:02 -070044 private final static String M24 = "HH:mm";
Jim Miller109f1fd2012-09-19 20:44:16 -070045
46 private Calendar mCalendar;
47 private String mFormat;
48 private TextView mTimeView;
49 private AmPm mAmPm;
50 private ContentObserver mFormatChangeObserver;
51 private int mAttached = 0; // for debugging - tells us whether attach/detach is unbalanced
52
53 /* called by system on minute ticks */
54 private final Handler mHandler = new Handler();
55 private BroadcastReceiver mIntentReceiver;
56
57 private static class TimeChangedReceiver extends BroadcastReceiver {
58 private WeakReference<ClockView> mClock;
59 private Context mContext;
60
61 public TimeChangedReceiver(ClockView clock) {
62 mClock = new WeakReference<ClockView>(clock);
63 mContext = clock.getContext();
64 }
65
66 @Override
67 public void onReceive(Context context, Intent intent) {
68 // Post a runnable to avoid blocking the broadcast.
69 final boolean timezoneChanged =
70 intent.getAction().equals(Intent.ACTION_TIMEZONE_CHANGED);
71 final ClockView clock = mClock.get();
72 if (clock != null) {
73 clock.mHandler.post(new Runnable() {
74 public void run() {
75 if (timezoneChanged) {
76 clock.mCalendar = Calendar.getInstance();
77 }
78 clock.updateTime();
79 }
80 });
81 } else {
82 try {
83 mContext.unregisterReceiver(this);
84 } catch (RuntimeException e) {
85 // Shouldn't happen
86 }
87 }
88 }
89 };
90
91 static class AmPm {
92 private TextView mAmPmTextView;
93 private String mAmString, mPmString;
94
95 AmPm(View parent, Typeface tf) {
96 // No longer used, uncomment if we decide to use AM/PM indicator again
97 // mAmPmTextView = (TextView) parent.findViewById(R.id.am_pm);
98 if (mAmPmTextView != null && tf != null) {
99 mAmPmTextView.setTypeface(tf);
100 }
101
102 String[] ampm = new DateFormatSymbols().getAmPmStrings();
103 mAmString = ampm[0];
104 mPmString = ampm[1];
105 }
106
107 void setShowAmPm(boolean show) {
108 if (mAmPmTextView != null) {
109 mAmPmTextView.setVisibility(show ? View.VISIBLE : View.GONE);
110 }
111 }
112
113 void setIsMorning(boolean isMorning) {
114 if (mAmPmTextView != null) {
115 mAmPmTextView.setText(isMorning ? mAmString : mPmString);
116 }
117 }
118 }
119
120 private static class FormatChangeObserver extends ContentObserver {
121 private WeakReference<ClockView> mClock;
122 private Context mContext;
123 public FormatChangeObserver(ClockView clock) {
124 super(new Handler());
125 mClock = new WeakReference<ClockView>(clock);
126 mContext = clock.getContext();
127 }
128 @Override
129 public void onChange(boolean selfChange) {
130 ClockView digitalClock = mClock.get();
131 if (digitalClock != null) {
132 digitalClock.setDateFormat();
133 digitalClock.updateTime();
134 } else {
135 try {
136 mContext.getContentResolver().unregisterContentObserver(this);
137 } catch (RuntimeException e) {
138 // Shouldn't happen
139 }
140 }
141 }
142 }
143
144 public ClockView(Context context) {
145 this(context, null);
146 }
147
148 public ClockView(Context context, AttributeSet attrs) {
149 super(context, attrs);
150 }
151
152 @Override
153 protected void onFinishInflate() {
154 super.onFinishInflate();
155 mTimeView = (TextView) findViewById(R.id.clock_text);
Christian Robertson24de6052012-09-25 21:40:28 -0700156 mTimeView.setTypeface(Typeface.createFromFile(ANDROID_CLOCK_FONT_FILE));
Jim Miller109f1fd2012-09-19 20:44:16 -0700157 mAmPm = new AmPm(this, null);
158 mCalendar = Calendar.getInstance();
159 setDateFormat();
160 }
161
162 @Override
163 protected void onAttachedToWindow() {
164 super.onAttachedToWindow();
165
166 mAttached++;
167
168 /* monitor time ticks, time changed, timezone */
169 if (mIntentReceiver == null) {
170 mIntentReceiver = new TimeChangedReceiver(this);
171 IntentFilter filter = new IntentFilter();
172 filter.addAction(Intent.ACTION_TIME_TICK);
173 filter.addAction(Intent.ACTION_TIME_CHANGED);
174 filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
Amith Yamasanicd757062012-10-19 18:23:52 -0700175 mContext.registerReceiverAsUser(mIntentReceiver, UserHandle.OWNER, filter, null, null );
Jim Miller109f1fd2012-09-19 20:44:16 -0700176 }
177
178 /* monitor 12/24-hour display preference */
179 if (mFormatChangeObserver == null) {
180 mFormatChangeObserver = new FormatChangeObserver(this);
181 mContext.getContentResolver().registerContentObserver(
182 Settings.System.CONTENT_URI, true, mFormatChangeObserver);
183 }
184
185 updateTime();
186 }
187
188 @Override
189 protected void onDetachedFromWindow() {
190 super.onDetachedFromWindow();
191
192 mAttached--;
193
194 if (mIntentReceiver != null) {
195 mContext.unregisterReceiver(mIntentReceiver);
196 }
197 if (mFormatChangeObserver != null) {
198 mContext.getContentResolver().unregisterContentObserver(
199 mFormatChangeObserver);
200 }
201
202 mFormatChangeObserver = null;
203 mIntentReceiver = null;
204 }
205
206 void updateTime(Calendar c) {
207 mCalendar = c;
208 updateTime();
209 }
210
211 public void updateTime() {
212 mCalendar.setTimeInMillis(System.currentTimeMillis());
213
214 CharSequence newTime = DateFormat.format(mFormat, mCalendar);
215 mTimeView.setText(newTime);
216 mAmPm.setIsMorning(mCalendar.get(Calendar.AM_PM) == 0);
217 }
218
219 private void setDateFormat() {
220 mFormat = android.text.format.DateFormat.is24HourFormat(getContext()) ? M24 : M12;
221 mAmPm.setShowAmPm(mFormat.equals(M12));
222 }
223}