1 /* 2 * Copyright (C) 2008 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 com.android.deskclock; 18 19 import android.content.BroadcastReceiver; 20 import android.content.Context; 21 import android.content.Intent; 22 import android.content.IntentFilter; 23 import android.database.ContentObserver; 24 import android.graphics.Typeface; 25 import android.os.Handler; 26 import android.provider.Settings; 27 import android.text.format.DateFormat; 28 import android.util.AttributeSet; 29 import android.view.View; 30 import android.widget.LinearLayout; 31 import android.widget.TextView; 32 33 import java.text.DateFormatSymbols; 34 import java.util.Calendar; 35 import java.util.TimeZone; 36 37 /** 38 * Displays the time 39 */ 40 public class DigitalClock extends LinearLayout { 41 42 private final static String HOURS_24 = "kk"; 43 private final static String HOURS = "h"; 44 private final static String MINUTES = ":mm"; 45 46 private Calendar mCalendar; 47 private String mHoursFormat; 48 private TextView mTimeDisplayHours, mTimeDisplayMinutes; 49 private AmPm mAmPm; 50 private ContentObserver mFormatChangeObserver; 51 private boolean mLive = true; 52 private boolean mAttached; 53 private final Typeface mRobotoThin; 54 private String mTimeZoneId; 55 56 57 /* called by system on minute ticks */ 58 private final Handler mHandler = new Handler(); 59 private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { 60 @Override 61 public void onReceive(Context context, Intent intent) { 62 if (mLive && intent.getAction().equals( 63 Intent.ACTION_TIMEZONE_CHANGED)) { 64 mCalendar = Calendar.getInstance(); 65 } 66 // Post a runnable to avoid blocking the broadcast. 67 mHandler.post(new Runnable() { 68 public void run() { 69 updateTime(); 70 } 71 }); 72 } 73 }; 74 75 static class AmPm { 76 private final TextView mAmPm; 77 private final String mAmString, mPmString; 78 79 AmPm(View parent) { 80 mAmPm = (TextView) parent.findViewById(R.id.am_pm); 81 82 String[] ampm = new DateFormatSymbols().getAmPmStrings(); 83 mAmString = ampm[0]; 84 mPmString = ampm[1]; 85 } 86 87 void setShowAmPm(boolean show) { 88 mAmPm.setVisibility(show ? View.VISIBLE : View.GONE); 89 } 90 91 void setIsMorning(boolean isMorning) { 92 mAmPm.setText(isMorning ? mAmString : mPmString); 93 } 94 95 CharSequence getAmPmText() { 96 return mAmPm.getText(); 97 } 98 } 99 100 private class FormatChangeObserver extends ContentObserver { 101 public FormatChangeObserver() { 102 super(new Handler()); 103 } 104 @Override 105 public void onChange(boolean selfChange) { 106 setDateFormat(); 107 updateTime(); 108 } 109 } 110 111 public DigitalClock(Context context) { 112 this(context, null); 113 } 114 115 public DigitalClock(Context context, AttributeSet attrs) { 116 super(context, attrs); 117 mRobotoThin = Typeface.createFromAsset(context.getAssets(),"fonts/Roboto-Thin.ttf"); 118 } 119 120 @Override 121 protected void onFinishInflate() { 122 super.onFinishInflate(); 123 124 mTimeDisplayHours = (TextView)findViewById(R.id.timeDisplayHours); 125 mTimeDisplayMinutes = (TextView)findViewById(R.id.timeDisplayMinutes); 126 mTimeDisplayMinutes.setTypeface(mRobotoThin); 127 mAmPm = new AmPm(this); 128 mCalendar = Calendar.getInstance(); 129 130 setDateFormat(); 131 } 132 133 @Override 134 protected void onAttachedToWindow() { 135 super.onAttachedToWindow(); 136 137 if (Log.LOGV) Log.v("onAttachedToWindow " + this); 138 139 if (mAttached) return; 140 mAttached = true; 141 142 if (mLive) { 143 /* monitor time ticks, time changed, timezone */ 144 IntentFilter filter = new IntentFilter(); 145 filter.addAction(Intent.ACTION_TIME_TICK); 146 filter.addAction(Intent.ACTION_TIME_CHANGED); 147 filter.addAction(Intent.ACTION_TIMEZONE_CHANGED); 148 getContext().registerReceiver(mIntentReceiver, filter); 149 } 150 151 /* monitor 12/24-hour display preference */ 152 mFormatChangeObserver = new FormatChangeObserver(); 153 getContext().getContentResolver().registerContentObserver( 154 Settings.System.CONTENT_URI, true, mFormatChangeObserver); 155 156 updateTime(); 157 } 158 159 @Override 160 protected void onDetachedFromWindow() { 161 super.onDetachedFromWindow(); 162 163 if (!mAttached) return; 164 mAttached = false; 165 166 if (mLive) { 167 getContext().unregisterReceiver(mIntentReceiver); 168 } 169 getContext().getContentResolver().unregisterContentObserver( 170 mFormatChangeObserver); 171 } 172 173 174 void updateTime(Calendar c) { 175 mCalendar = c; 176 updateTime(); 177 } 178 179 public void updateTime(int hour, int minute) { 180 // set the alarm text 181 final Calendar c = Calendar.getInstance(); 182 c.set(Calendar.HOUR_OF_DAY, hour); 183 c.set(Calendar.MINUTE, minute); 184 mCalendar = c; 185 updateTime(); 186 } 187 188 private void updateTime() { 189 if (mLive) { 190 mCalendar.setTimeInMillis(System.currentTimeMillis()); 191 } 192 if (mTimeZoneId != null) { 193 mCalendar.setTimeZone(TimeZone.getTimeZone(mTimeZoneId)); 194 } 195 196 StringBuilder fullTimeStr = new StringBuilder(); 197 CharSequence newTime = DateFormat.format(mHoursFormat, mCalendar); 198 mTimeDisplayHours.setText(newTime); 199 fullTimeStr.append(newTime); 200 newTime = DateFormat.format(MINUTES, mCalendar); 201 fullTimeStr.append(newTime); 202 mTimeDisplayMinutes.setText(newTime); 203 204 boolean isMorning = mCalendar.get(Calendar.AM_PM) == 0; 205 mAmPm.setIsMorning(isMorning); 206 if (!Alarms.get24HourMode(getContext())) { 207 fullTimeStr.append(mAmPm.getAmPmText()); 208 } 209 210 // Update accessibility string. 211 setContentDescription(fullTimeStr); 212 } 213 214 private void setDateFormat() { 215 mHoursFormat = Alarms.get24HourMode(getContext()) ? HOURS_24 : HOURS; 216 mAmPm.setShowAmPm(!Alarms.get24HourMode(getContext())); 217 } 218 219 void setLive(boolean live) { 220 mLive = live; 221 } 222 223 public void setTimeZone(String id) { 224 mTimeZoneId = id; 225 updateTime(); 226 } 227 } 228