OSDN Git Service

original
[gb-231r1-is01/Gingerbread_2.3.3_r1_IS01.git] / frameworks / base / core / java / android / widget / DateTimeView.java
1 /*
2  * Copyright (C) 2010 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
17 package android.widget;
18
19 import android.content.Context;
20 import android.content.Intent;
21 import android.content.IntentFilter;
22 import android.content.BroadcastReceiver;
23 import android.database.ContentObserver;
24 import android.net.Uri;
25 import android.os.Handler;
26 import android.text.format.Time;
27 import android.util.AttributeSet;
28 import android.util.Log;
29 import android.provider.Settings;
30 import android.provider.Settings.SettingNotFoundException;
31 import android.widget.TextView;
32 import android.widget.RemoteViews.RemoteView;
33
34 import com.android.internal.R;
35
36 import java.text.DateFormat;
37 import java.text.SimpleDateFormat;
38 import java.util.Date;
39
40 //
41 // TODO
42 // - listen for the next threshold time to update the view.
43 // - listen for date format pref changed
44 // - put the AM/PM in a smaller font
45 //
46
47 /**
48  * Displays a given time in a convenient human-readable foramt.
49  *
50  * @hide
51  */
52 @RemoteView
53 public class DateTimeView extends TextView {
54     private static final String TAG = "DateTimeView";
55
56     private static final long TWELVE_HOURS_IN_MINUTES = 12 * 60;
57     private static final long TWENTY_FOUR_HOURS_IN_MILLIS = 24 * 60 * 60 * 1000;
58
59     private static final int SHOW_TIME = 0;
60     private static final int SHOW_MONTH_DAY_YEAR = 1;
61
62     Date mTime;
63     long mTimeMillis;
64
65     int mLastDisplay = -1;
66     DateFormat mLastFormat;
67
68     private boolean mAttachedToWindow;
69     private long mUpdateTimeMillis;
70
71     public DateTimeView(Context context) {
72         super(context);
73     }
74
75     public DateTimeView(Context context, AttributeSet attrs) {
76         super(context, attrs);
77     }
78
79     @Override
80     protected void onAttachedToWindow() {
81         super.onDetachedFromWindow();
82         registerReceivers();
83         mAttachedToWindow = true;
84     }
85         
86     @Override
87     protected void onDetachedFromWindow() {
88         super.onDetachedFromWindow();
89         unregisterReceivers();
90         mAttachedToWindow = false;
91     }
92
93     @android.view.RemotableViewMethod
94     public void setTime(long time) {
95         Time t = new Time();
96         t.set(time);
97         t.second = 0;
98         mTimeMillis = t.toMillis(false);
99         mTime = new Date(t.year-1900, t.month, t.monthDay, t.hour, t.minute, 0);
100         update();
101     }
102
103     void update() {
104         if (mTime == null) {
105             return;
106         }
107
108         long start = System.nanoTime();
109
110         int display;
111         Date time = mTime;
112
113         Time t = new Time();
114         t.set(mTimeMillis);
115         t.second = 0;
116
117         t.hour -= 12;
118         long twelveHoursBefore = t.toMillis(false);
119         t.hour += 12;
120         long twelveHoursAfter = t.toMillis(false);
121         t.hour = 0;
122         t.minute = 0;
123         long midnightBefore = t.toMillis(false);
124         t.monthDay++;
125         long midnightAfter = t.toMillis(false);
126
127         long nowMillis = System.currentTimeMillis();
128         t.set(nowMillis);
129         t.second = 0;
130         nowMillis = t.normalize(false);
131
132         // Choose the display mode
133         choose_display: {
134             if ((nowMillis >= midnightBefore && nowMillis < midnightAfter)
135                     || (nowMillis >= twelveHoursBefore && nowMillis < twelveHoursAfter)) {
136                 display = SHOW_TIME;
137                 break choose_display;
138             }
139             // Else, show month day and year.
140             display = SHOW_MONTH_DAY_YEAR;
141             break choose_display;
142         }
143
144         // Choose the format
145         DateFormat format;
146         if (display == mLastDisplay && mLastFormat != null) {
147             // use cached format
148             format = mLastFormat;
149         } else {
150             switch (display) {
151                 case SHOW_TIME:
152                     format = getTimeFormat();
153                     break;
154                 case SHOW_MONTH_DAY_YEAR:
155                     format = getDateFormat();
156                     break;
157                 default:
158                     throw new RuntimeException("unknown display value: " + display);
159             }
160             mLastFormat = format;
161         }
162
163         // Set the text
164         String text = format.format(mTime);
165         setText(text);
166
167         // Schedule the next update
168         if (display == SHOW_TIME) {
169             // Currently showing the time, update at the later of twelve hours after or midnight.
170             mUpdateTimeMillis = twelveHoursAfter > midnightAfter ? twelveHoursAfter : midnightAfter;
171         } else {
172             // Currently showing the date
173             if (mTimeMillis < nowMillis) {
174                 // If the time is in the past, don't schedule an update
175                 mUpdateTimeMillis = 0;
176             } else {
177                 // If hte time is in the future, schedule one at the earlier of twelve hours
178                 // before or midnight before.
179                 mUpdateTimeMillis = twelveHoursBefore < midnightBefore
180                         ? twelveHoursBefore : midnightBefore;
181             }
182         }
183         if (false) {
184             Log.d(TAG, "update needed for '" + time + "' at '" + new Date(mUpdateTimeMillis)
185                     + "' - text=" + text);
186         }
187
188         long finish = System.nanoTime();
189     }
190
191     private DateFormat getTimeFormat() {
192         int res;
193         Context context = getContext();
194         if (android.text.format.DateFormat.is24HourFormat(context)) {
195             res = R.string.twenty_four_hour_time_format;
196         } else {
197             res = R.string.twelve_hour_time_format;
198         }
199         String format = context.getString(res);
200         return new SimpleDateFormat(format);
201     }
202
203     private DateFormat getDateFormat() {
204         String format = Settings.System.getString(getContext().getContentResolver(),
205                 Settings.System.DATE_FORMAT);
206         if (format == null || "".equals(format)) {
207             return DateFormat.getDateInstance(DateFormat.SHORT);
208         } else {
209             try {
210                 return new SimpleDateFormat(format);
211             } catch (IllegalArgumentException e) {
212                 // If we tried to use a bad format string, fall back to a default.
213                 return DateFormat.getDateInstance(DateFormat.SHORT);
214             }
215         }
216     }
217
218     private void registerReceivers() {
219         Context context = getContext();
220
221         IntentFilter filter = new IntentFilter();
222         filter.addAction(Intent.ACTION_TIME_TICK);
223         filter.addAction(Intent.ACTION_TIME_CHANGED);
224         filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
225         filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
226         context.registerReceiver(mBroadcastReceiver, filter);
227
228         Uri uri = Settings.System.getUriFor(Settings.System.DATE_FORMAT);
229         context.getContentResolver().registerContentObserver(uri, true, mContentObserver);
230     }
231
232     private void unregisterReceivers() {
233         Context context = getContext();
234         context.unregisterReceiver(mBroadcastReceiver);
235         context.getContentResolver().unregisterContentObserver(mContentObserver);
236     }
237
238     private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
239         @Override
240         public void onReceive(Context context, Intent intent) {
241             String action = intent.getAction();
242             if (Intent.ACTION_TIME_TICK.equals(action)) {
243                 if (System.currentTimeMillis() < mUpdateTimeMillis) {
244                     // The update() function takes a few milliseconds to run because of
245                     // all of the time conversions it needs to do, so we can't do that
246                     // every minute.
247                     return;
248                 }
249             }
250             // ACTION_TIME_CHANGED can also signal a change of 12/24 hr. format.
251             mLastFormat = null;
252             update();
253         }
254     };
255
256     private ContentObserver mContentObserver = new ContentObserver(new Handler()) {
257         @Override
258         public void onChange(boolean selfChange) {
259             mLastFormat = null;
260             update();
261         }
262     };
263 }