| Joe Onorato | 263700d | 2010-05-14 11:54:53 -0700 | [diff] [blame] | 1 | /* | 
|  | 2 | * Copyright (C) 2006 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 |  | 
| Joe Onorato | fd52b18 | 2010-11-10 18:00:52 -0800 | [diff] [blame] | 17 | package com.android.systemui.statusbar.policy; | 
| Joe Onorato | 263700d | 2010-05-14 11:54:53 -0700 | [diff] [blame] | 18 |  | 
| Daniel Sandler | 87937db | 2010-05-27 13:44:11 -0400 | [diff] [blame] | 19 | import android.content.BroadcastReceiver; | 
| Joe Onorato | 263700d | 2010-05-14 11:54:53 -0700 | [diff] [blame] | 20 | import android.content.Context; | 
|  | 21 | import android.content.Intent; | 
|  | 22 | import android.content.IntentFilter; | 
| Joe Onorato | 263700d | 2010-05-14 11:54:53 -0700 | [diff] [blame] | 23 | import android.content.res.Resources; | 
|  | 24 | import android.content.res.TypedArray; | 
|  | 25 | import android.graphics.Canvas; | 
| Daniel Sandler | 87937db | 2010-05-27 13:44:11 -0400 | [diff] [blame] | 26 | import android.graphics.Typeface; | 
| Joe Onorato | 263700d | 2010-05-14 11:54:53 -0700 | [diff] [blame] | 27 | import android.graphics.drawable.Drawable; | 
| Joe Onorato | 263700d | 2010-05-14 11:54:53 -0700 | [diff] [blame] | 28 | import android.text.Spannable; | 
|  | 29 | import android.text.SpannableStringBuilder; | 
| Daniel Sandler | 87937db | 2010-05-27 13:44:11 -0400 | [diff] [blame] | 30 | import android.text.format.DateFormat; | 
|  | 31 | import android.text.style.CharacterStyle; | 
|  | 32 | import android.text.style.ForegroundColorSpan; | 
|  | 33 | import android.text.style.RelativeSizeSpan; | 
|  | 34 | import android.text.style.RelativeSizeSpan; | 
|  | 35 | import android.text.style.StyleSpan; | 
| Joe Onorato | 263700d | 2010-05-14 11:54:53 -0700 | [diff] [blame] | 36 | import android.util.AttributeSet; | 
| Daniel Sandler | 08d05e3 | 2012-08-08 16:39:54 -0400 | [diff] [blame] | 37 | import android.util.Slog; | 
| Joe Onorato | 263700d | 2010-05-14 11:54:53 -0700 | [diff] [blame] | 38 | import android.view.View; | 
|  | 39 | import android.widget.TextView; | 
|  | 40 |  | 
|  | 41 | import java.text.SimpleDateFormat; | 
|  | 42 | import java.util.Calendar; | 
|  | 43 | import java.util.TimeZone; | 
|  | 44 |  | 
|  | 45 | import com.android.internal.R; | 
|  | 46 |  | 
|  | 47 | /** | 
|  | 48 | * This widget display an analogic clock with two hands for hours and | 
|  | 49 | * minutes. | 
|  | 50 | */ | 
|  | 51 | public class Clock extends TextView { | 
| Joe Onorato | 263700d | 2010-05-14 11:54:53 -0700 | [diff] [blame] | 52 | private boolean mAttached; | 
|  | 53 | private Calendar mCalendar; | 
|  | 54 | private String mClockFormatString; | 
|  | 55 | private SimpleDateFormat mClockFormat; | 
|  | 56 |  | 
| Daniel Sandler | 87937db | 2010-05-27 13:44:11 -0400 | [diff] [blame] | 57 | private static final int AM_PM_STYLE_NORMAL  = 0; | 
|  | 58 | private static final int AM_PM_STYLE_SMALL   = 1; | 
|  | 59 | private static final int AM_PM_STYLE_GONE    = 2; | 
|  | 60 |  | 
|  | 61 | private static final int AM_PM_STYLE = AM_PM_STYLE_GONE; | 
|  | 62 |  | 
| Joe Onorato | 263700d | 2010-05-14 11:54:53 -0700 | [diff] [blame] | 63 | public Clock(Context context) { | 
|  | 64 | this(context, null); | 
|  | 65 | } | 
|  | 66 |  | 
|  | 67 | public Clock(Context context, AttributeSet attrs) { | 
|  | 68 | this(context, attrs, 0); | 
|  | 69 | } | 
|  | 70 |  | 
|  | 71 | public Clock(Context context, AttributeSet attrs, int defStyle) { | 
|  | 72 | super(context, attrs, defStyle); | 
|  | 73 | } | 
|  | 74 |  | 
|  | 75 | @Override | 
|  | 76 | protected void onAttachedToWindow() { | 
|  | 77 | super.onAttachedToWindow(); | 
|  | 78 |  | 
|  | 79 | if (!mAttached) { | 
|  | 80 | mAttached = true; | 
|  | 81 | IntentFilter filter = new IntentFilter(); | 
|  | 82 |  | 
|  | 83 | filter.addAction(Intent.ACTION_TIME_TICK); | 
|  | 84 | filter.addAction(Intent.ACTION_TIME_CHANGED); | 
|  | 85 | filter.addAction(Intent.ACTION_TIMEZONE_CHANGED); | 
|  | 86 | filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED); | 
|  | 87 |  | 
| Joe Onorato | 1a86dd1 | 2010-06-01 08:17:58 -0700 | [diff] [blame] | 88 | getContext().registerReceiver(mIntentReceiver, filter, null, getHandler()); | 
| Joe Onorato | 263700d | 2010-05-14 11:54:53 -0700 | [diff] [blame] | 89 | } | 
|  | 90 |  | 
|  | 91 | // NOTE: It's safe to do these after registering the receiver since the receiver always runs | 
|  | 92 | // in the main thread, therefore the receiver can't run before this method returns. | 
|  | 93 |  | 
|  | 94 | // The time zone may have changed while the receiver wasn't registered, so update the Time | 
|  | 95 | mCalendar = Calendar.getInstance(TimeZone.getDefault()); | 
|  | 96 |  | 
|  | 97 | // Make sure we update to the current time | 
|  | 98 | updateClock(); | 
|  | 99 | } | 
|  | 100 |  | 
|  | 101 | @Override | 
|  | 102 | protected void onDetachedFromWindow() { | 
|  | 103 | super.onDetachedFromWindow(); | 
|  | 104 | if (mAttached) { | 
|  | 105 | getContext().unregisterReceiver(mIntentReceiver); | 
|  | 106 | mAttached = false; | 
|  | 107 | } | 
|  | 108 | } | 
|  | 109 |  | 
|  | 110 | private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { | 
|  | 111 | @Override | 
|  | 112 | public void onReceive(Context context, Intent intent) { | 
|  | 113 | String action = intent.getAction(); | 
|  | 114 | if (action.equals(Intent.ACTION_TIMEZONE_CHANGED)) { | 
|  | 115 | String tz = intent.getStringExtra("time-zone"); | 
|  | 116 | mCalendar = Calendar.getInstance(TimeZone.getTimeZone(tz)); | 
|  | 117 | if (mClockFormat != null) { | 
|  | 118 | mClockFormat.setTimeZone(mCalendar.getTimeZone()); | 
|  | 119 | } | 
|  | 120 | } | 
|  | 121 | updateClock(); | 
|  | 122 | } | 
|  | 123 | }; | 
|  | 124 |  | 
|  | 125 | final void updateClock() { | 
|  | 126 | mCalendar.setTimeInMillis(System.currentTimeMillis()); | 
|  | 127 | setText(getSmallTime()); | 
|  | 128 | } | 
|  | 129 |  | 
|  | 130 | private final CharSequence getSmallTime() { | 
|  | 131 | Context context = getContext(); | 
|  | 132 | boolean b24 = DateFormat.is24HourFormat(context); | 
|  | 133 | int res; | 
|  | 134 |  | 
|  | 135 | if (b24) { | 
|  | 136 | res = R.string.twenty_four_hour_time_format; | 
|  | 137 | } else { | 
|  | 138 | res = R.string.twelve_hour_time_format; | 
|  | 139 | } | 
|  | 140 |  | 
|  | 141 | final char MAGIC1 = '\uEF00'; | 
|  | 142 | final char MAGIC2 = '\uEF01'; | 
|  | 143 |  | 
|  | 144 | SimpleDateFormat sdf; | 
|  | 145 | String format = context.getString(res); | 
|  | 146 | if (!format.equals(mClockFormatString)) { | 
|  | 147 | /* | 
|  | 148 | * Search for an unquoted "a" in the format string, so we can | 
|  | 149 | * add dummy characters around it to let us find it again after | 
|  | 150 | * formatting and change its size. | 
|  | 151 | */ | 
| Daniel Sandler | 87937db | 2010-05-27 13:44:11 -0400 | [diff] [blame] | 152 | if (AM_PM_STYLE != AM_PM_STYLE_NORMAL) { | 
|  | 153 | int a = -1; | 
|  | 154 | boolean quoted = false; | 
|  | 155 | for (int i = 0; i < format.length(); i++) { | 
|  | 156 | char c = format.charAt(i); | 
| Joe Onorato | 263700d | 2010-05-14 11:54:53 -0700 | [diff] [blame] | 157 |  | 
| Daniel Sandler | 87937db | 2010-05-27 13:44:11 -0400 | [diff] [blame] | 158 | if (c == '\'') { | 
|  | 159 | quoted = !quoted; | 
|  | 160 | } | 
|  | 161 | if (!quoted && c == 'a') { | 
|  | 162 | a = i; | 
|  | 163 | break; | 
|  | 164 | } | 
| Joe Onorato | 263700d | 2010-05-14 11:54:53 -0700 | [diff] [blame] | 165 | } | 
|  | 166 |  | 
| Daniel Sandler | 87937db | 2010-05-27 13:44:11 -0400 | [diff] [blame] | 167 | if (a >= 0) { | 
|  | 168 | // Move a back so any whitespace before AM/PM is also in the alternate size. | 
|  | 169 | final int b = a; | 
|  | 170 | while (a > 0 && Character.isWhitespace(format.charAt(a-1))) { | 
|  | 171 | a--; | 
|  | 172 | } | 
|  | 173 | format = format.substring(0, a) + MAGIC1 + format.substring(a, b) | 
| Joe Onorato | 263700d | 2010-05-14 11:54:53 -0700 | [diff] [blame] | 174 | + "a" + MAGIC2 + format.substring(b + 1); | 
| Daniel Sandler | 87937db | 2010-05-27 13:44:11 -0400 | [diff] [blame] | 175 | } | 
| Joe Onorato | 263700d | 2010-05-14 11:54:53 -0700 | [diff] [blame] | 176 | } | 
| Joe Onorato | 263700d | 2010-05-14 11:54:53 -0700 | [diff] [blame] | 177 | mClockFormat = sdf = new SimpleDateFormat(format); | 
|  | 178 | mClockFormatString = format; | 
|  | 179 | } else { | 
|  | 180 | sdf = mClockFormat; | 
|  | 181 | } | 
|  | 182 | String result = sdf.format(mCalendar.getTime()); | 
|  | 183 |  | 
| Daniel Sandler | 87937db | 2010-05-27 13:44:11 -0400 | [diff] [blame] | 184 | if (AM_PM_STYLE != AM_PM_STYLE_NORMAL) { | 
|  | 185 | int magic1 = result.indexOf(MAGIC1); | 
|  | 186 | int magic2 = result.indexOf(MAGIC2); | 
|  | 187 | if (magic1 >= 0 && magic2 > magic1) { | 
|  | 188 | SpannableStringBuilder formatted = new SpannableStringBuilder(result); | 
|  | 189 | if (AM_PM_STYLE == AM_PM_STYLE_GONE) { | 
|  | 190 | formatted.delete(magic1, magic2+1); | 
|  | 191 | } else { | 
|  | 192 | if (AM_PM_STYLE == AM_PM_STYLE_SMALL) { | 
|  | 193 | CharacterStyle style = new RelativeSizeSpan(0.7f); | 
|  | 194 | formatted.setSpan(style, magic1, magic2, | 
|  | 195 | Spannable.SPAN_EXCLUSIVE_INCLUSIVE); | 
|  | 196 | } | 
|  | 197 | formatted.delete(magic2, magic2 + 1); | 
|  | 198 | formatted.delete(magic1, magic1 + 1); | 
|  | 199 | } | 
|  | 200 | return formatted; | 
|  | 201 | } | 
| Joe Onorato | 263700d | 2010-05-14 11:54:53 -0700 | [diff] [blame] | 202 | } | 
| Daniel Sandler | 87937db | 2010-05-27 13:44:11 -0400 | [diff] [blame] | 203 |  | 
|  | 204 | return result; | 
|  | 205 |  | 
| Joe Onorato | 263700d | 2010-05-14 11:54:53 -0700 | [diff] [blame] | 206 | } | 
|  | 207 | } | 
|  | 208 |  |