blob: 5097216a7405e74604b426fc2276d3a4564774cf [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;
Robert Snoeberger0397c842019-02-07 14:25:46 -050033import com.android.systemui.colorextraction.SysuiColorExtractor;
Kunhung Li29007e62018-07-30 19:30:25 +080034import com.android.systemui.plugins.ClockPlugin;
Beverly8fdb5332019-02-04 14:29:49 -050035import com.android.systemui.plugins.statusbar.StatusBarStateController;
Robert Snoeberger60854082019-01-04 13:13:17 -050036import com.android.systemui.statusbar.StatusBarState;
Robert Snoeberger33259ad2019-06-19 14:55:49 -040037import com.android.systemui.util.wakelock.KeepAwakeAnimationListener;
Kunhung Li29007e62018-07-30 19:30:25 +080038
Lucas Dupin43499522019-03-04 16:45:58 -080039import java.io.FileDescriptor;
40import java.io.PrintWriter;
41import java.util.Arrays;
Robert Snoeberger9c1074f2018-12-07 17:35:21 -050042import java.util.TimeZone;
Robert Snoeberger33ce6d92018-10-26 10:52:38 -040043
Robert Snoebergerbe35b762019-03-15 14:33:02 -040044import javax.inject.Inject;
45import javax.inject.Named;
46
Kunhung Li29007e62018-07-30 19:30:25 +080047/**
48 * Switch to show plugin clock when plugin is connected, otherwise it will show default clock.
49 */
Robert Snoebergere3b3e782018-12-17 13:32:15 -050050public class KeyguardClockSwitch extends RelativeLayout {
Robert Snoeberger046ee9c2019-01-10 18:29:38 -050051
Lucas Dupinf69aa772019-04-26 11:05:23 -070052 private static final String TAG = "KeyguardClockSwitch";
Robert Snoeberger61f04732019-06-27 10:31:09 -040053 private static final boolean CUSTOM_CLOCKS_ENABLED = false;
Lucas Dupinf69aa772019-04-26 11:05:23 -070054
Robert Snoebergerbe35b762019-03-15 14:33:02 -040055 /**
Robert Snoeberger7cfa9dd2019-05-06 17:41:36 -040056 * Animation fraction when text is transitioned to/from bold.
57 */
58 private static final float TO_BOLD_TRANSITION_FRACTION = 0.7f;
59
60 /**
Robert Snoebergerbe35b762019-03-15 14:33:02 -040061 * Controller used to track StatusBar state to know when to show the big_clock_container.
62 */
63 private final StatusBarStateController mStatusBarStateController;
64
65 /**
66 * Color extractor used to apply colors from wallpaper to custom clock faces.
67 */
68 private final SysuiColorExtractor mSysuiColorExtractor;
69
70 /**
71 * Manager used to know when to show a custom clock face.
72 */
73 private final ClockManager mClockManager;
74
75 /**
76 * Layout transition that scales the default clock face.
77 */
Lucas Dupine570af62019-02-10 14:52:30 -080078 private final Transition mTransition;
Robert Snoebergerbe35b762019-03-15 14:33:02 -040079
Robert Snoeberger7cfa9dd2019-05-06 17:41:36 -040080 private final ClockVisibilityTransition mClockTransition;
81 private final ClockVisibilityTransition mBoldClockTransition;
Robert Snoebergerf9030c72019-04-22 16:22:49 -040082
83 /**
Kunhung Li29007e62018-07-30 19:30:25 +080084 * Optional/alternative clock injected via plugin.
85 */
86 private ClockPlugin mClockPlugin;
Robert Snoebergerbe35b762019-03-15 14:33:02 -040087
Kunhung Li29007e62018-07-30 19:30:25 +080088 /**
89 * Default clock.
90 */
91 private TextClock mClockView;
Robert Snoebergerbe35b762019-03-15 14:33:02 -040092
Robert Snoebergere3b3e782018-12-17 13:32:15 -050093 /**
Robert Snoebergerf9030c72019-04-22 16:22:49 -040094 * Default clock, bold version.
95 * Used to transition to bold when shrinking the default clock.
96 */
97 private TextClock mClockViewBold;
98
99 /**
Robert Snoebergere3b3e782018-12-17 13:32:15 -0500100 * Frame for default and custom clock.
101 */
Robert Snoeberger6a0140a2018-12-20 12:46:17 -0500102 private FrameLayout mSmallClockFrame;
Robert Snoebergerbe35b762019-03-15 14:33:02 -0400103
Robert Snoeberger6a0140a2018-12-20 12:46:17 -0500104 /**
105 * Container for big custom clock.
106 */
107 private ViewGroup mBigClockContainer;
Robert Snoebergerbe35b762019-03-15 14:33:02 -0400108
Robert Snoebergere3b3e782018-12-17 13:32:15 -0500109 /**
Robert Snoeberger98312392019-03-15 16:53:51 -0400110 * Status area (date and other stuff) shown below the clock. Plugin can decide whether or not to
111 * show it below the alternate clock.
Robert Snoebergere3b3e782018-12-17 13:32:15 -0500112 */
113 private View mKeyguardStatusArea;
Robert Snoebergerbe35b762019-03-15 14:33:02 -0400114
Robert Snoeberger8bf1a3c2019-01-10 10:30:09 -0500115 /**
Robert Snoeberger58f23152019-01-10 15:51:32 -0500116 * Maintain state so that a newly connected plugin can be initialized.
117 */
118 private float mDarkAmount;
Robert Snoebergerbe35b762019-03-15 14:33:02 -0400119
Lucas Dupine570af62019-02-10 14:52:30 -0800120 /**
Robert Snoeberger146ab3c2019-06-13 14:12:10 -0400121 * Boolean value indicating if notifications are visible on lock screen.
122 */
123 private boolean mHasVisibleNotifications;
124
125 /**
Lucas Dupine570af62019-02-10 14:52:30 -0800126 * If the Keyguard Slice has a header (big center-aligned text.)
127 */
128 private boolean mShowingHeader;
Robert Snoeberger0397c842019-02-07 14:25:46 -0500129 private boolean mSupportsDarkText;
130 private int[] mColorPalette;
Kunhung Li29007e62018-07-30 19:30:25 +0800131
Robert Snoeberger98312392019-03-15 16:53:51 -0400132 /**
133 * Track the state of the status bar to know when to hide the big_clock_container.
134 */
135 private int mStatusBarState;
136
Robert Snoeberger60854082019-01-04 13:13:17 -0500137 private final StatusBarStateController.StateListener mStateListener =
138 new StatusBarStateController.StateListener() {
139 @Override
140 public void onStateChanged(int newState) {
Robert Snoeberger98312392019-03-15 16:53:51 -0400141 mStatusBarState = newState;
142 updateBigClockVisibility();
Robert Snoeberger60854082019-01-04 13:13:17 -0500143 }
Robert Snoeberger98312392019-03-15 16:53:51 -0400144 };
Kunhung Li29007e62018-07-30 19:30:25 +0800145
Robert Snoeberger15b4af12019-01-18 15:37:27 -0500146 private ClockManager.ClockChangedListener mClockChangedListener = this::setClockPlugin;
Robert Snoeberger046ee9c2019-01-10 18:29:38 -0500147
Robert Snoeberger0397c842019-02-07 14:25:46 -0500148 /**
149 * Listener for changes to the color palette.
150 *
151 * The color palette changes when the wallpaper is changed.
152 */
Robert Snoebergerbe35b762019-03-15 14:33:02 -0400153 private final OnColorsChangedListener mColorsListener = (extractor, which) -> {
Robert Snoeberger0397c842019-02-07 14:25:46 -0500154 if ((which & WallpaperManager.FLAG_LOCK) != 0) {
Robert Snoebergerbe35b762019-03-15 14:33:02 -0400155 updateColors();
Robert Snoeberger0397c842019-02-07 14:25:46 -0500156 }
157 };
158
Robert Snoebergerbe35b762019-03-15 14:33:02 -0400159 @Inject
160 public KeyguardClockSwitch(@Named(VIEW_CONTEXT) Context context, AttributeSet attrs,
161 StatusBarStateController statusBarStateController, SysuiColorExtractor colorExtractor,
162 ClockManager clockManager) {
Kunhung Li29007e62018-07-30 19:30:25 +0800163 super(context, attrs);
Robert Snoebergerbe35b762019-03-15 14:33:02 -0400164 mStatusBarStateController = statusBarStateController;
Robert Snoeberger372e13f2019-04-08 17:07:14 -0400165 mStatusBarState = mStatusBarStateController.getState();
Robert Snoebergerbe35b762019-03-15 14:33:02 -0400166 mSysuiColorExtractor = colorExtractor;
167 mClockManager = clockManager;
Robert Snoeberger7cfa9dd2019-05-06 17:41:36 -0400168
169 mClockTransition = new ClockVisibilityTransition().setCutoff(
170 1 - TO_BOLD_TRANSITION_FRACTION);
171 mClockTransition.addTarget(R.id.default_clock_view);
172 mBoldClockTransition = new ClockVisibilityTransition().setCutoff(
173 TO_BOLD_TRANSITION_FRACTION);
174 mBoldClockTransition.addTarget(R.id.default_clock_view_bold);
175 mTransition = new TransitionSet()
176 .setOrdering(TransitionSet.ORDERING_TOGETHER)
177 .addTransition(mClockTransition)
178 .addTransition(mBoldClockTransition)
179 .setDuration(KeyguardSliceView.DEFAULT_ANIM_DURATION / 2)
180 .setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN);
Kunhung Li29007e62018-07-30 19:30:25 +0800181 }
182
Lucas Dupin7fc9dc12019-01-03 09:19:43 -0800183 /**
184 * Returns if this view is presenting a custom clock, or the default implementation.
185 */
186 public boolean hasCustomClock() {
187 return mClockPlugin != null;
188 }
189
Kunhung Li29007e62018-07-30 19:30:25 +0800190 @Override
191 protected void onFinishInflate() {
192 super.onFinishInflate();
193 mClockView = findViewById(R.id.default_clock_view);
Robert Snoebergerf9030c72019-04-22 16:22:49 -0400194 mClockViewBold = findViewById(R.id.default_clock_view_bold);
Robert Snoeberger6a0140a2018-12-20 12:46:17 -0500195 mSmallClockFrame = findViewById(R.id.clock_view);
Robert Snoebergere3b3e782018-12-17 13:32:15 -0500196 mKeyguardStatusArea = findViewById(R.id.keyguard_status_area);
Kunhung Li29007e62018-07-30 19:30:25 +0800197 }
198
199 @Override
200 protected void onAttachedToWindow() {
201 super.onAttachedToWindow();
Robert Snoeberger61f04732019-06-27 10:31:09 -0400202 if (CUSTOM_CLOCKS_ENABLED) {
203 mClockManager.addOnClockChangedListener(mClockChangedListener);
204 }
Robert Snoebergerbe35b762019-03-15 14:33:02 -0400205 mStatusBarStateController.addCallback(mStateListener);
206 mSysuiColorExtractor.addOnColorsChangedListener(mColorsListener);
207 updateColors();
Kunhung Li29007e62018-07-30 19:30:25 +0800208 }
209
210 @Override
211 protected void onDetachedFromWindow() {
212 super.onDetachedFromWindow();
Robert Snoeberger61f04732019-06-27 10:31:09 -0400213 if (CUSTOM_CLOCKS_ENABLED) {
214 mClockManager.removeOnClockChangedListener(mClockChangedListener);
215 }
Robert Snoebergerbe35b762019-03-15 14:33:02 -0400216 mStatusBarStateController.removeCallback(mStateListener);
217 mSysuiColorExtractor.removeOnColorsChangedListener(mColorsListener);
Robert Snoebergerd7470252019-03-04 16:05:36 -0500218 setClockPlugin(null);
Kunhung Li29007e62018-07-30 19:30:25 +0800219 }
220
Robert Snoeberger8bf1a3c2019-01-10 10:30:09 -0500221 private void setClockPlugin(ClockPlugin plugin) {
222 // Disconnect from existing plugin.
223 if (mClockPlugin != null) {
224 View smallClockView = mClockPlugin.getView();
225 if (smallClockView != null && smallClockView.getParent() == mSmallClockFrame) {
226 mSmallClockFrame.removeView(smallClockView);
227 }
228 if (mBigClockContainer != null) {
229 mBigClockContainer.removeAllViews();
Robert Snoeberger98312392019-03-15 16:53:51 -0400230 updateBigClockVisibility();
Robert Snoeberger8bf1a3c2019-01-10 10:30:09 -0500231 }
Robert Snoeberger3358cfb2019-04-03 13:09:55 -0400232 mClockPlugin.onDestroyView();
Robert Snoeberger8bf1a3c2019-01-10 10:30:09 -0500233 mClockPlugin = null;
234 }
235 if (plugin == null) {
Robert Snoebergerf65513a2019-06-20 10:40:13 -0400236 if (mShowingHeader) {
237 mClockView.setVisibility(View.GONE);
238 mClockViewBold.setVisibility(View.VISIBLE);
239 } else {
240 mClockView.setVisibility(View.VISIBLE);
241 mClockViewBold.setVisibility(View.INVISIBLE);
242 }
Robert Snoeberger8bf1a3c2019-01-10 10:30:09 -0500243 mKeyguardStatusArea.setVisibility(View.VISIBLE);
244 return;
245 }
246 // Attach small and big clock views to hierarchy.
247 View smallClockView = plugin.getView();
248 if (smallClockView != null) {
249 mSmallClockFrame.addView(smallClockView, -1,
250 new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
251 ViewGroup.LayoutParams.WRAP_CONTENT));
252 mClockView.setVisibility(View.GONE);
Robert Snoebergerf9030c72019-04-22 16:22:49 -0400253 mClockViewBold.setVisibility(View.GONE);
Robert Snoeberger8bf1a3c2019-01-10 10:30:09 -0500254 }
255 View bigClockView = plugin.getBigClockView();
256 if (bigClockView != null && mBigClockContainer != null) {
257 mBigClockContainer.addView(bigClockView);
Robert Snoeberger98312392019-03-15 16:53:51 -0400258 updateBigClockVisibility();
Robert Snoeberger8bf1a3c2019-01-10 10:30:09 -0500259 }
260 // Hide default clock.
261 if (!plugin.shouldShowStatusArea()) {
262 mKeyguardStatusArea.setVisibility(View.GONE);
263 }
264 // Initialize plugin parameters.
265 mClockPlugin = plugin;
266 mClockPlugin.setStyle(getPaint().getStyle());
267 mClockPlugin.setTextColor(getCurrentTextColor());
Robert Snoeberger58f23152019-01-10 15:51:32 -0500268 mClockPlugin.setDarkAmount(mDarkAmount);
Robert Snoeberger0397c842019-02-07 14:25:46 -0500269 if (mColorPalette != null) {
270 mClockPlugin.setColorPalette(mSupportsDarkText, mColorPalette);
271 }
Robert Snoeberger8bf1a3c2019-01-10 10:30:09 -0500272 }
273
Kunhung Li29007e62018-07-30 19:30:25 +0800274 /**
Robert Snoeberger6a0140a2018-12-20 12:46:17 -0500275 * Set container for big clock face appearing behind NSSL and KeyguardStatusView.
276 */
277 public void setBigClockContainer(ViewGroup container) {
278 if (mClockPlugin != null && container != null) {
279 View bigClockView = mClockPlugin.getBigClockView();
280 if (bigClockView != null) {
281 container.addView(bigClockView);
Robert Snoeberger6a0140a2018-12-20 12:46:17 -0500282 }
283 }
284 mBigClockContainer = container;
Robert Snoeberger98312392019-03-15 16:53:51 -0400285 updateBigClockVisibility();
Robert Snoeberger6a0140a2018-12-20 12:46:17 -0500286 }
287
288 /**
Kunhung Li29007e62018-07-30 19:30:25 +0800289 * It will also update plugin setStyle if plugin is connected.
290 */
291 public void setStyle(Style style) {
292 mClockView.getPaint().setStyle(style);
Robert Snoebergerf9030c72019-04-22 16:22:49 -0400293 mClockViewBold.getPaint().setStyle(style);
Kunhung Li29007e62018-07-30 19:30:25 +0800294 if (mClockPlugin != null) {
295 mClockPlugin.setStyle(style);
296 }
297 }
298
299 /**
300 * It will also update plugin setTextColor if plugin is connected.
301 */
302 public void setTextColor(int color) {
303 mClockView.setTextColor(color);
Robert Snoebergerf9030c72019-04-22 16:22:49 -0400304 mClockViewBold.setTextColor(color);
Kunhung Li29007e62018-07-30 19:30:25 +0800305 if (mClockPlugin != null) {
306 mClockPlugin.setTextColor(color);
307 }
308 }
309
310 public void setShowCurrentUserTime(boolean showCurrentUserTime) {
311 mClockView.setShowCurrentUserTime(showCurrentUserTime);
Robert Snoebergerf9030c72019-04-22 16:22:49 -0400312 mClockViewBold.setShowCurrentUserTime(showCurrentUserTime);
Kunhung Li29007e62018-07-30 19:30:25 +0800313 }
314
Kunhung Li29007e62018-07-30 19:30:25 +0800315 public void setTextSize(int unit, float size) {
316 mClockView.setTextSize(unit, size);
317 }
318
319 public void setFormat12Hour(CharSequence format) {
320 mClockView.setFormat12Hour(format);
Robert Snoebergerf9030c72019-04-22 16:22:49 -0400321 mClockViewBold.setFormat12Hour(format);
Kunhung Li29007e62018-07-30 19:30:25 +0800322 }
323
324 public void setFormat24Hour(CharSequence format) {
325 mClockView.setFormat24Hour(format);
Robert Snoebergerf9030c72019-04-22 16:22:49 -0400326 mClockViewBold.setFormat24Hour(format);
Kunhung Li29007e62018-07-30 19:30:25 +0800327 }
328
Robert Snoebergere32efd72018-11-12 08:38:34 -0500329 /**
330 * Set the amount (ratio) that the device has transitioned to doze.
Robert Snoeberger98312392019-03-15 16:53:51 -0400331 *
Robert Snoebergere32efd72018-11-12 08:38:34 -0500332 * @param darkAmount Amount of transition to doze: 1f for doze and 0f for awake.
333 */
334 public void setDarkAmount(float darkAmount) {
Robert Snoeberger58f23152019-01-10 15:51:32 -0500335 mDarkAmount = darkAmount;
Robert Snoebergere32efd72018-11-12 08:38:34 -0500336 if (mClockPlugin != null) {
337 mClockPlugin.setDarkAmount(darkAmount);
338 }
Robert Snoeberger146ab3c2019-06-13 14:12:10 -0400339 updateBigClockAlpha();
340 }
341
342 /**
343 * Set whether or not the lock screen is showing notifications.
344 */
345 void setHasVisibleNotifications(boolean hasVisibleNotifications) {
346 if (hasVisibleNotifications == mHasVisibleNotifications) {
347 return;
348 }
349 mHasVisibleNotifications = hasVisibleNotifications;
350 if (mDarkAmount == 0f && mBigClockContainer != null) {
351 // Starting a fade transition since the visibility of the big clock will change.
352 TransitionManager.beginDelayedTransition(mBigClockContainer,
353 new Fade().setDuration(KeyguardSliceView.DEFAULT_ANIM_DURATION / 2).addTarget(
354 mBigClockContainer));
355 }
356 updateBigClockAlpha();
Robert Snoebergere32efd72018-11-12 08:38:34 -0500357 }
358
Kunhung Li29007e62018-07-30 19:30:25 +0800359 public Paint getPaint() {
360 return mClockView.getPaint();
361 }
362
363 public int getCurrentTextColor() {
364 return mClockView.getCurrentTextColor();
365 }
366
367 public float getTextSize() {
368 return mClockView.getTextSize();
369 }
370
Robert Snoebergerae926732019-03-21 11:40:16 -0400371 /**
Robert Snoeberger69956802019-04-16 16:55:21 -0400372 * Returns the preferred Y position of the clock.
373 *
374 * @param totalHeight Height of the parent container.
375 * @return preferred Y position.
376 */
377 int getPreferredY(int totalHeight) {
378 if (mClockPlugin != null) {
379 return mClockPlugin.getPreferredY(totalHeight);
380 } else {
381 return totalHeight / 2;
382 }
383 }
384
385 /**
Robert Snoebergerae926732019-03-21 11:40:16 -0400386 * Refresh the time of the clock, due to either time tick broadcast or doze time tick alarm.
387 */
Kunhung Li29007e62018-07-30 19:30:25 +0800388 public void refresh() {
389 mClockView.refresh();
Robert Snoebergerf9030c72019-04-22 16:22:49 -0400390 mClockViewBold.refresh();
Robert Snoebergerffbe3152018-11-08 15:53:27 -0500391 if (mClockPlugin != null) {
Robert Snoeberger9ad03f42019-02-28 14:47:49 -0500392 mClockPlugin.onTimeTick();
Robert Snoebergerffbe3152018-11-08 15:53:27 -0500393 }
Lucas Dupinf69aa772019-04-26 11:05:23 -0700394 if (Build.IS_DEBUGGABLE) {
395 // Log for debugging b/130888082 (sysui waking up, but clock not updating)
396 Log.d(TAG, "Updating clock: " + mClockView.getText());
397 }
Robert Snoebergerffbe3152018-11-08 15:53:27 -0500398 }
399
400 /**
Robert Snoeberger9c1074f2018-12-07 17:35:21 -0500401 * Notifies that the time zone has changed.
402 */
403 public void onTimeZoneChanged(TimeZone timeZone) {
404 if (mClockPlugin != null) {
405 mClockPlugin.onTimeZoneChanged(timeZone);
406 }
407 }
408
Robert Snoebergerbe35b762019-03-15 14:33:02 -0400409 private void updateColors() {
410 ColorExtractor.GradientColors colors = mSysuiColorExtractor.getColors(
Lucas Dupin89233c42019-06-10 18:00:22 -0700411 WallpaperManager.FLAG_LOCK);
Robert Snoeberger0397c842019-02-07 14:25:46 -0500412 mSupportsDarkText = colors.supportsDarkText();
413 mColorPalette = colors.getColorPalette();
414 if (mClockPlugin != null) {
415 mClockPlugin.setColorPalette(mSupportsDarkText, mColorPalette);
416 }
417 }
418
Robert Snoeberger98312392019-03-15 16:53:51 -0400419 private void updateBigClockVisibility() {
420 if (mBigClockContainer == null) {
421 return;
422 }
423 final boolean inDisplayState = mStatusBarState == StatusBarState.KEYGUARD
424 || mStatusBarState == StatusBarState.SHADE_LOCKED;
425 final int visibility =
426 inDisplayState && mBigClockContainer.getChildCount() != 0 ? View.VISIBLE
427 : View.GONE;
428 if (mBigClockContainer.getVisibility() != visibility) {
429 mBigClockContainer.setVisibility(visibility);
430 }
431 }
432
Robert Snoeberger146ab3c2019-06-13 14:12:10 -0400433 private void updateBigClockAlpha() {
434 if (mBigClockContainer != null) {
435 final float alpha = mHasVisibleNotifications ? mDarkAmount : 1f;
436 mBigClockContainer.setAlpha(alpha);
437 if (alpha == 0f) {
438 mBigClockContainer.setVisibility(INVISIBLE);
439 } else if (mBigClockContainer.getVisibility() == INVISIBLE) {
440 mBigClockContainer.setVisibility(VISIBLE);
441 }
442 }
443 }
444
Lucas Dupine570af62019-02-10 14:52:30 -0800445 /**
Robert Snoeberger98312392019-03-15 16:53:51 -0400446 * Sets if the keyguard slice is showing a center-aligned header. We need a smaller clock in
Robert Snoebergerf9030c72019-04-22 16:22:49 -0400447 * these cases.
Lucas Dupine570af62019-02-10 14:52:30 -0800448 */
Robert Snoeberger7cfa9dd2019-05-06 17:41:36 -0400449 void setKeyguardShowingHeader(boolean hasHeader) {
Robert Snoebergerf65513a2019-06-20 10:40:13 -0400450 if (mShowingHeader == hasHeader) {
Lucas Dupine570af62019-02-10 14:52:30 -0800451 return;
452 }
453 mShowingHeader = hasHeader;
Robert Snoebergerf65513a2019-06-20 10:40:13 -0400454 if (hasCustomClock()) {
455 return;
456 }
Lucas Dupine570af62019-02-10 14:52:30 -0800457
Robert Snoeberger7cfa9dd2019-05-06 17:41:36 -0400458 float smallFontSize = mContext.getResources().getDimensionPixelSize(
459 R.dimen.widget_small_font_size);
460 float bigFontSize = mContext.getResources().getDimensionPixelSize(
461 R.dimen.widget_big_font_size);
462 mClockTransition.setScale(smallFontSize / bigFontSize);
463 mBoldClockTransition.setScale(bigFontSize / smallFontSize);
464
Robert Snoebergerb66e9822019-05-16 11:14:43 -0400465 // End any current transitions before starting a new transition so that the new transition
466 // starts from a good state instead of a potentially bad intermediate state arrived at
467 // during a transition animation.
468 TransitionManager.endTransitions((ViewGroup) mClockView.getParent());
Robert Snoeberger7cfa9dd2019-05-06 17:41:36 -0400469
470 if (hasHeader) {
471 // After the transition, make the default clock GONE so that it doesn't make the
472 // KeyguardStatusView appear taller in KeyguardClockPositionAlgorithm and elsewhere.
473 mTransition.addListener(new TransitionListenerAdapter() {
474 @Override
475 public void onTransitionEnd(Transition transition) {
476 super.onTransitionEnd(transition);
477 // Check that header is actually showing. I saw issues where this event was
478 // fired after the big clock transitioned back to visible, which causes the time
479 // to completely disappear.
480 if (mShowingHeader) {
481 mClockView.setVisibility(View.GONE);
482 }
483 transition.removeListener(this);
484 }
485 });
486 }
Robert Snoebergerb66e9822019-05-16 11:14:43 -0400487
488 TransitionManager.beginDelayedTransition((ViewGroup) mClockView.getParent(), mTransition);
489 mClockView.setVisibility(hasHeader ? View.INVISIBLE : View.VISIBLE);
490 mClockViewBold.setVisibility(hasHeader ? View.VISIBLE : View.INVISIBLE);
491 int paddingBottom = mContext.getResources().getDimensionPixelSize(hasHeader
492 ? R.dimen.widget_vertical_padding_clock : R.dimen.title_clock_padding);
493 mClockView.setPadding(mClockView.getPaddingLeft(), mClockView.getPaddingTop(),
494 mClockView.getPaddingRight(), paddingBottom);
495 mClockViewBold.setPadding(mClockViewBold.getPaddingLeft(), mClockViewBold.getPaddingTop(),
496 mClockViewBold.getPaddingRight(), paddingBottom);
Lucas Dupine570af62019-02-10 14:52:30 -0800497 }
498
Robert Snoeberger98312392019-03-15 16:53:51 -0400499 @VisibleForTesting(otherwise = VisibleForTesting.NONE)
Robert Snoeberger15b4af12019-01-18 15:37:27 -0500500 ClockManager.ClockChangedListener getClockChangedListener() {
501 return mClockChangedListener;
Kunhung Li29007e62018-07-30 19:30:25 +0800502 }
Robert Snoeberger60854082019-01-04 13:13:17 -0500503
Robert Snoeberger98312392019-03-15 16:53:51 -0400504 @VisibleForTesting(otherwise = VisibleForTesting.NONE)
Robert Snoeberger60854082019-01-04 13:13:17 -0500505 StatusBarStateController.StateListener getStateListener() {
506 return mStateListener;
507 }
Lucas Dupine570af62019-02-10 14:52:30 -0800508
Lucas Dupin43499522019-03-04 16:45:58 -0800509 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
510 pw.println("KeyguardClockSwitch:");
511 pw.println(" mClockPlugin: " + mClockPlugin);
512 pw.println(" mClockView: " + mClockView);
Robert Snoebergerf9030c72019-04-22 16:22:49 -0400513 pw.println(" mClockViewBold: " + mClockViewBold);
Lucas Dupin43499522019-03-04 16:45:58 -0800514 pw.println(" mSmallClockFrame: " + mSmallClockFrame);
515 pw.println(" mBigClockContainer: " + mBigClockContainer);
516 pw.println(" mKeyguardStatusArea: " + mKeyguardStatusArea);
517 pw.println(" mDarkAmount: " + mDarkAmount);
518 pw.println(" mShowingHeader: " + mShowingHeader);
519 pw.println(" mSupportsDarkText: " + mSupportsDarkText);
520 pw.println(" mColorPalette: " + Arrays.toString(mColorPalette));
521 }
522
Lucas Dupine570af62019-02-10 14:52:30 -0800523 /**
Robert Snoeberger7cfa9dd2019-05-06 17:41:36 -0400524 * {@link Visibility} transformation that scales the view while it is disappearing/appearing and
525 * transitions suddenly at a cutoff fraction during the animation.
Lucas Dupine570af62019-02-10 14:52:30 -0800526 */
Robert Snoeberger7cfa9dd2019-05-06 17:41:36 -0400527 private class ClockVisibilityTransition extends android.transition.Visibility {
528
529 private static final String PROPNAME_VISIBILITY = "systemui:keyguard:visibility";
530
531 private float mCutoff;
532 private float mScale;
Lucas Dupine570af62019-02-10 14:52:30 -0800533
Robert Snoebergerf9030c72019-04-22 16:22:49 -0400534 /**
Robert Snoeberger7cfa9dd2019-05-06 17:41:36 -0400535 * Constructs a transition that switches between visible/invisible at a cutoff and scales in
536 * size while appearing/disappearing.
Robert Snoebergerf9030c72019-04-22 16:22:49 -0400537 */
Robert Snoeberger7cfa9dd2019-05-06 17:41:36 -0400538 ClockVisibilityTransition() {
539 setCutoff(1f);
540 setScale(1f);
541 }
Robert Snoebergerf9030c72019-04-22 16:22:49 -0400542
Robert Snoeberger7cfa9dd2019-05-06 17:41:36 -0400543 /**
544 * Sets the transition point between visible/invisible.
545 *
546 * @param cutoff The fraction in [0, 1] when the view switches between visible/invisible.
547 * @return This transition object
548 */
549 public ClockVisibilityTransition setCutoff(float cutoff) {
550 mCutoff = cutoff;
551 return this;
552 }
553
554 /**
555 * Sets the scale factor applied while appearing/disappearing.
556 *
557 * @param scale Scale factor applied while appearing/disappearing. When factor is less than
558 * one, the view will shrink while disappearing. When it is greater than one,
559 * the view will expand while disappearing.
560 * @return This transition object
561 */
562 public ClockVisibilityTransition setScale(float scale) {
563 mScale = scale;
564 return this;
Lucas Dupine570af62019-02-10 14:52:30 -0800565 }
566
567 @Override
Robert Snoeberger7cfa9dd2019-05-06 17:41:36 -0400568 public void captureStartValues(TransitionValues transitionValues) {
569 super.captureStartValues(transitionValues);
570 captureVisibility(transitionValues);
571 }
572
573 @Override
574 public void captureEndValues(TransitionValues transitionValues) {
575 super.captureStartValues(transitionValues);
576 captureVisibility(transitionValues);
577 }
578
579 private void captureVisibility(TransitionValues transitionValues) {
580 transitionValues.values.put(PROPNAME_VISIBILITY,
581 transitionValues.view.getVisibility());
582 }
583
584 @Override
585 public Animator onAppear(ViewGroup sceneRoot, View view, TransitionValues startValues,
Lucas Dupine570af62019-02-10 14:52:30 -0800586 TransitionValues endValues) {
Robert Snoebergerdc8fee72019-07-19 16:35:35 -0400587 if (!sceneRoot.isShown()) {
588 return null;
589 }
Robert Snoeberger7cfa9dd2019-05-06 17:41:36 -0400590 final float cutoff = mCutoff;
591 final int startVisibility = View.INVISIBLE;
592 final int endVisibility = (int) endValues.values.get(PROPNAME_VISIBILITY);
593 final float startScale = mScale;
594 final float endScale = 1f;
595 return createAnimator(view, cutoff, startVisibility, endVisibility, startScale,
596 endScale);
597 }
Lucas Dupine570af62019-02-10 14:52:30 -0800598
Robert Snoeberger7cfa9dd2019-05-06 17:41:36 -0400599 @Override
600 public Animator onDisappear(ViewGroup sceneRoot, View view, TransitionValues startValues,
601 TransitionValues endValues) {
Robert Snoebergerdc8fee72019-07-19 16:35:35 -0400602 if (!sceneRoot.isShown()) {
603 return null;
604 }
Robert Snoeberger7cfa9dd2019-05-06 17:41:36 -0400605 final float cutoff = 1f - mCutoff;
606 final int startVisibility = View.VISIBLE;
607 final int endVisibility = (int) endValues.values.get(PROPNAME_VISIBILITY);
608 final float startScale = 1f;
609 final float endScale = mScale;
610 return createAnimator(view, cutoff, startVisibility, endVisibility, startScale,
611 endScale);
612 }
613
614 private Animator createAnimator(View view, float cutoff, int startVisibility,
615 int endVisibility, float startScale, float endScale) {
616 view.setPivotY(view.getHeight() - view.getPaddingBottom());
Robert Snoeberger7cfa9dd2019-05-06 17:41:36 -0400617 ValueAnimator animator = ValueAnimator.ofFloat(0f, 1f);
618 animator.addUpdateListener(animation -> {
619 final float fraction = animation.getAnimatedFraction();
620 if (fraction > cutoff) {
621 view.setVisibility(endVisibility);
Lucas Dupine570af62019-02-10 14:52:30 -0800622 }
Robert Snoeberger7cfa9dd2019-05-06 17:41:36 -0400623 final float scale = MathUtils.lerp(startScale, endScale, fraction);
624 view.setScaleX(scale);
625 view.setScaleY(scale);
626 });
Robert Snoeberger33259ad2019-06-19 14:55:49 -0400627 animator.addListener(new KeepAwakeAnimationListener(getContext()) {
Robert Snoebergerb66e9822019-05-16 11:14:43 -0400628 @Override
629 public void onAnimationStart(Animator animation) {
630 super.onAnimationStart(animation);
631 view.setVisibility(startVisibility);
Robert Snoeberger33259ad2019-06-19 14:55:49 -0400632 }
633
634 @Override
635 public void onAnimationEnd(Animator animation) {
636 super.onAnimationEnd(animation);
Robert Snoebergerb66e9822019-05-16 11:14:43 -0400637 animation.removeListener(this);
638 }
639 });
Robert Snoeberger7cfa9dd2019-05-06 17:41:36 -0400640 addListener(new TransitionListenerAdapter() {
641 @Override
642 public void onTransitionEnd(Transition transition) {
643 view.setVisibility(endVisibility);
644 view.setScaleX(1f);
645 view.setScaleY(1f);
646 transition.removeListener(this);
647 }
648 });
Lucas Dupine570af62019-02-10 14:52:30 -0800649 return animator;
650 }
651 }
Kunhung Li29007e62018-07-30 19:30:25 +0800652}