blob: 2b656c220d635651388768b02647c9cdf6cd6c4c [file] [log] [blame]
Jim Millerdcb3d842012-08-23 19:18:12 -07001/*
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
Jim Miller5ecd8112013-01-09 18:50:26 -080017package com.android.keyguard;
Jim Millerdcb3d842012-08-23 19:18:12 -070018
Jose Lima235510e2014-08-13 12:50:01 -070019import android.app.AlarmManager;
Jim Millerdcb3d842012-08-23 19:18:12 -070020import android.content.Context;
Jorim Jaggie210cc82014-08-12 23:44:59 +020021import android.content.res.Configuration;
Jim Miller0c486892013-10-11 16:21:45 -070022import android.content.res.Resources;
Lucas Dupin76d38e72017-05-13 22:04:22 -070023import android.graphics.Color;
Geoffrey Pitschc239fef2017-07-14 09:55:16 -040024import android.os.Handler;
25import android.os.Looper;
Adrian Roos9dd16eb2015-01-08 16:20:49 +010026import android.os.UserHandle;
Lucas Dupin76d38e72017-05-13 22:04:22 -070027import android.support.v4.graphics.ColorUtils;
Jim Milleredc74ab2012-11-06 21:46:11 -080028import android.text.TextUtils;
Jim Miller38ab2772013-10-08 15:32:09 -070029import android.text.format.DateFormat;
Lucas Dupin6bd86012017-12-05 17:58:57 -080030import android.util.ArraySet;
Jim Millerdcb3d842012-08-23 19:18:12 -070031import android.util.AttributeSet;
Jim Miller20daffd2013-10-07 14:59:53 -070032import android.util.Log;
Jim Milleredc74ab2012-11-06 21:46:11 -080033import android.util.Slog;
Jorim Jaggie210cc82014-08-12 23:44:59 +020034import android.util.TypedValue;
Jim Milleredc74ab2012-11-06 21:46:11 -080035import android.view.View;
Adrian Roos7907ff22017-01-17 15:44:11 -080036import android.view.ViewGroup;
Jim Millerdcb3d842012-08-23 19:18:12 -070037import android.widget.GridLayout;
Jim Miller38ab2772013-10-08 15:32:09 -070038import android.widget.TextClock;
Jim Milleredc74ab2012-11-06 21:46:11 -080039import android.widget.TextView;
Jim Millerdcb3d842012-08-23 19:18:12 -070040
Michael Jurka1254f2f2012-10-25 11:44:31 -070041import com.android.internal.widget.LockPatternUtils;
42
Lucas Dupin6bd86012017-12-05 17:58:57 -080043import com.google.android.collect.Sets;
44
Chris Wren56018e52013-01-15 10:59:43 -050045import java.util.Locale;
46
Jim Millerdcb3d842012-08-23 19:18:12 -070047public class KeyguardStatusView extends GridLayout {
Jorim Jaggi5cf17872014-03-26 18:31:48 +010048 private static final boolean DEBUG = KeyguardConstants.DEBUG;
Jim Milleredc74ab2012-11-06 21:46:11 -080049 private static final String TAG = "KeyguardStatusView";
Geoffrey Pitschc239fef2017-07-14 09:55:16 -040050 private static final int MARQUEE_DELAY_MS = 2000;
Jim Milleredc74ab2012-11-06 21:46:11 -080051
Adrian Roos9dd16eb2015-01-08 16:20:49 +010052 private final LockPatternUtils mLockPatternUtils;
53 private final AlarmManager mAlarmManager;
Lucas Dupin6bd86012017-12-05 17:58:57 -080054 private final float mSmallClockScale;
55 private final float mWidgetPadding;
Jim Milleredc74ab2012-11-06 21:46:11 -080056
Jim Miller0c486892013-10-11 16:21:45 -070057 private TextClock mClockView;
Lucas Dupin6bd86012017-12-05 17:58:57 -080058 private View mClockSeparator;
Jorim Jaggi93afa1d2014-06-03 20:56:32 +020059 private TextView mOwnerInfo;
Adrian Roos7907ff22017-01-17 15:44:11 -080060 private ViewGroup mClockContainer;
Lucas Dupin957e50c2017-10-10 11:23:27 -070061 private KeyguardSliceView mKeyguardSlice;
Geoffrey Pitschc239fef2017-07-14 09:55:16 -040062 private Runnable mPendingMarqueeStart;
63 private Handler mHandler;
Jim Milleredc74ab2012-11-06 21:46:11 -080064
Lucas Dupin6bd86012017-12-05 17:58:57 -080065 private ArraySet<View> mVisibleInDoze;
Adrian Roosd83e9992017-03-16 15:17:57 -070066 private boolean mPulsing;
Adrian Roos7f910722017-07-12 19:15:59 +020067 private float mDarkAmount = 0;
Lucas Dupin76d38e72017-05-13 22:04:22 -070068 private int mTextColor;
Adrian Roosd83e9992017-03-16 15:17:57 -070069
Jim Milleredc74ab2012-11-06 21:46:11 -080070 private KeyguardUpdateMonitorCallback mInfoCallback = new KeyguardUpdateMonitorCallback() {
71
72 @Override
73 public void onTimeChanged() {
74 refresh();
75 }
76
77 @Override
Jorim Jaggi5cf17872014-03-26 18:31:48 +010078 public void onKeyguardVisibilityChanged(boolean showing) {
Jim Milleredc74ab2012-11-06 21:46:11 -080079 if (showing) {
80 if (DEBUG) Slog.v(TAG, "refresh statusview showing:" + showing);
81 refresh();
Jorim Jaggi93afa1d2014-06-03 20:56:32 +020082 updateOwnerInfo();
Jim Milleredc74ab2012-11-06 21:46:11 -080083 }
Jorim Jaggi5cf17872014-03-26 18:31:48 +010084 }
Jim Miller20daffd2013-10-07 14:59:53 -070085
Jim Miller38ab2772013-10-08 15:32:09 -070086 @Override
Jorim Jaggi0d210f62015-07-10 14:24:44 -070087 public void onStartedWakingUp() {
Jim Miller20daffd2013-10-07 14:59:53 -070088 setEnableMarquee(true);
Jorim Jaggi5cf17872014-03-26 18:31:48 +010089 }
Jim Miller20daffd2013-10-07 14:59:53 -070090
Jim Miller38ab2772013-10-08 15:32:09 -070091 @Override
Jorim Jaggi0d210f62015-07-10 14:24:44 -070092 public void onFinishedGoingToSleep(int why) {
Jim Miller20daffd2013-10-07 14:59:53 -070093 setEnableMarquee(false);
Jorim Jaggi5cf17872014-03-26 18:31:48 +010094 }
Jorim Jaggic7dea6e2014-07-26 14:36:57 +020095
96 @Override
97 public void onUserSwitchComplete(int userId) {
98 refresh();
Adrian Roose32dac82014-07-28 15:58:50 +020099 updateOwnerInfo();
Jorim Jaggic7dea6e2014-07-26 14:36:57 +0200100 }
Jim Milleredc74ab2012-11-06 21:46:11 -0800101 };
Jim Miller6212cc02012-09-05 17:35:31 -0700102
Jim Millerdcb3d842012-08-23 19:18:12 -0700103 public KeyguardStatusView(Context context) {
104 this(context, null, 0);
105 }
106
107 public KeyguardStatusView(Context context, AttributeSet attrs) {
108 this(context, attrs, 0);
109 }
110
111 public KeyguardStatusView(Context context, AttributeSet attrs, int defStyle) {
112 super(context, attrs, defStyle);
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100113 mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
114 mLockPatternUtils = new LockPatternUtils(getContext());
Geoffrey Pitschc239fef2017-07-14 09:55:16 -0400115 mHandler = new Handler(Looper.myLooper());
Lucas Dupin6bd86012017-12-05 17:58:57 -0800116 mSmallClockScale = getResources().getDimension(R.dimen.widget_small_font_size)
117 / getResources().getDimension(R.dimen.widget_big_font_size);
118 mWidgetPadding = getResources().getDimension(R.dimen.widget_vertical_padding);
Jim Millerdcb3d842012-08-23 19:18:12 -0700119 }
120
Jim Miller20daffd2013-10-07 14:59:53 -0700121 private void setEnableMarquee(boolean enabled) {
Geoffrey Pitschc239fef2017-07-14 09:55:16 -0400122 if (DEBUG) Log.v(TAG, "Schedule setEnableMarquee: " + (enabled ? "Enable" : "Disable"));
123 if (enabled) {
124 if (mPendingMarqueeStart == null) {
125 mPendingMarqueeStart = () -> {
126 setEnableMarqueeImpl(true);
127 mPendingMarqueeStart = null;
128 };
129 mHandler.postDelayed(mPendingMarqueeStart, MARQUEE_DELAY_MS);
130 }
131 } else {
132 if (mPendingMarqueeStart != null) {
133 mHandler.removeCallbacks(mPendingMarqueeStart);
134 mPendingMarqueeStart = null;
135 }
136 setEnableMarqueeImpl(false);
137 }
138 }
139
140 private void setEnableMarqueeImpl(boolean enabled) {
Jim Miller20daffd2013-10-07 14:59:53 -0700141 if (DEBUG) Log.v(TAG, (enabled ? "Enable" : "Disable") + " transport text marquee");
John Spurlock1e6eb172014-07-13 11:59:50 -0400142 if (mOwnerInfo != null) mOwnerInfo.setSelected(enabled);
Jim Miller20daffd2013-10-07 14:59:53 -0700143 }
144
Jim Milleredc74ab2012-11-06 21:46:11 -0800145 @Override
146 protected void onFinishInflate() {
147 super.onFinishInflate();
Alan Viverette51efddb2017-04-05 10:00:01 -0400148 mClockContainer = findViewById(R.id.keyguard_clock_container);
Alan Viverette51efddb2017-04-05 10:00:01 -0400149 mClockView = findViewById(R.id.clock_view);
Selim Cinek9c4a7072014-11-21 17:44:34 +0100150 mClockView.setShowCurrentUserTime(true);
Adrian Roosb670f4b2017-07-20 20:06:54 +0200151 if (KeyguardClockAccessibilityDelegate.isNeeded(mContext)) {
152 mClockView.setAccessibilityDelegate(new KeyguardClockAccessibilityDelegate(mContext));
153 }
Alan Viverette51efddb2017-04-05 10:00:01 -0400154 mOwnerInfo = findViewById(R.id.owner_info);
Lucas Dupin957e50c2017-10-10 11:23:27 -0700155 mKeyguardSlice = findViewById(R.id.keyguard_status_area);
Lucas Dupin6bd86012017-12-05 17:58:57 -0800156 mClockSeparator = findViewById(R.id.clock_separator);
Lucas Dupin4272f442018-01-13 22:00:35 -0800157 mVisibleInDoze = Sets.newArraySet(mClockView, mKeyguardSlice, mClockSeparator);
Lucas Dupin76d38e72017-05-13 22:04:22 -0700158 mTextColor = mClockView.getCurrentTextColor();
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100159
Lucas Dupin6bd86012017-12-05 17:58:57 -0800160 mKeyguardSlice.setListener(this::onSliceContentChanged);
161 onSliceContentChanged(mKeyguardSlice.hasHeader());
162
Jorim Jaggi0d210f62015-07-10 14:24:44 -0700163 boolean shouldMarquee = KeyguardUpdateMonitor.getInstance(mContext).isDeviceInteractive();
164 setEnableMarquee(shouldMarquee);
Jim Milleredc74ab2012-11-06 21:46:11 -0800165 refresh();
Jorim Jaggi93afa1d2014-06-03 20:56:32 +0200166 updateOwnerInfo();
Jorim Jaggicc12a9d2014-05-26 01:55:29 +0200167
168 // Disable elegant text height because our fancy colon makes the ymin value huge for no
169 // reason.
170 mClockView.setElegantTextHeight(false);
Jim Milleredc74ab2012-11-06 21:46:11 -0800171 }
172
Lucas Dupin6bd86012017-12-05 17:58:57 -0800173 private void onSliceContentChanged(boolean hasHeader) {
Lucas Dupin6bf7b642018-01-22 18:56:24 -0800174 final boolean smallClock = hasHeader || mPulsing;
175 final float clockScale = smallClock ? mSmallClockScale : 1;
Lucas Dupin6bd86012017-12-05 17:58:57 -0800176 float translation = (mClockView.getHeight() - (mClockView.getHeight() * clockScale)) / 2f;
Lucas Dupin6bf7b642018-01-22 18:56:24 -0800177 if (smallClock) {
Lucas Dupin6bd86012017-12-05 17:58:57 -0800178 translation -= mWidgetPadding;
179 }
180 mClockView.setTranslationY(translation);
181 mClockView.setScaleX(clockScale);
182 mClockView.setScaleY(clockScale);
Lucas Dupin6bf7b642018-01-22 18:56:24 -0800183 mClockSeparator.setVisibility(hasHeader && !mPulsing ? VISIBLE : GONE);
Lucas Dupin6bd86012017-12-05 17:58:57 -0800184 }
185
Jorim Jaggie210cc82014-08-12 23:44:59 +0200186 @Override
187 protected void onConfigurationChanged(Configuration newConfig) {
188 super.onConfigurationChanged(newConfig);
189 mClockView.setTextSize(TypedValue.COMPLEX_UNIT_PX,
190 getResources().getDimensionPixelSize(R.dimen.widget_big_font_size));
Selim Cinekb6143c12016-07-14 16:32:23 -0700191 // Some layouts like burmese have a different margin for the clock
192 MarginLayoutParams layoutParams = (MarginLayoutParams) mClockView.getLayoutParams();
193 layoutParams.bottomMargin = getResources().getDimensionPixelSize(
194 R.dimen.bottom_text_spacing_digital);
195 mClockView.setLayoutParams(layoutParams);
Jorim Jaggiad15b492017-05-30 18:01:49 -0700196 if (mOwnerInfo != null) {
197 mOwnerInfo.setTextSize(TypedValue.COMPLEX_UNIT_PX,
198 getResources().getDimensionPixelSize(R.dimen.widget_label_font_size));
199 }
Jorim Jaggie210cc82014-08-12 23:44:59 +0200200 }
201
Jorim Jaggid09def7512014-09-02 18:36:45 +0200202 public void refreshTime() {
John Spurlock385a63d2013-10-30 19:40:48 -0400203 mClockView.setFormat12Hour(Patterns.clockView12);
204 mClockView.setFormat24Hour(Patterns.clockView24);
Jorim Jaggid09def7512014-09-02 18:36:45 +0200205 }
Jim Miller0c486892013-10-11 16:21:45 -0700206
Jorim Jaggid09def7512014-09-02 18:36:45 +0200207 private void refresh() {
Adrian Roos9dd16eb2015-01-08 16:20:49 +0100208 AlarmManager.AlarmClockInfo nextAlarm =
209 mAlarmManager.getNextAlarmClock(UserHandle.USER_CURRENT);
Jorim Jaggid09def7512014-09-02 18:36:45 +0200210 Patterns.update(mContext, nextAlarm != null);
211
212 refreshTime();
Jim Milleredc74ab2012-11-06 21:46:11 -0800213 }
214
Adrian Roosc934c432017-01-13 11:44:56 -0800215 public int getClockBottom() {
Lucas Dupin957e50c2017-10-10 11:23:27 -0700216 return mKeyguardSlice.getVisibility() == VISIBLE ? mKeyguardSlice.getBottom()
217 : mClockView.getBottom();
Adrian Roosc934c432017-01-13 11:44:56 -0800218 }
219
Lucas Dupin987f1932017-05-13 21:02:52 -0700220 public float getClockTextSize() {
221 return mClockView.getTextSize();
222 }
223
Jorim Jaggi93afa1d2014-06-03 20:56:32 +0200224 private void updateOwnerInfo() {
John Spurlock1e6eb172014-07-13 11:59:50 -0400225 if (mOwnerInfo == null) return;
Jorim Jaggi93afa1d2014-06-03 20:56:32 +0200226 String ownerInfo = getOwnerInfo();
227 if (!TextUtils.isEmpty(ownerInfo)) {
228 mOwnerInfo.setVisibility(View.VISIBLE);
229 mOwnerInfo.setText(ownerInfo);
230 } else {
231 mOwnerInfo.setVisibility(View.GONE);
232 }
233 }
234
Jim Milleredc74ab2012-11-06 21:46:11 -0800235 @Override
236 protected void onAttachedToWindow() {
237 super.onAttachedToWindow();
238 KeyguardUpdateMonitor.getInstance(mContext).registerCallback(mInfoCallback);
239 }
240
241 @Override
242 protected void onDetachedFromWindow() {
243 super.onDetachedFromWindow();
244 KeyguardUpdateMonitor.getInstance(mContext).removeCallback(mInfoCallback);
245 }
246
Jorim Jaggi93afa1d2014-06-03 20:56:32 +0200247 private String getOwnerInfo() {
Jorim Jaggi93afa1d2014-06-03 20:56:32 +0200248 String info = null;
Andrei Stingaceanu04e245b2015-11-12 12:15:56 +0000249 if (mLockPatternUtils.isDeviceOwnerInfoEnabled()) {
250 // Use the device owner information set by device policy client via
251 // device policy manager.
252 info = mLockPatternUtils.getDeviceOwnerInfo();
253 } else {
254 // Use the current user owner information if enabled.
255 final boolean ownerInfoEnabled = mLockPatternUtils.isOwnerInfoEnabled(
256 KeyguardUpdateMonitor.getCurrentUser());
257 if (ownerInfoEnabled) {
258 info = mLockPatternUtils.getOwnerInfo(KeyguardUpdateMonitor.getCurrentUser());
259 }
Jorim Jaggi93afa1d2014-06-03 20:56:32 +0200260 }
261 return info;
262 }
263
Selim Cinekf99d0002014-06-13 07:36:01 +0200264 @Override
265 public boolean hasOverlappingRendering() {
266 return false;
267 }
268
John Spurlock385a63d2013-10-30 19:40:48 -0400269 // DateFormat.getBestDateTimePattern is extremely expensive, and refresh is called often.
270 // This is an optimization to ensure we only recompute the patterns when the inputs change.
271 private static final class Patterns {
Adrian Roos59de4f32017-05-31 15:22:38 -0700272 static String dateViewSkel;
John Spurlock385a63d2013-10-30 19:40:48 -0400273 static String clockView12;
274 static String clockView24;
275 static String cacheKey;
276
Jorim Jaggic7dea6e2014-07-26 14:36:57 +0200277 static void update(Context context, boolean hasAlarm) {
John Spurlock385a63d2013-10-30 19:40:48 -0400278 final Locale locale = Locale.getDefault();
279 final Resources res = context.getResources();
Adrian Roos59de4f32017-05-31 15:22:38 -0700280 dateViewSkel = res.getString(hasAlarm
Jorim Jaggic7dea6e2014-07-26 14:36:57 +0200281 ? R.string.abbrev_wday_month_day_no_year_alarm
282 : R.string.abbrev_wday_month_day_no_year);
John Spurlock385a63d2013-10-30 19:40:48 -0400283 final String clockView12Skel = res.getString(R.string.clock_12hr_format);
284 final String clockView24Skel = res.getString(R.string.clock_24hr_format);
285 final String key = locale.toString() + dateViewSkel + clockView12Skel + clockView24Skel;
286 if (key.equals(cacheKey)) return;
287
John Spurlock385a63d2013-10-30 19:40:48 -0400288 clockView12 = DateFormat.getBestDateTimePattern(locale, clockView12Skel);
289 // CLDR insists on adding an AM/PM indicator even though it wasn't in the skeleton
290 // format. The following code removes the AM/PM indicator if we didn't want it.
291 if (!clockView12Skel.contains("a")) {
292 clockView12 = clockView12.replaceAll("a", "").trim();
293 }
294
295 clockView24 = DateFormat.getBestDateTimePattern(locale, clockView24Skel);
296
Jorim Jaggicc12a9d2014-05-26 01:55:29 +0200297 // Use fancy colon.
298 clockView24 = clockView24.replace(':', '\uee01');
299 clockView12 = clockView12.replace(':', '\uee01');
300
John Spurlock385a63d2013-10-30 19:40:48 -0400301 cacheKey = key;
302 }
303 }
Adrian Roos7907ff22017-01-17 15:44:11 -0800304
Lucas Dupin4272f442018-01-13 22:00:35 -0800305 public void setDarkAmount(float darkAmount) {
Lucas Dupin76d38e72017-05-13 22:04:22 -0700306 if (mDarkAmount == darkAmount) {
Adrian Roos52414e32017-04-28 09:23:19 -0700307 return;
308 }
Lucas Dupin76d38e72017-05-13 22:04:22 -0700309 mDarkAmount = darkAmount;
Adrian Roosd83e9992017-03-16 15:17:57 -0700310
Lucas Dupin76d38e72017-05-13 22:04:22 -0700311 boolean dark = darkAmount == 1;
Adrian Roos7907ff22017-01-17 15:44:11 -0800312 final int N = mClockContainer.getChildCount();
313 for (int i = 0; i < N; i++) {
314 View child = mClockContainer.getChildAt(i);
Lucas Dupin6bd86012017-12-05 17:58:57 -0800315 if (mVisibleInDoze.contains(child)) {
Adrian Roos7907ff22017-01-17 15:44:11 -0800316 continue;
317 }
318 child.setAlpha(dark ? 0 : 1);
319 }
Adrian Roos8e130f02017-07-20 15:14:25 +0200320 if (mOwnerInfo != null) {
321 mOwnerInfo.setAlpha(dark ? 0 : 1);
322 }
323
Lucas Dupin6bd86012017-12-05 17:58:57 -0800324 final int blendedTextColor = ColorUtils.blendARGB(mTextColor, Color.WHITE, darkAmount);
Adrian Roosd83e9992017-03-16 15:17:57 -0700325 updateDozeVisibleViews();
Lucas Dupin957e50c2017-10-10 11:23:27 -0700326 mKeyguardSlice.setDark(darkAmount);
Lucas Dupin6bd86012017-12-05 17:58:57 -0800327 mClockView.setTextColor(blendedTextColor);
328 mClockSeparator.setBackgroundColor(blendedTextColor);
Adrian Roos7907ff22017-01-17 15:44:11 -0800329 }
Adrian Roosd83e9992017-03-16 15:17:57 -0700330
331 public void setPulsing(boolean pulsing) {
332 mPulsing = pulsing;
Lucas Dupin6bf7b642018-01-22 18:56:24 -0800333 mKeyguardSlice.setVisibility(pulsing ? GONE : VISIBLE);
334 onSliceContentChanged(mKeyguardSlice.hasHeader());
Adrian Roosd83e9992017-03-16 15:17:57 -0700335 updateDozeVisibleViews();
336 }
337
338 private void updateDozeVisibleViews() {
339 for (View child : mVisibleInDoze) {
Lucas Dupin76d38e72017-05-13 22:04:22 -0700340 child.setAlpha(mDarkAmount == 1 && mPulsing ? 0.8f : 1);
Adrian Roosd83e9992017-03-16 15:17:57 -0700341 }
342 }
Jim Millerdcb3d842012-08-23 19:18:12 -0700343}