blob: 037a8d3146d2e6ad125d3d030b48b622884da55d [file] [log] [blame]
Jim Miller0b728242012-10-28 19:42:30 -07001/*
2 * Copyright (C) 2011 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 Miller0b728242012-10-28 19:42:30 -070018
Lucas Dupin2e838ac2019-04-17 16:50:58 -070019import static com.android.systemui.util.InjectionInflationController.VIEW_CONTEXT;
20
Jim Miller0b728242012-10-28 19:42:30 -070021import android.content.Context;
Jason Chang1e4a4bd2018-05-22 17:30:19 +080022import android.content.res.ColorStateList;
Lucas Dupin2e838ac2019-04-17 16:50:58 -070023import android.content.res.TypedArray;
24import android.graphics.Color;
Jim Miller0b728242012-10-28 19:42:30 -070025import android.os.Handler;
26import android.os.Looper;
Alan Viveretteb428b0f2013-02-07 12:19:15 -080027import android.os.SystemClock;
Jim Miller0b728242012-10-28 19:42:30 -070028import android.text.TextUtils;
29import android.util.AttributeSet;
Lucas Dupin32774922019-04-25 12:42:25 -070030import android.util.TypedValue;
Jim Miller0b728242012-10-28 19:42:30 -070031import android.view.View;
32import android.widget.TextView;
33
Lucas Dupin2e838ac2019-04-17 16:50:58 -070034import com.android.systemui.statusbar.policy.ConfigurationController;
35
Alan Viveretteb428b0f2013-02-07 12:19:15 -080036import java.lang.ref.WeakReference;
37
Lucas Dupin2e838ac2019-04-17 16:50:58 -070038import javax.inject.Inject;
39import javax.inject.Named;
40
Jim Miller0b728242012-10-28 19:42:30 -070041/***
42 * Manages a number of views inside of the given layout. See below for a list of widgets.
43 */
Lucas Dupin2e838ac2019-04-17 16:50:58 -070044public class KeyguardMessageArea extends TextView implements SecurityMessageDisplay,
45 ConfigurationController.ConfigurationListener {
Alan Viveretteb428b0f2013-02-07 12:19:15 -080046 /** Handler token posted with accessibility announcement runnables. */
47 private static final Object ANNOUNCE_TOKEN = new Object();
48
49 /**
50 * Delay before speaking an accessibility announcement. Used to prevent
51 * lift-to-type from interrupting itself.
52 */
53 private static final long ANNOUNCEMENT_DELAY = 250;
Selim Cinekcfafe4e2015-08-11 14:58:44 -070054 private static final int DEFAULT_COLOR = -1;
Alan Viveretteb428b0f2013-02-07 12:19:15 -080055
Adrian Roos28828b52015-05-25 18:48:14 -070056 private final Handler mHandler;
Lucas Dupin2e838ac2019-04-17 16:50:58 -070057 private final ConfigurationController mConfigurationController;
Jim Miller0b728242012-10-28 19:42:30 -070058
Lucas Dupin2e838ac2019-04-17 16:50:58 -070059 private ColorStateList mDefaultColorState;
Adrian Roos154b9ee2016-10-20 15:34:23 -070060 private CharSequence mMessage;
Jason Chang1e4a4bd2018-05-22 17:30:19 +080061 private ColorStateList mNextMessageColorState = ColorStateList.valueOf(DEFAULT_COLOR);
Lucas Dupin473f3a52019-04-30 15:33:28 -070062 private boolean mBouncerVisible;
Jim Miller187ec582013-04-15 18:27:54 -070063
Jim Miller0b728242012-10-28 19:42:30 -070064 private KeyguardUpdateMonitorCallback mInfoCallback = new KeyguardUpdateMonitorCallback() {
Jorim Jaggi0d210f62015-07-10 14:24:44 -070065 public void onFinishedGoingToSleep(int why) {
Jim Miller20daffd2013-10-07 14:59:53 -070066 setSelected(false);
Lucas Dupin473f3a52019-04-30 15:33:28 -070067 }
68
Jorim Jaggi0d210f62015-07-10 14:24:44 -070069 public void onStartedWakingUp() {
Jim Miller20daffd2013-10-07 14:59:53 -070070 setSelected(true);
Lucas Dupin473f3a52019-04-30 15:33:28 -070071 }
72
73 @Override
74 public void onKeyguardBouncerChanged(boolean bouncer) {
75 mBouncerVisible = bouncer;
76 update();
77 }
Jim Miller0b728242012-10-28 19:42:30 -070078 };
79
80 public KeyguardMessageArea(Context context) {
Lucas Dupin2e838ac2019-04-17 16:50:58 -070081 super(context, null);
82 throw new IllegalStateException("This constructor should never be invoked");
Jim Miller0b728242012-10-28 19:42:30 -070083 }
84
Lucas Dupin2e838ac2019-04-17 16:50:58 -070085 @Inject
86 public KeyguardMessageArea(@Named(VIEW_CONTEXT) Context context, AttributeSet attrs,
87 ConfigurationController configurationController) {
88 this(context, attrs, KeyguardUpdateMonitor.getInstance(context), configurationController);
Adrian Roos154b9ee2016-10-20 15:34:23 -070089 }
90
Lucas Dupin2e838ac2019-04-17 16:50:58 -070091 public KeyguardMessageArea(Context context, AttributeSet attrs, KeyguardUpdateMonitor monitor,
92 ConfigurationController configurationController) {
Jim Miller0b728242012-10-28 19:42:30 -070093 super(context, attrs);
Chris Craik362adb82013-11-05 17:41:21 -080094 setLayerType(LAYER_TYPE_HARDWARE, null); // work around nested unclipped SaveLayer bug
Jim Miller0b728242012-10-28 19:42:30 -070095
Adrian Roos154b9ee2016-10-20 15:34:23 -070096 monitor.registerCallback(mInfoCallback);
Jim Miller0b728242012-10-28 19:42:30 -070097 mHandler = new Handler(Looper.myLooper());
Lucas Dupin2e838ac2019-04-17 16:50:58 -070098 mConfigurationController = configurationController;
Lucas Dupin2e838ac2019-04-17 16:50:58 -070099 onThemeChanged();
Jim Miller0b728242012-10-28 19:42:30 -0700100 }
101
Jim Miller20daffd2013-10-07 14:59:53 -0700102 @Override
Lucas Dupin2e838ac2019-04-17 16:50:58 -0700103 protected void onAttachedToWindow() {
104 super.onAttachedToWindow();
105 mConfigurationController.addCallback(this);
Lucas Dupin12dab902019-04-19 11:10:48 -0700106 onThemeChanged();
Lucas Dupin2e838ac2019-04-17 16:50:58 -0700107 }
108
109 @Override
110 protected void onDetachedFromWindow() {
111 super.onDetachedFromWindow();
112 mConfigurationController.removeCallback(this);
113 }
114
115 @Override
Jason Chang1e4a4bd2018-05-22 17:30:19 +0800116 public void setNextMessageColor(ColorStateList colorState) {
117 mNextMessageColorState = colorState;
Selim Cinekcfafe4e2015-08-11 14:58:44 -0700118 }
119
120 @Override
Lucas Dupin2e838ac2019-04-17 16:50:58 -0700121 public void onThemeChanged() {
122 TypedArray array = mContext.obtainStyledAttributes(new int[] {
123 R.attr.wallpaperTextColor
124 });
125 ColorStateList newTextColors = ColorStateList.valueOf(array.getColor(0, Color.RED));
126 array.recycle();
Lucas Dupin2e838ac2019-04-17 16:50:58 -0700127 mDefaultColorState = newTextColors;
Lucas Dupin12dab902019-04-19 11:10:48 -0700128 update();
Lucas Dupin2e838ac2019-04-17 16:50:58 -0700129 }
130
131 @Override
Lucas Dupin32774922019-04-25 12:42:25 -0700132 public void onDensityOrFontScaleChanged() {
133 TypedArray array = mContext.obtainStyledAttributes(R.style.Keyguard_TextView, new int[] {
134 android.R.attr.textSize
135 });
136 setTextSize(TypedValue.COMPLEX_UNIT_PX, array.getDimensionPixelSize(0, 0));
137 array.recycle();
138 }
139
140 @Override
Adrian Roosdb327e92016-10-12 16:41:28 -0700141 public void setMessage(CharSequence msg) {
142 if (!TextUtils.isEmpty(msg)) {
Adrian Roos28828b52015-05-25 18:48:14 -0700143 securityMessageChanged(msg);
144 } else {
145 clearMessage();
146 }
147 }
148
149 @Override
Adrian Roosdb327e92016-10-12 16:41:28 -0700150 public void setMessage(int resId) {
151 CharSequence message = null;
152 if (resId != 0) {
153 message = getContext().getResources().getText(resId);
Adrian Roos28828b52015-05-25 18:48:14 -0700154 }
Adrian Roosdb327e92016-10-12 16:41:28 -0700155 setMessage(message);
Adrian Roos28828b52015-05-25 18:48:14 -0700156 }
157
158 @Override
Adrian Roosdb327e92016-10-12 16:41:28 -0700159 public void formatMessage(int resId, Object... formatArgs) {
160 CharSequence message = null;
161 if (resId != 0) {
162 message = getContext().getString(resId, formatArgs);
Adrian Roos28828b52015-05-25 18:48:14 -0700163 }
Adrian Roosdb327e92016-10-12 16:41:28 -0700164 setMessage(message);
Adrian Roos28828b52015-05-25 18:48:14 -0700165 }
166
Lucas Dupin2e838ac2019-04-17 16:50:58 -0700167 public static KeyguardMessageArea findSecurityMessageDisplay(View v) {
168 KeyguardMessageArea messageArea = v.findViewById(R.id.keyguard_message_area);
169 if (messageArea == null) {
170 messageArea = v.getRootView().findViewById(R.id.keyguard_message_area);
171 }
Adrian Roos28828b52015-05-25 18:48:14 -0700172 if (messageArea == null) {
173 throw new RuntimeException("Can't find keyguard_message_area in " + v.getClass());
174 }
175 return messageArea;
176 }
177
178 @Override
Jim Miller20daffd2013-10-07 14:59:53 -0700179 protected void onFinishInflate() {
Jorim Jaggi0d210f62015-07-10 14:24:44 -0700180 boolean shouldMarquee = KeyguardUpdateMonitor.getInstance(mContext).isDeviceInteractive();
181 setSelected(shouldMarquee); // This is required to ensure marquee works
Jim Miller20daffd2013-10-07 14:59:53 -0700182 }
183
Adrian Roos28828b52015-05-25 18:48:14 -0700184 private void securityMessageChanged(CharSequence message) {
185 mMessage = message;
Jim Miller0b728242012-10-28 19:42:30 -0700186 update();
Alan Viveretteb428b0f2013-02-07 12:19:15 -0800187 mHandler.removeCallbacksAndMessages(ANNOUNCE_TOKEN);
188 mHandler.postAtTime(new AnnounceRunnable(this, getText()), ANNOUNCE_TOKEN,
189 (SystemClock.uptimeMillis() + ANNOUNCEMENT_DELAY));
Jim Miller0b728242012-10-28 19:42:30 -0700190 }
191
Adrian Roos28828b52015-05-25 18:48:14 -0700192 private void clearMessage() {
Adrian Roos154b9ee2016-10-20 15:34:23 -0700193 mMessage = null;
194 update();
Xiyuan Xia09eb0332015-05-13 15:29:42 -0700195 }
196
Adrian Roos28828b52015-05-25 18:48:14 -0700197 private void update() {
198 CharSequence status = mMessage;
Lucas Dupin473f3a52019-04-30 15:33:28 -0700199 setVisibility(TextUtils.isEmpty(status) || !mBouncerVisible ? INVISIBLE : VISIBLE);
Jim Miller0b728242012-10-28 19:42:30 -0700200 setText(status);
Jason Chang1e4a4bd2018-05-22 17:30:19 +0800201 ColorStateList colorState = mDefaultColorState;
202 if (mNextMessageColorState.getDefaultColor() != DEFAULT_COLOR) {
203 colorState = mNextMessageColorState;
204 mNextMessageColorState = ColorStateList.valueOf(DEFAULT_COLOR);
Selim Cinekcfafe4e2015-08-11 14:58:44 -0700205 }
Jason Chang1e4a4bd2018-05-22 17:30:19 +0800206 setTextColor(colorState);
Jim Miller0b728242012-10-28 19:42:30 -0700207 }
208
Jim Miller0b728242012-10-28 19:42:30 -0700209
Alan Viveretteb428b0f2013-02-07 12:19:15 -0800210 /**
211 * Runnable used to delay accessibility announcements.
212 */
213 private static class AnnounceRunnable implements Runnable {
214 private final WeakReference<View> mHost;
215 private final CharSequence mTextToAnnounce;
216
Adrian Roos28828b52015-05-25 18:48:14 -0700217 AnnounceRunnable(View host, CharSequence textToAnnounce) {
Alan Viveretteb428b0f2013-02-07 12:19:15 -0800218 mHost = new WeakReference<View>(host);
219 mTextToAnnounce = textToAnnounce;
220 }
221
222 @Override
223 public void run() {
224 final View host = mHost.get();
225 if (host != null) {
226 host.announceForAccessibility(mTextToAnnounce);
227 }
228 }
229 }
Jim Miller0b728242012-10-28 19:42:30 -0700230}