KeyguardStatusView.java revision d09def75110ea9833e3985ce33a878a471a8a0dc
1/* 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 17package com.android.keyguard; 18 19import android.app.AlarmManager; 20import android.content.ContentResolver; 21import android.content.Context; 22import android.content.res.Configuration; 23import android.content.res.Resources; 24import android.provider.AlarmClock; 25import android.text.TextUtils; 26import android.text.format.DateFormat; 27import android.util.AttributeSet; 28import android.util.Log; 29import android.util.Slog; 30import android.util.TypedValue; 31import android.view.View; 32import android.widget.GridLayout; 33import android.widget.TextClock; 34import android.widget.TextView; 35 36import com.android.internal.widget.LockPatternUtils; 37 38import java.util.Locale; 39 40public class KeyguardStatusView extends GridLayout { 41 private static final boolean DEBUG = KeyguardConstants.DEBUG; 42 private static final String TAG = "KeyguardStatusView"; 43 44 private LockPatternUtils mLockPatternUtils; 45 46 private TextView mAlarmStatusView; 47 private TextClock mDateView; 48 private TextClock mClockView; 49 private TextView mOwnerInfo; 50 51 private KeyguardUpdateMonitorCallback mInfoCallback = new KeyguardUpdateMonitorCallback() { 52 53 @Override 54 public void onTimeChanged() { 55 refresh(); 56 } 57 58 @Override 59 public void onKeyguardVisibilityChanged(boolean showing) { 60 if (showing) { 61 if (DEBUG) Slog.v(TAG, "refresh statusview showing:" + showing); 62 refresh(); 63 updateOwnerInfo(); 64 } 65 } 66 67 @Override 68 public void onScreenTurnedOn() { 69 setEnableMarquee(true); 70 } 71 72 @Override 73 public void onScreenTurnedOff(int why) { 74 setEnableMarquee(false); 75 } 76 77 @Override 78 public void onUserSwitchComplete(int userId) { 79 refresh(); 80 updateOwnerInfo(); 81 } 82 }; 83 84 public KeyguardStatusView(Context context) { 85 this(context, null, 0); 86 } 87 88 public KeyguardStatusView(Context context, AttributeSet attrs) { 89 this(context, attrs, 0); 90 } 91 92 public KeyguardStatusView(Context context, AttributeSet attrs, int defStyle) { 93 super(context, attrs, defStyle); 94 } 95 96 private void setEnableMarquee(boolean enabled) { 97 if (DEBUG) Log.v(TAG, (enabled ? "Enable" : "Disable") + " transport text marquee"); 98 if (mAlarmStatusView != null) mAlarmStatusView.setSelected(enabled); 99 if (mOwnerInfo != null) mOwnerInfo.setSelected(enabled); 100 } 101 102 @Override 103 protected void onFinishInflate() { 104 super.onFinishInflate(); 105 mAlarmStatusView = (TextView) findViewById(R.id.alarm_status); 106 mDateView = (TextClock) findViewById(R.id.date_view); 107 mClockView = (TextClock) findViewById(R.id.clock_view); 108 mOwnerInfo = (TextView) findViewById(R.id.owner_info); 109 mLockPatternUtils = new LockPatternUtils(getContext()); 110 final boolean screenOn = KeyguardUpdateMonitor.getInstance(mContext).isScreenOn(); 111 setEnableMarquee(screenOn); 112 refresh(); 113 updateOwnerInfo(); 114 115 // Disable elegant text height because our fancy colon makes the ymin value huge for no 116 // reason. 117 mClockView.setElegantTextHeight(false); 118 } 119 120 @Override 121 protected void onConfigurationChanged(Configuration newConfig) { 122 super.onConfigurationChanged(newConfig); 123 mClockView.setTextSize(TypedValue.COMPLEX_UNIT_PX, 124 getResources().getDimensionPixelSize(R.dimen.widget_big_font_size)); 125 mDateView.setTextSize(TypedValue.COMPLEX_UNIT_PX, 126 getResources().getDimensionPixelSize(R.dimen.widget_label_font_size)); 127 mOwnerInfo.setTextSize(TypedValue.COMPLEX_UNIT_PX, 128 getResources().getDimensionPixelSize(R.dimen.widget_label_font_size)); 129 } 130 131 public void refreshTime() { 132 mDateView.setFormat24Hour(Patterns.dateView); 133 mDateView.setFormat12Hour(Patterns.dateView); 134 135 mClockView.setFormat12Hour(Patterns.clockView12); 136 mClockView.setFormat24Hour(Patterns.clockView24); 137 } 138 139 private void refresh() { 140 AlarmManager.AlarmClockInfo nextAlarm = mLockPatternUtils.getNextAlarm(); 141 Patterns.update(mContext, nextAlarm != null); 142 143 refreshTime(); 144 refreshAlarmStatus(nextAlarm); 145 } 146 147 void refreshAlarmStatus(AlarmManager.AlarmClockInfo nextAlarm) { 148 if (nextAlarm != null) { 149 String alarm = formatNextAlarm(mContext, nextAlarm); 150 mAlarmStatusView.setText(alarm); 151 mAlarmStatusView.setContentDescription( 152 getResources().getString(R.string.keyguard_accessibility_next_alarm, alarm)); 153 mAlarmStatusView.setVisibility(View.VISIBLE); 154 } else { 155 mAlarmStatusView.setVisibility(View.GONE); 156 } 157 } 158 159 public static String formatNextAlarm(Context context, AlarmManager.AlarmClockInfo info) { 160 if (info == null) { 161 return ""; 162 } 163 String skeleton = DateFormat.is24HourFormat(context) ? "EHm" : "Ehma"; 164 String pattern = DateFormat.getBestDateTimePattern(Locale.getDefault(), skeleton); 165 return DateFormat.format(pattern, info.getTriggerTime()).toString(); 166 } 167 168 private void updateOwnerInfo() { 169 if (mOwnerInfo == null) return; 170 String ownerInfo = getOwnerInfo(); 171 if (!TextUtils.isEmpty(ownerInfo)) { 172 mOwnerInfo.setVisibility(View.VISIBLE); 173 mOwnerInfo.setText(ownerInfo); 174 } else { 175 mOwnerInfo.setVisibility(View.GONE); 176 } 177 } 178 179 @Override 180 protected void onAttachedToWindow() { 181 super.onAttachedToWindow(); 182 KeyguardUpdateMonitor.getInstance(mContext).registerCallback(mInfoCallback); 183 } 184 185 @Override 186 protected void onDetachedFromWindow() { 187 super.onDetachedFromWindow(); 188 KeyguardUpdateMonitor.getInstance(mContext).removeCallback(mInfoCallback); 189 } 190 191 public int getAppWidgetId() { 192 return LockPatternUtils.ID_DEFAULT_STATUS_WIDGET; 193 } 194 195 private String getOwnerInfo() { 196 ContentResolver res = getContext().getContentResolver(); 197 String info = null; 198 final boolean ownerInfoEnabled = mLockPatternUtils.isOwnerInfoEnabled(); 199 if (ownerInfoEnabled) { 200 info = mLockPatternUtils.getOwnerInfo(mLockPatternUtils.getCurrentUser()); 201 } 202 return info; 203 } 204 205 @Override 206 public boolean hasOverlappingRendering() { 207 return false; 208 } 209 210 // DateFormat.getBestDateTimePattern is extremely expensive, and refresh is called often. 211 // This is an optimization to ensure we only recompute the patterns when the inputs change. 212 private static final class Patterns { 213 static String dateView; 214 static String clockView12; 215 static String clockView24; 216 static String cacheKey; 217 218 static void update(Context context, boolean hasAlarm) { 219 final Locale locale = Locale.getDefault(); 220 final Resources res = context.getResources(); 221 final String dateViewSkel = res.getString(hasAlarm 222 ? R.string.abbrev_wday_month_day_no_year_alarm 223 : R.string.abbrev_wday_month_day_no_year); 224 final String clockView12Skel = res.getString(R.string.clock_12hr_format); 225 final String clockView24Skel = res.getString(R.string.clock_24hr_format); 226 final String key = locale.toString() + dateViewSkel + clockView12Skel + clockView24Skel; 227 if (key.equals(cacheKey)) return; 228 229 dateView = DateFormat.getBestDateTimePattern(locale, dateViewSkel); 230 231 clockView12 = DateFormat.getBestDateTimePattern(locale, clockView12Skel); 232 // CLDR insists on adding an AM/PM indicator even though it wasn't in the skeleton 233 // format. The following code removes the AM/PM indicator if we didn't want it. 234 if (!clockView12Skel.contains("a")) { 235 clockView12 = clockView12.replaceAll("a", "").trim(); 236 } 237 238 clockView24 = DateFormat.getBestDateTimePattern(locale, clockView24Skel); 239 240 // Use fancy colon. 241 clockView24 = clockView24.replace(':', '\uee01'); 242 clockView12 = clockView12.replace(':', '\uee01'); 243 244 cacheKey = key; 245 } 246 } 247} 248