2 * Copyright (C) 2012 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package com.android.keyguard;
19 import android.app.ActivityManager;
20 import android.app.AlarmManager;
21 import android.content.Context;
22 import android.content.res.Configuration;
23 import android.content.res.Resources;
24 import android.os.UserHandle;
25 import android.text.TextUtils;
26 import android.text.format.DateFormat;
27 import android.util.AttributeSet;
28 import android.util.Log;
29 import android.util.Slog;
30 import android.util.TypedValue;
31 import android.view.View;
32 import android.widget.GridLayout;
33 import android.widget.TextClock;
34 import android.widget.TextView;
36 import com.android.internal.widget.LockPatternUtils;
38 import java.util.Locale;
40 public class KeyguardStatusView extends GridLayout {
41 private static final boolean DEBUG = KeyguardConstants.DEBUG;
42 private static final String TAG = "KeyguardStatusView";
44 private final LockPatternUtils mLockPatternUtils;
45 private final AlarmManager mAlarmManager;
47 private TextView mAlarmStatusView;
48 private TextClock mDateView;
49 private TextClock mClockView;
50 private TextView mOwnerInfo;
52 private KeyguardUpdateMonitorCallback mInfoCallback = new KeyguardUpdateMonitorCallback() {
55 public void onTimeChanged() {
60 public void onKeyguardVisibilityChanged(boolean showing) {
62 if (DEBUG) Slog.v(TAG, "refresh statusview showing:" + showing);
69 public void onStartedWakingUp() {
70 setEnableMarquee(true);
74 public void onFinishedGoingToSleep(int why) {
75 setEnableMarquee(false);
79 public void onUserSwitchComplete(int userId) {
85 public KeyguardStatusView(Context context) {
86 this(context, null, 0);
89 public KeyguardStatusView(Context context, AttributeSet attrs) {
90 this(context, attrs, 0);
93 public KeyguardStatusView(Context context, AttributeSet attrs, int defStyle) {
94 super(context, attrs, defStyle);
95 mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
96 mLockPatternUtils = new LockPatternUtils(getContext());
99 private void setEnableMarquee(boolean enabled) {
100 if (DEBUG) Log.v(TAG, (enabled ? "Enable" : "Disable") + " transport text marquee");
101 if (mAlarmStatusView != null) mAlarmStatusView.setSelected(enabled);
102 if (mOwnerInfo != null) mOwnerInfo.setSelected(enabled);
106 protected void onFinishInflate() {
107 super.onFinishInflate();
108 mAlarmStatusView = (TextView) findViewById(R.id.alarm_status);
109 mDateView = (TextClock) findViewById(R.id.date_view);
110 mClockView = (TextClock) findViewById(R.id.clock_view);
111 mDateView.setShowCurrentUserTime(true);
112 mClockView.setShowCurrentUserTime(true);
113 mOwnerInfo = (TextView) findViewById(R.id.owner_info);
115 boolean shouldMarquee = KeyguardUpdateMonitor.getInstance(mContext).isDeviceInteractive();
116 setEnableMarquee(shouldMarquee);
120 // Disable elegant text height because our fancy colon makes the ymin value huge for no
122 mClockView.setElegantTextHeight(false);
126 protected void onConfigurationChanged(Configuration newConfig) {
127 super.onConfigurationChanged(newConfig);
128 mClockView.setTextSize(TypedValue.COMPLEX_UNIT_PX,
129 getResources().getDimensionPixelSize(R.dimen.widget_big_font_size));
130 mDateView.setTextSize(TypedValue.COMPLEX_UNIT_PX,
131 getResources().getDimensionPixelSize(R.dimen.widget_label_font_size));
132 mOwnerInfo.setTextSize(TypedValue.COMPLEX_UNIT_PX,
133 getResources().getDimensionPixelSize(R.dimen.widget_label_font_size));
136 public void refreshTime() {
137 mDateView.setFormat24Hour(Patterns.dateView);
138 mDateView.setFormat12Hour(Patterns.dateView);
140 mClockView.setFormat12Hour(Patterns.clockView12);
141 mClockView.setFormat24Hour(Patterns.clockView24);
144 private void refresh() {
145 AlarmManager.AlarmClockInfo nextAlarm =
146 mAlarmManager.getNextAlarmClock(UserHandle.USER_CURRENT);
147 Patterns.update(mContext, nextAlarm != null);
150 refreshAlarmStatus(nextAlarm);
153 void refreshAlarmStatus(AlarmManager.AlarmClockInfo nextAlarm) {
154 if (nextAlarm != null) {
155 String alarm = formatNextAlarm(mContext, nextAlarm);
156 mAlarmStatusView.setText(alarm);
157 mAlarmStatusView.setContentDescription(
158 getResources().getString(R.string.keyguard_accessibility_next_alarm, alarm));
159 mAlarmStatusView.setVisibility(View.VISIBLE);
161 mAlarmStatusView.setVisibility(View.GONE);
165 public static String formatNextAlarm(Context context, AlarmManager.AlarmClockInfo info) {
169 String skeleton = DateFormat.is24HourFormat(context, ActivityManager.getCurrentUser())
172 String pattern = DateFormat.getBestDateTimePattern(Locale.getDefault(), skeleton);
173 return DateFormat.format(pattern, info.getTriggerTime()).toString();
176 private void updateOwnerInfo() {
177 if (mOwnerInfo == null) return;
178 String ownerInfo = getOwnerInfo();
179 if (!TextUtils.isEmpty(ownerInfo)) {
180 mOwnerInfo.setVisibility(View.VISIBLE);
181 mOwnerInfo.setText(ownerInfo);
183 mOwnerInfo.setVisibility(View.GONE);
188 protected void onAttachedToWindow() {
189 super.onAttachedToWindow();
190 KeyguardUpdateMonitor.getInstance(mContext).registerCallback(mInfoCallback);
194 protected void onDetachedFromWindow() {
195 super.onDetachedFromWindow();
196 KeyguardUpdateMonitor.getInstance(mContext).removeCallback(mInfoCallback);
199 private String getOwnerInfo() {
201 if (mLockPatternUtils.isDeviceOwnerInfoEnabled()) {
202 // Use the device owner information set by device policy client via
203 // device policy manager.
204 info = mLockPatternUtils.getDeviceOwnerInfo();
206 // Use the current user owner information if enabled.
207 final boolean ownerInfoEnabled = mLockPatternUtils.isOwnerInfoEnabled(
208 KeyguardUpdateMonitor.getCurrentUser());
209 if (ownerInfoEnabled) {
210 info = mLockPatternUtils.getOwnerInfo(KeyguardUpdateMonitor.getCurrentUser());
217 public boolean hasOverlappingRendering() {
221 // DateFormat.getBestDateTimePattern is extremely expensive, and refresh is called often.
222 // This is an optimization to ensure we only recompute the patterns when the inputs change.
223 private static final class Patterns {
224 static String dateView;
225 static String clockView12;
226 static String clockView24;
227 static String cacheKey;
229 static void update(Context context, boolean hasAlarm) {
230 final Locale locale = Locale.getDefault();
231 final Resources res = context.getResources();
232 final String dateViewSkel = res.getString(hasAlarm
233 ? R.string.abbrev_wday_month_day_no_year_alarm
234 : R.string.abbrev_wday_month_day_no_year);
235 final String clockView12Skel = res.getString(R.string.clock_12hr_format);
236 final String clockView24Skel = res.getString(R.string.clock_24hr_format);
237 final String key = locale.toString() + dateViewSkel + clockView12Skel + clockView24Skel;
238 if (key.equals(cacheKey)) return;
240 dateView = DateFormat.getBestDateTimePattern(locale, dateViewSkel);
242 clockView12 = DateFormat.getBestDateTimePattern(locale, clockView12Skel);
243 // CLDR insists on adding an AM/PM indicator even though it wasn't in the skeleton
244 // format. The following code removes the AM/PM indicator if we didn't want it.
245 if (!clockView12Skel.contains("a")) {
246 clockView12 = clockView12.replaceAll("a", "").trim();
249 clockView24 = DateFormat.getBestDateTimePattern(locale, clockView24Skel);
252 clockView24 = clockView24.replace(':', '\uee01');
253 clockView12 = clockView12.replace(':', '\uee01');