blob: df0dc467f87e72cbb19d4b5fdd63e21c5c7e33d4 [file] [log] [blame]
Kunhung Li29007e62018-07-30 19:30:25 +08001package com.android.keyguard;
2
Robert Snoebergerbe35b762019-03-15 14:33:02 -04003import static com.android.systemui.util.InjectionInflationController.VIEW_CONTEXT;
4
Lucas Dupine570af62019-02-10 14:52:30 -08005import android.animation.Animator;
Lucas Dupine570af62019-02-10 14:52:30 -08006import android.animation.ValueAnimator;
Robert Snoeberger0397c842019-02-07 14:25:46 -05007import android.app.WallpaperManager;
Kunhung Li29007e62018-07-30 19:30:25 +08008import android.content.Context;
9import android.graphics.Paint;
10import android.graphics.Paint.Style;
Lucas Dupinf69aa772019-04-26 11:05:23 -070011import android.os.Build;
Robert Snoeberger146ab3c2019-06-13 14:12:10 -040012import android.transition.Fade;
Lucas Dupine570af62019-02-10 14:52:30 -080013import android.transition.Transition;
Robert Snoebergerf9030c72019-04-22 16:22:49 -040014import android.transition.TransitionListenerAdapter;
Lucas Dupine570af62019-02-10 14:52:30 -080015import android.transition.TransitionManager;
Robert Snoeberger7cfa9dd2019-05-06 17:41:36 -040016import android.transition.TransitionSet;
Lucas Dupine570af62019-02-10 14:52:30 -080017import android.transition.TransitionValues;
Kunhung Li29007e62018-07-30 19:30:25 +080018import android.util.AttributeSet;
Lucas Dupinf69aa772019-04-26 11:05:23 -070019import android.util.Log;
Lucas Dupine570af62019-02-10 14:52:30 -080020import android.util.MathUtils;
Kunhung Li29007e62018-07-30 19:30:25 +080021import android.view.View;
22import android.view.ViewGroup;
23import android.widget.FrameLayout;
Robert Snoebergere3b3e782018-12-17 13:32:15 -050024import android.widget.RelativeLayout;
Kunhung Li29007e62018-07-30 19:30:25 +080025import android.widget.TextClock;
26
27import androidx.annotation.VisibleForTesting;
28
Robert Snoeberger0397c842019-02-07 14:25:46 -050029import com.android.internal.colorextraction.ColorExtractor;
Robert Snoebergerbe35b762019-03-15 14:33:02 -040030import com.android.internal.colorextraction.ColorExtractor.OnColorsChangedListener;
Robert Snoeberger15b4af12019-01-18 15:37:27 -050031import com.android.keyguard.clock.ClockManager;
Lucas Dupine570af62019-02-10 14:52:30 -080032import com.android.systemui.Interpolators;
Sunny Goyal87fccf02019-08-13 17:39:10 -070033import com.android.systemui.R;
Robert Snoeberger0397c842019-02-07 14:25:46 -050034import com.android.systemui.colorextraction.SysuiColorExtractor;
Kunhung Li29007e62018-07-30 19:30:25 +080035import com.android.systemui.plugins.ClockPlugin;
Beverly8fdb5332019-02-04 14:29:49 -050036import com.android.systemui.plugins.statusbar.StatusBarStateController;
Robert Snoeberger60854082019-01-04 13:13:17 -050037import com.android.systemui.statusbar.StatusBarState;
Robert Snoeberger33259ad2019-06-19 14:55:49 -040038import com.android.systemui.util.wakelock.KeepAwakeAnimationListener;
Kunhung Li29007e62018-07-30 19:30:25 +080039
Lucas Dupin43499522019-03-04 16:45:58 -080040import java.io.FileDescriptor;
41import java.io.PrintWriter;
42import java.util.Arrays;
Robert Snoeberger9c1074f2018-12-07 17:35:21 -050043import java.util.TimeZone;
Robert Snoeberger33ce6d92018-10-26 10:52:38 -040044
Robert Snoebergerbe35b762019-03-15 14:33:02 -040045import javax.inject.Inject;
46import javax.inject.Named;
47
Kunhung Li29007e62018-07-30 19:30:25 +080048/**
49 * Switch to show plugin clock when plugin is connected, otherwise it will show default clock.
50 */
Robert Snoebergere3b3e782018-12-17 13:32:15 -050051public class KeyguardClockSwitch extends RelativeLayout {
Robert Snoeberger046ee9c2019-01-10 18:29:38 -050052
Lucas Dupinf69aa772019-04-26 11:05:23 -070053 private static final String TAG = "KeyguardClockSwitch";
Robert Snoeberger61f04732019-06-27 10:31:09 -040054 private static final boolean CUSTOM_CLOCKS_ENABLED = false;
Lucas Dupinf69aa772019-04-26 11:05:23 -070055
Robert Snoebergerbe35b762019-03-15 14:33:02 -040056 /**
Robert Snoeberger7cfa9dd2019-05-06 17:41:36 -040057 * Animation fraction when text is transitioned to/from bold.
58 */
59 private static final float TO_BOLD_TRANSITION_FRACTION = 0.7f;
60
61 /**
Robert Snoebergerbe35b762019-03-15 14:33:02 -040062 * Controller used to track StatusBar state to know when to show the big_clock_container.
63 */
64 private final StatusBarStateController mStatusBarStateController;
65
66 /**
67 * Color extractor used to apply colors from wallpaper to custom clock faces.
68 */
69 private final SysuiColorExtractor mSysuiColorExtractor;
70
71 /**
72 * Manager used to know when to show a custom clock face.
73 */
74 private final ClockManager mClockManager;
75
76 /**
77 * Layout transition that scales the default clock face.
78 */
Lucas Dupine570af62019-02-10 14:52:30 -080079 private final Transition mTransition;
Robert Snoebergerbe35b762019-03-15 14:33:02 -040080
Robert Snoeberger7cfa9dd2019-05-06 17:41:36 -040081 private final ClockVisibilityTransition mClockTransition;
82 private final ClockVisibilityTransition mBoldClockTransition;
Robert Snoebergerf9030c72019-04-22 16:22:49 -040083
84 /**
Kunhung Li29007e62018-07-30 19:30:25 +080085 * Optional/alternative clock injected via plugin.
86 */
87 private ClockPlugin mClockPlugin;
Robert Snoebergerbe35b762019-03-15 14:33:02 -040088
Kunhung Li29007e62018-07-30 19:30:25 +080089 /**
90 * Default clock.
91 */
92 private TextClock mClockView;
Robert Snoebergerbe35b762019-03-15 14:33:02 -040093
Robert Snoebergere3b3e782018-12-17 13:32:15 -050094 /**
Robert Snoebergerf9030c72019-04-22 16:22:49 -040095 * Default clock, bold version.
96 * Used to transition to bold when shrinking the default clock.
97 */
98 private TextClock mClockViewBold;
99
100 /**
Robert Snoebergere3b3e782018-12-17 13:32:15 -0500101 * Frame for default and custom clock.
102 */
Robert Snoeberger6a0140a2018-12-20 12:46:17 -0500103 private FrameLayout mSmallClockFrame;
Robert Snoebergerbe35b762019-03-15 14:33:02 -0400104
Robert Snoeberger6a0140a2018-12-20 12:46:17 -0500105 /**
106 * Container for big custom clock.
107 */
108 private ViewGroup mBigClockContainer;
Robert Snoebergerbe35b762019-03-15 14:33:02 -0400109
Robert Snoebergere3b3e782018-12-17 13:32:15 -0500110 /**
Robert Snoeberger98312392019-03-15 16:53:51 -0400111 * Status area (date and other stuff) shown below the clock. Plugin can decide whether or not to
112 * show it below the alternate clock.
Robert Snoebergere3b3e782018-12-17 13:32:15 -0500113 */
114 private View mKeyguardStatusArea;
Robert Snoebergerbe35b762019-03-15 14:33:02 -0400115
Robert Snoeberger8bf1a3c2019-01-10 10:30:09 -0500116 /**
Robert Snoeberger58f23152019-01-10 15:51:32 -0500117 * Maintain state so that a newly connected plugin can be initialized.
118 */
119 private float mDarkAmount;
Robert Snoebergerbe35b762019-03-15 14:33:02 -0400120
Lucas Dupine570af62019-02-10 14:52:30 -0800121 /**
Robert Snoeberger146ab3c2019-06-13 14:12:10 -0400122 * Boolean value indicating if notifications are visible on lock screen.
123 */
124 private boolean mHasVisibleNotifications;
125
126 /**
Lucas Dupine570af62019-02-10 14:52:30 -0800127 * If the Keyguard Slice has a header (big center-aligned text.)
128 */
129 private boolean mShowingHeader;
Robert Snoeberger0397c842019-02-07 14:25:46 -0500130 private boolean mSupportsDarkText;
131 private int[] mColorPalette;
Kunhung Li29007e62018-07-30 19:30:25 +0800132
Robert Snoeberger98312392019-03-15 16:53:51 -0400133 /**
134 * Track the state of the status bar to know when to hide the big_clock_container.
135 */
136 private int mStatusBarState;
137
Robert Snoeberger60854082019-01-04 13:13:17 -0500138 private final StatusBarStateController.StateListener mStateListener =
139 new StatusBarStateController.StateListener() {
140 @Override
141 public void onStateChanged(int newState) {
Robert Snoeberger98312392019-03-15 16:53:51 -0400142 mStatusBarState = newState;
143 updateBigClockVisibility();
Robert Snoeberger60854082019-01-04 13:13:17 -0500144 }
Robert Snoeberger98312392019-03-15 16:53:51 -0400145 };
Kunhung Li29007e62018-07-30 19:30:25 +0800146
Robert Snoeberger15b4af12019-01-18 15:37:27 -0500147 private ClockManager.ClockChangedListener mClockChangedListener = this::setClockPlugin;
Robert Snoeberger046ee9c2019-01-10 18:29:38 -0500148
Robert Snoeberger0397c842019-02-07 14:25:46 -0500149 /**
150 * Listener for changes to the color palette.
151 *
152 * The color palette changes when the wallpaper is changed.
153 */
Robert Snoebergerbe35b762019-03-15 14:33:02 -0400154 private final OnColorsChangedListener mColorsListener = (extractor, which) -> {
Robert Snoeberger0397c842019-02-07 14:25:46 -0500155 if ((which & WallpaperManager.FLAG_LOCK) != 0) {
Robert Snoebergerbe35b762019-03-15 14:33:02 -0400156 updateColors();
Robert Snoeberger0397c842019-02-07 14:25:46 -0500157 }
158 };
159
Robert Snoebergerbe35b762019-03-15 14:33:02 -0400160 @Inject
161 public KeyguardClockSwitch(@Named(VIEW_CONTEXT) Context context, AttributeSet attrs,
162 StatusBarStateController statusBarStateController, SysuiColorExtractor colorExtractor,
163 ClockManager clockManager) {
Kunhung Li29007e62018-07-30 19:30:25 +0800164 super(context, attrs);
Robert Snoebergerbe35b762019-03-15 14:33:02 -0400165 mStatusBarStateController = statusBarStateController;
Robert Snoeberger372e13f2019-04-08 17:07:14 -0400166 mStatusBarState = mStatusBarStateController.getState();
Robert Snoebergerbe35b762019-03-15 14:33:02 -0400167 mSysuiColorExtractor = colorExtractor;
168 mClockManager = clockManager;
Robert Snoeberger7cfa9dd2019-05-06 17:41:36 -0400169
170 mClockTransition = new ClockVisibilityTransition().setCutoff(
171 1 - TO_BOLD_TRANSITION_FRACTION);
172 mClockTransition.addTarget(R.id.default_clock_view);
173 mBoldClockTransition = new ClockVisibilityTransition().setCutoff(
174 TO_BOLD_TRANSITION_FRACTION);
175 mBoldClockTransition.addTarget(R.id.default_clock_view_bold);
176 mTransition = new TransitionSet()
177 .setOrdering(TransitionSet.ORDERING_TOGETHER)
178 .addTransition(mClockTransition)
179 .addTransition(mBoldClockTransition)
180 .setDuration(KeyguardSliceView.DEFAULT_ANIM_DURATION / 2)
181 .setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN);
Kunhung Li29007e62018-07-30 19:30:25 +0800182 }
183
Lucas Dupin7fc9dc12019-01-03 09:19:43 -0800184 /**
185 * Returns if this view is presenting a custom clock, or the default implementation.
186 */
187 public boolean hasCustomClock() {
188 return mClockPlugin != null;
189 }
190
Kunhung Li29007e62018-07-30 19:30:25 +0800191 @Override
192 protected void onFinishInflate() {
193 super.onFinishInflate();
194 mClockView = findViewById(R.id.default_clock_view);
Robert Snoebergerf9030c72019-04-22 16:22:49 -0400195 mClockViewBold = findViewById(R.id.default_clock_view_bold);
Robert Snoeberger6a0140a2018-12-20 12:46:17 -0500196 mSmallClockFrame = findViewById(R.id.clock_view);
Robert Snoebergere3b3e782018-12-17 13:32:15 -0500197 mKeyguardStatusArea = findViewById(R.id.keyguard_status_area);
Kunhung Li29007e62018-07-30 19:30:25 +0800198 }
199
200 @Override
201 protected void onAttachedToWindow() {
202 super.onAttachedToWindow();
Robert Snoeberger61f04732019-06-27 10:31:09 -0400203 if (CUSTOM_CLOCKS_ENABLED) {
204 mClockManager.addOnClockChangedListener(mClockChangedListener);
205 }
Robert Snoebergerbe35b762019-03-15 14:33:02 -0400206 mStatusBarStateController.addCallback(mStateListener);
207 mSysuiColorExtractor.addOnColorsChangedListener(mColorsListener);
208 updateColors();
Kunhung Li29007e62018-07-30 19:30:25 +0800209 }
210
211 @Override
212 protected void onDetachedFromWindow() {
213 super.onDetachedFromWindow();
Robert Snoeberger61f04732019-06-27 10:31:09 -0400214 if (CUSTOM_CLOCKS_ENABLED) {
215 mClockManager.removeOnClockChangedListener(mClockChangedListener);
216 }
Robert Snoebergerbe35b762019-03-15 14:33:02 -0400217 mStatusBarStateController.removeCallback(mStateListener);
218 mSysuiColorExtractor.removeOnColorsChangedListener(mColorsListener);
Robert Snoebergerd7470252019-03-04 16:05:36 -0500219 setClockPlugin(null);
Kunhung Li29007e62018-07-30 19:30:25 +0800220 }
221
Robert Snoeberger8bf1a3c2019-01-10 10:30:09 -0500222 private void setClockPlugin(ClockPlugin plugin) {
223 // Disconnect from existing plugin.
224 if (mClockPlugin != null) {
225 View smallClockView = mClockPlugin.getView();
226 if (smallClockView != null && smallClockView.getParent() == mSmallClockFrame) {
227 mSmallClockFrame.removeView(smallClockView);
228 }
229 if (mBigClockContainer != null) {
230 mBigClockContainer.removeAllViews();
Robert Snoeberger98312392019-03-15 16:53:51 -0400231 updateBigClockVisibility();
Robert Snoeberger8bf1a3c2019-01-10 10:30:09 -0500232 }
Robert Snoeberger3358cfb2019-04-03 13:09:55 -0400233 mClockPlugin.onDestroyView();
Robert Snoeberger8bf1a3c2019-01-10 10:30:09 -0500234 mClockPlugin = null;
235 }
236 if (plugin == null) {
Robert Snoebergerf65513a2019-06-20 10:40:13 -0400237 if (mShowingHeader) {
238 mClockView.setVisibility(View.GONE);
239 mClockViewBold.setVisibility(View.VISIBLE);
240 } else {
241 mClockView.setVisibility(View.VISIBLE);
242 mClockViewBold.setVisibility(View.INVISIBLE);
243 }
Robert Snoeberger8bf1a3c2019-01-10 10:30:09 -0500244 mKeyguardStatusArea.setVisibility(View.VISIBLE);
245 return;
246 }
247 // Attach small and big clock views to hierarchy.
248 View smallClockView = plugin.getView();
249 if (smallClockView != null) {
250 mSmallClockFrame.addView(smallClockView, -1,
251 new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
252 ViewGroup.LayoutParams.WRAP_CONTENT));
253 mClockView.setVisibility(View.GONE);
Robert Snoebergerf9030c72019-04-22 16:22:49 -0400254 mClockViewBold.setVisibility(View.GONE);
Robert Snoeberger8bf1a3c2019-01-10 10:30:09 -0500255 }
256 View bigClockView = plugin.getBigClockView();
257 if (bigClockView != null && mBigClockContainer != null) {
258 mBigClockContainer.addView(bigClockView);
Robert Snoeberger98312392019-03-15 16:53:51 -0400259 updateBigClockVisibility();
Robert Snoeberger8bf1a3c2019-01-10 10:30:09 -0500260 }
261 // Hide default clock.
262 if (!plugin.shouldShowStatusArea()) {
263 mKeyguardStatusArea.setVisibility(View.GONE);
264 }
265 // Initialize plugin parameters.
266 mClockPlugin = plugin;
267 mClockPlugin.setStyle(getPaint().getStyle());
268 mClockPlugin.setTextColor(getCurrentTextColor());
Robert Snoeberger58f23152019-01-10 15:51:32 -0500269 mClockPlugin.setDarkAmount(mDarkAmount);
Robert Snoeberger0397c842019-02-07 14:25:46 -0500270 if (mColorPalette != null) {
271 mClockPlugin.setColorPalette(mSupportsDarkText, mColorPalette);
272 }
Robert Snoeberger8bf1a3c2019-01-10 10:30:09 -0500273 }
274
Kunhung Li29007e62018-07-30 19:30:25 +0800275 /**
Robert Snoeberger6a0140a2018-12-20 12:46:17 -0500276 * Set container for big clock face appearing behind NSSL and KeyguardStatusView.
277 */
278 public void setBigClockContainer(ViewGroup container) {
279 if (mClockPlugin != null && container != null) {
280 View bigClockView = mClockPlugin.getBigClockView();
281 if (bigClockView != null) {
282 container.addView(bigClockView);
Robert Snoeberger6a0140a2018-12-20 12:46:17 -0500283 }
284 }
285 mBigClockContainer = container;
Robert Snoeberger98312392019-03-15 16:53:51 -0400286 updateBigClockVisibility();
Robert Snoeberger6a0140a2018-12-20 12:46:17 -0500287 }
288
289 /**
Kunhung Li29007e62018-07-30 19:30:25 +0800290 * It will also update plugin setStyle if plugin is connected.
291 */
292 public void setStyle(Style style) {
293 mClockView.getPaint().setStyle(style);
Robert Snoebergerf9030c72019-04-22 16:22:49 -0400294 mClockViewBold.getPaint().setStyle(style);
Kunhung Li29007e62018-07-30 19:30:25 +0800295 if (mClockPlugin != null) {
296 mClockPlugin.setStyle(style);
297 }
298 }
299
300 /**
301 * It will also update plugin setTextColor if plugin is connected.
302 */
303 public void setTextColor(int color) {
304 mClockView.setTextColor(color);
Robert Snoebergerf9030c72019-04-22 16:22:49 -0400305 mClockViewBold.setTextColor(color);
Kunhung Li29007e62018-07-30 19:30:25 +0800306 if (mClockPlugin != null) {
307 mClockPlugin.setTextColor(color);
308 }
309 }
310
311 public void setShowCurrentUserTime(boolean showCurrentUserTime) {
312 mClockView.setShowCurrentUserTime(showCurrentUserTime);
Robert Snoebergerf9030c72019-04-22 16:22:49 -0400313 mClockViewBold.setShowCurrentUserTime(showCurrentUserTime);
Kunhung Li29007e62018-07-30 19:30:25 +0800314 }
315
Kunhung Li29007e62018-07-30 19:30:25 +0800316 public void setTextSize(int unit, float size) {
317 mClockView.setTextSize(unit, size);
318 }
319
320 public void setFormat12Hour(CharSequence format) {
321 mClockView.setFormat12Hour(format);
Robert Snoebergerf9030c72019-04-22 16:22:49 -0400322 mClockViewBold.setFormat12Hour(format);
Kunhung Li29007e62018-07-30 19:30:25 +0800323 }
324
325 public void setFormat24Hour(CharSequence format) {
326 mClockView.setFormat24Hour(format);
Robert Snoebergerf9030c72019-04-22 16:22:49 -0400327 mClockViewBold.setFormat24Hour(format);
Kunhung Li29007e62018-07-30 19:30:25 +0800328 }
329
Robert Snoebergere32efd72018-11-12 08:38:34 -0500330 /**
331 * Set the amount (ratio) that the device has transitioned to doze.
Robert Snoeberger98312392019-03-15 16:53:51 -0400332 *
Robert Snoebergere32efd72018-11-12 08:38:34 -0500333 * @param darkAmount Amount of transition to doze: 1f for doze and 0f for awake.
334 */
335 public void setDarkAmount(float darkAmount) {
Robert Snoeberger58f23152019-01-10 15:51:32 -0500336 mDarkAmount = darkAmount;
Robert Snoebergere32efd72018-11-12 08:38:34 -0500337 if (mClockPlugin != null) {
338 mClockPlugin.setDarkAmount(darkAmount);
339 }
Robert Snoeberger146ab3c2019-06-13 14:12:10 -0400340 updateBigClockAlpha();
341 }
342
343 /**
344 * Set whether or not the lock screen is showing notifications.
345 */
346 void setHasVisibleNotifications(boolean hasVisibleNotifications) {
347 if (hasVisibleNotifications == mHasVisibleNotifications) {
348 return;
349 }
350 mHasVisibleNotifications = hasVisibleNotifications;
351 if (mDarkAmount == 0f && mBigClockContainer != null) {
352 // Starting a fade transition since the visibility of the big clock will change.
353 TransitionManager.beginDelayedTransition(mBigClockContainer,
354 new Fade().setDuration(KeyguardSliceView.DEFAULT_ANIM_DURATION / 2).addTarget(
355 mBigClockContainer));
356 }
357 updateBigClockAlpha();
Robert Snoebergere32efd72018-11-12 08:38:34 -0500358 }
359
Kunhung Li29007e62018-07-30 19:30:25 +0800360 public Paint getPaint() {
361 return mClockView.getPaint();
362 }
363
364 public int getCurrentTextColor() {
365 return mClockView.getCurrentTextColor();
366 }
367
368 public float getTextSize() {
369 return mClockView.getTextSize();
370 }
371
Robert Snoebergerae926732019-03-21 11:40:16 -0400372 /**
Robert Snoeberger69956802019-04-16 16:55:21 -0400373 * Returns the preferred Y position of the clock.
374 *
375 * @param totalHeight Height of the parent container.
376 * @return preferred Y position.
377 */
378 int getPreferredY(int totalHeight) {
379 if (mClockPlugin != null) {
380 return mClockPlugin.getPreferredY(totalHeight);
381 } else {
382 return totalHeight / 2;
383 }
384 }
385
386 /**
Robert Snoebergerae926732019-03-21 11:40:16 -0400387 * Refresh the time of the clock, due to either time tick broadcast or doze time tick alarm.
388 */
Kunhung Li29007e62018-07-30 19:30:25 +0800389 public void refresh() {
390 mClockView.refresh();
Robert Snoebergerf9030c72019-04-22 16:22:49 -0400391 mClockViewBold.refresh();
Robert Snoebergerffbe3152018-11-08 15:53:27 -0500392 if (mClockPlugin != null) {
Robert Snoeberger9ad03f42019-02-28 14:47:49 -0500393 mClockPlugin.onTimeTick();
Robert Snoebergerffbe3152018-11-08 15:53:27 -0500394 }
Lucas Dupinf69aa772019-04-26 11:05:23 -0700395 if (Build.IS_DEBUGGABLE) {
396 // Log for debugging b/130888082 (sysui waking up, but clock not updating)
397 Log.d(TAG, "Updating clock: " + mClockView.getText());
398 }
Robert Snoebergerffbe3152018-11-08 15:53:27 -0500399 }
400
401 /**
Robert Snoeberger9c1074f2018-12-07 17:35:21 -0500402 * Notifies that the time zone has changed.
403 */
404 public void onTimeZoneChanged(TimeZone timeZone) {
405 if (mClockPlugin != null) {
406 mClockPlugin.onTimeZoneChanged(timeZone);
407 }
408 }
409
Robert Snoebergerbe35b762019-03-15 14:33:02 -0400410 private void updateColors() {
411 ColorExtractor.GradientColors colors = mSysuiColorExtractor.getColors(
Lucas Dupin89233c42019-06-10 18:00:22 -0700412 WallpaperManager.FLAG_LOCK);
Robert Snoeberger0397c842019-02-07 14:25:46 -0500413 mSupportsDarkText = colors.supportsDarkText();
414 mColorPalette = colors.getColorPalette();
415 if (mClockPlugin != null) {
416 mClockPlugin.setColorPalette(mSupportsDarkText, mColorPalette);
417 }
418 }
419
Robert Snoeberger98312392019-03-15 16:53:51 -0400420 private void updateBigClockVisibility() {
421 if (mBigClockContainer == null) {
422 return;
423 }
424 final boolean inDisplayState = mStatusBarState == StatusBarState.KEYGUARD
425 || mStatusBarState == StatusBarState.SHADE_LOCKED;
426 final int visibility =
427 inDisplayState && mBigClockContainer.getChildCount() != 0 ? View.VISIBLE
428 : View.GONE;
429 if (mBigClockContainer.getVisibility() != visibility) {
430 mBigClockContainer.setVisibility(visibility);
431 }
432 }
433
Robert Snoeberger146ab3c2019-06-13 14:12:10 -0400434 private void updateBigClockAlpha() {
435 if (mBigClockContainer != null) {
436 final float alpha = mHasVisibleNotifications ? mDarkAmount : 1f;
437 mBigClockContainer.setAlpha(alpha);
438 if (alpha == 0f) {
439 mBigClockContainer.setVisibility(INVISIBLE);
440 } else if (mBigClockContainer.getVisibility() == INVISIBLE) {
441 mBigClockContainer.setVisibility(VISIBLE);
442 }
443 }
444 }
445
Lucas Dupine570af62019-02-10 14:52:30 -0800446 /**
Robert Snoeberger98312392019-03-15 16:53:51 -0400447 * Sets if the keyguard slice is showing a center-aligned header. We need a smaller clock in
Robert Snoebergerf9030c72019-04-22 16:22:49 -0400448 * these cases.
Lucas Dupine570af62019-02-10 14:52:30 -0800449 */
Robert Snoeberger7cfa9dd2019-05-06 17:41:36 -0400450 void setKeyguardShowingHeader(boolean hasHeader) {
Robert Snoebergerf65513a2019-06-20 10:40:13 -0400451 if (mShowingHeader == hasHeader) {
Lucas Dupine570af62019-02-10 14:52:30 -0800452 return;
453 }
454 mShowingHeader = hasHeader;
Robert Snoebergerf65513a2019-06-20 10:40:13 -0400455 if (hasCustomClock()) {
456 return;
457 }
Lucas Dupine570af62019-02-10 14:52:30 -0800458
Robert Snoeberger7cfa9dd2019-05-06 17:41:36 -0400459 float smallFontSize = mContext.getResources().getDimensionPixelSize(
460 R.dimen.widget_small_font_size);
461 float bigFontSize = mContext.getResources().getDimensionPixelSize(
462 R.dimen.widget_big_font_size);
463 mClockTransition.setScale(smallFontSize / bigFontSize);
464 mBoldClockTransition.setScale(bigFontSize / smallFontSize);
465
Robert Snoebergerb66e9822019-05-16 11:14:43 -0400466 // End any current transitions before starting a new transition so that the new transition
467 // starts from a good state instead of a potentially bad intermediate state arrived at
468 // during a transition animation.
469 TransitionManager.endTransitions((ViewGroup) mClockView.getParent());
Robert Snoeberger7cfa9dd2019-05-06 17:41:36 -0400470
471 if (hasHeader) {
472 // After the transition, make the default clock GONE so that it doesn't make the
473 // KeyguardStatusView appear taller in KeyguardClockPositionAlgorithm and elsewhere.
474 mTransition.addListener(new TransitionListenerAdapter() {
475 @Override
476 public void onTransitionEnd(Transition transition) {
477 super.onTransitionEnd(transition);
478 // Check that header is actually showing. I saw issues where this event was
479 // fired after the big clock transitioned back to visible, which causes the time
480 // to completely disappear.
481 if (mShowingHeader) {
482 mClockView.setVisibility(View.GONE);
483 }
484 transition.removeListener(this);
485 }
486 });
487 }
Robert Snoebergerb66e9822019-05-16 11:14:43 -0400488
489 TransitionManager.beginDelayedTransition((ViewGroup) mClockView.getParent(), mTransition);
490 mClockView.setVisibility(hasHeader ? View.INVISIBLE : View.VISIBLE);
491 mClockViewBold.setVisibility(hasHeader ? View.VISIBLE : View.INVISIBLE);
492 int paddingBottom = mContext.getResources().getDimensionPixelSize(hasHeader
493 ? R.dimen.widget_vertical_padding_clock : R.dimen.title_clock_padding);
494 mClockView.setPadding(mClockView.getPaddingLeft(), mClockView.getPaddingTop(),
495 mClockView.getPaddingRight(), paddingBottom);
496 mClockViewBold.setPadding(mClockViewBold.getPaddingLeft(), mClockViewBold.getPaddingTop(),
497 mClockViewBold.getPaddingRight(), paddingBottom);
Lucas Dupine570af62019-02-10 14:52:30 -0800498 }
499
Robert Snoeberger98312392019-03-15 16:53:51 -0400500 @VisibleForTesting(otherwise = VisibleForTesting.NONE)
Robert Snoeberger15b4af12019-01-18 15:37:27 -0500501 ClockManager.ClockChangedListener getClockChangedListener() {
502 return mClockChangedListener;
Kunhung Li29007e62018-07-30 19:30:25 +0800503 }
Robert Snoeberger60854082019-01-04 13:13:17 -0500504
Robert Snoeberger98312392019-03-15 16:53:51 -0400505 @VisibleForTesting(otherwise = VisibleForTesting.NONE)
Robert Snoeberger60854082019-01-04 13:13:17 -0500506 StatusBarStateController.StateListener getStateListener() {
507 return mStateListener;
508 }
Lucas Dupine570af62019-02-10 14:52:30 -0800509
Lucas Dupin43499522019-03-04 16:45:58 -0800510 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
511 pw.println("KeyguardClockSwitch:");
512 pw.println(" mClockPlugin: " + mClockPlugin);
513 pw.println(" mClockView: " + mClockView);
Robert Snoebergerf9030c72019-04-22 16:22:49 -0400514 pw.println(" mClockViewBold: " + mClockViewBold);
Lucas Dupin43499522019-03-04 16:45:58 -0800515 pw.println(" mSmallClockFrame: " + mSmallClockFrame);
516 pw.println(" mBigClockContainer: " + mBigClockContainer);
517 pw.println(" mKeyguardStatusArea: " + mKeyguardStatusArea);
518 pw.println(" mDarkAmount: " + mDarkAmount);
519 pw.println(" mShowingHeader: " + mShowingHeader);
520 pw.println(" mSupportsDarkText: " + mSupportsDarkText);
521 pw.println(" mColorPalette: " + Arrays.toString(mColorPalette));
522 }
523
Lucas Dupine570af62019-02-10 14:52:30 -0800524 /**
Robert Snoeberger7cfa9dd2019-05-06 17:41:36 -0400525 * {@link Visibility} transformation that scales the view while it is disappearing/appearing and
526 * transitions suddenly at a cutoff fraction during the animation.
Lucas Dupine570af62019-02-10 14:52:30 -0800527 */
Robert Snoeberger7cfa9dd2019-05-06 17:41:36 -0400528 private class ClockVisibilityTransition extends android.transition.Visibility {
529
530 private static final String PROPNAME_VISIBILITY = "systemui:keyguard:visibility";
531
532 private float mCutoff;
533 private float mScale;
Lucas Dupine570af62019-02-10 14:52:30 -0800534
Robert Snoebergerf9030c72019-04-22 16:22:49 -0400535 /**
Robert Snoeberger7cfa9dd2019-05-06 17:41:36 -0400536 * Constructs a transition that switches between visible/invisible at a cutoff and scales in
537 * size while appearing/disappearing.
Robert Snoebergerf9030c72019-04-22 16:22:49 -0400538 */
Robert Snoeberger7cfa9dd2019-05-06 17:41:36 -0400539 ClockVisibilityTransition() {
540 setCutoff(1f);
541 setScale(1f);
542 }
Robert Snoebergerf9030c72019-04-22 16:22:49 -0400543
Robert Snoeberger7cfa9dd2019-05-06 17:41:36 -0400544 /**
545 * Sets the transition point between visible/invisible.
546 *
547 * @param cutoff The fraction in [0, 1] when the view switches between visible/invisible.
548 * @return This transition object
549 */
550 public ClockVisibilityTransition setCutoff(float cutoff) {
551 mCutoff = cutoff;
552 return this;
553 }
554
555 /**
556 * Sets the scale factor applied while appearing/disappearing.
557 *
558 * @param scale Scale factor applied while appearing/disappearing. When factor is less than
559 * one, the view will shrink while disappearing. When it is greater than one,
560 * the view will expand while disappearing.
561 * @return This transition object
562 */
563 public ClockVisibilityTransition setScale(float scale) {
564 mScale = scale;
565 return this;
Lucas Dupine570af62019-02-10 14:52:30 -0800566 }
567
568 @Override
Robert Snoeberger7cfa9dd2019-05-06 17:41:36 -0400569 public void captureStartValues(TransitionValues transitionValues) {
570 super.captureStartValues(transitionValues);
571 captureVisibility(transitionValues);
572 }
573
574 @Override
575 public void captureEndValues(TransitionValues transitionValues) {
576 super.captureStartValues(transitionValues);
577 captureVisibility(transitionValues);
578 }
579
580 private void captureVisibility(TransitionValues transitionValues) {
581 transitionValues.values.put(PROPNAME_VISIBILITY,
582 transitionValues.view.getVisibility());
583 }
584
585 @Override
586 public Animator onAppear(ViewGroup sceneRoot, View view, TransitionValues startValues,
Lucas Dupine570af62019-02-10 14:52:30 -0800587 TransitionValues endValues) {
Robert Snoebergerdc8fee72019-07-19 16:35:35 -0400588 if (!sceneRoot.isShown()) {
589 return null;
590 }
Robert Snoeberger7cfa9dd2019-05-06 17:41:36 -0400591 final float cutoff = mCutoff;
592 final int startVisibility = View.INVISIBLE;
593 final int endVisibility = (int) endValues.values.get(PROPNAME_VISIBILITY);
594 final float startScale = mScale;
595 final float endScale = 1f;
596 return createAnimator(view, cutoff, startVisibility, endVisibility, startScale,
597 endScale);
598 }
Lucas Dupine570af62019-02-10 14:52:30 -0800599
Robert Snoeberger7cfa9dd2019-05-06 17:41:36 -0400600 @Override
601 public Animator onDisappear(ViewGroup sceneRoot, View view, TransitionValues startValues,
602 TransitionValues endValues) {
Robert Snoebergerdc8fee72019-07-19 16:35:35 -0400603 if (!sceneRoot.isShown()) {
604 return null;
605 }
Robert Snoeberger7cfa9dd2019-05-06 17:41:36 -0400606 final float cutoff = 1f - mCutoff;
607 final int startVisibility = View.VISIBLE;
608 final int endVisibility = (int) endValues.values.get(PROPNAME_VISIBILITY);
609 final float startScale = 1f;
610 final float endScale = mScale;
611 return createAnimator(view, cutoff, startVisibility, endVisibility, startScale,
612 endScale);
613 }
614
615 private Animator createAnimator(View view, float cutoff, int startVisibility,
616 int endVisibility, float startScale, float endScale) {
617 view.setPivotY(view.getHeight() - view.getPaddingBottom());
Robert Snoeberger7cfa9dd2019-05-06 17:41:36 -0400618 ValueAnimator animator = ValueAnimator.ofFloat(0f, 1f);
619 animator.addUpdateListener(animation -> {
620 final float fraction = animation.getAnimatedFraction();
621 if (fraction > cutoff) {
622 view.setVisibility(endVisibility);
Lucas Dupine570af62019-02-10 14:52:30 -0800623 }
Robert Snoeberger7cfa9dd2019-05-06 17:41:36 -0400624 final float scale = MathUtils.lerp(startScale, endScale, fraction);
625 view.setScaleX(scale);
626 view.setScaleY(scale);
627 });
Robert Snoeberger33259ad2019-06-19 14:55:49 -0400628 animator.addListener(new KeepAwakeAnimationListener(getContext()) {
Robert Snoebergerb66e9822019-05-16 11:14:43 -0400629 @Override
630 public void onAnimationStart(Animator animation) {
631 super.onAnimationStart(animation);
632 view.setVisibility(startVisibility);
Robert Snoeberger33259ad2019-06-19 14:55:49 -0400633 }
634
635 @Override
636 public void onAnimationEnd(Animator animation) {
637 super.onAnimationEnd(animation);
Robert Snoebergerb66e9822019-05-16 11:14:43 -0400638 animation.removeListener(this);
639 }
640 });
Robert Snoeberger7cfa9dd2019-05-06 17:41:36 -0400641 addListener(new TransitionListenerAdapter() {
642 @Override
643 public void onTransitionEnd(Transition transition) {
644 view.setVisibility(endVisibility);
645 view.setScaleX(1f);
646 view.setScaleY(1f);
647 transition.removeListener(this);
648 }
649 });
Lucas Dupine570af62019-02-10 14:52:30 -0800650 return animator;
651 }
652 }
Kunhung Li29007e62018-07-30 19:30:25 +0800653}