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