blob: b1cba53c4bca3b4d016791ad6e7b6b6562413edb [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;
Robert Snoebergerb66e9822019-05-16 11:14:43 -04006import android.animation.AnimatorListenerAdapter;
Lucas Dupine570af62019-02-10 14:52:30 -08007import android.animation.ValueAnimator;
Robert Snoeberger0397c842019-02-07 14:25:46 -05008import android.app.WallpaperManager;
Kunhung Li29007e62018-07-30 19:30:25 +08009import android.content.Context;
10import android.graphics.Paint;
11import android.graphics.Paint.Style;
Lucas Dupinf69aa772019-04-26 11:05:23 -070012import android.os.Build;
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;
Kunhung Li29007e62018-07-30 19:30:25 +080037
Lucas Dupin43499522019-03-04 16:45:58 -080038import java.io.FileDescriptor;
39import java.io.PrintWriter;
40import java.util.Arrays;
Robert Snoeberger9c1074f2018-12-07 17:35:21 -050041import java.util.TimeZone;
Robert Snoeberger33ce6d92018-10-26 10:52:38 -040042
Robert Snoebergerbe35b762019-03-15 14:33:02 -040043import javax.inject.Inject;
44import javax.inject.Named;
45
Kunhung Li29007e62018-07-30 19:30:25 +080046/**
47 * Switch to show plugin clock when plugin is connected, otherwise it will show default clock.
48 */
Robert Snoebergere3b3e782018-12-17 13:32:15 -050049public class KeyguardClockSwitch extends RelativeLayout {
Robert Snoeberger046ee9c2019-01-10 18:29:38 -050050
Lucas Dupinf69aa772019-04-26 11:05:23 -070051 private static final String TAG = "KeyguardClockSwitch";
Robert Snoeberger61f04732019-06-27 10:31:09 -040052 private static final boolean CUSTOM_CLOCKS_ENABLED = false;
Lucas Dupinf69aa772019-04-26 11:05:23 -070053
Robert Snoebergerbe35b762019-03-15 14:33:02 -040054 /**
Robert Snoeberger7cfa9dd2019-05-06 17:41:36 -040055 * Animation fraction when text is transitioned to/from bold.
56 */
57 private static final float TO_BOLD_TRANSITION_FRACTION = 0.7f;
58
59 /**
Robert Snoebergerbe35b762019-03-15 14:33:02 -040060 * Controller used to track StatusBar state to know when to show the big_clock_container.
61 */
62 private final StatusBarStateController mStatusBarStateController;
63
64 /**
65 * Color extractor used to apply colors from wallpaper to custom clock faces.
66 */
67 private final SysuiColorExtractor mSysuiColorExtractor;
68
69 /**
70 * Manager used to know when to show a custom clock face.
71 */
72 private final ClockManager mClockManager;
73
74 /**
75 * Layout transition that scales the default clock face.
76 */
Lucas Dupine570af62019-02-10 14:52:30 -080077 private final Transition mTransition;
Robert Snoebergerbe35b762019-03-15 14:33:02 -040078
Robert Snoeberger7cfa9dd2019-05-06 17:41:36 -040079 private final ClockVisibilityTransition mClockTransition;
80 private final ClockVisibilityTransition mBoldClockTransition;
Robert Snoebergerf9030c72019-04-22 16:22:49 -040081
82 /**
Kunhung Li29007e62018-07-30 19:30:25 +080083 * Optional/alternative clock injected via plugin.
84 */
85 private ClockPlugin mClockPlugin;
Robert Snoebergerbe35b762019-03-15 14:33:02 -040086
Kunhung Li29007e62018-07-30 19:30:25 +080087 /**
88 * Default clock.
89 */
90 private TextClock mClockView;
Robert Snoebergerbe35b762019-03-15 14:33:02 -040091
Robert Snoebergere3b3e782018-12-17 13:32:15 -050092 /**
Robert Snoebergerf9030c72019-04-22 16:22:49 -040093 * Default clock, bold version.
94 * Used to transition to bold when shrinking the default clock.
95 */
96 private TextClock mClockViewBold;
97
98 /**
Robert Snoebergere3b3e782018-12-17 13:32:15 -050099 * Frame for default and custom clock.
100 */
Robert Snoeberger6a0140a2018-12-20 12:46:17 -0500101 private FrameLayout mSmallClockFrame;
Robert Snoebergerbe35b762019-03-15 14:33:02 -0400102
Robert Snoeberger6a0140a2018-12-20 12:46:17 -0500103 /**
104 * Container for big custom clock.
105 */
106 private ViewGroup mBigClockContainer;
Robert Snoebergerbe35b762019-03-15 14:33:02 -0400107
Robert Snoebergere3b3e782018-12-17 13:32:15 -0500108 /**
Robert Snoeberger98312392019-03-15 16:53:51 -0400109 * Status area (date and other stuff) shown below the clock. Plugin can decide whether or not to
110 * show it below the alternate clock.
Robert Snoebergere3b3e782018-12-17 13:32:15 -0500111 */
112 private View mKeyguardStatusArea;
Robert Snoebergerbe35b762019-03-15 14:33:02 -0400113
Robert Snoeberger8bf1a3c2019-01-10 10:30:09 -0500114 /**
Robert Snoeberger58f23152019-01-10 15:51:32 -0500115 * Maintain state so that a newly connected plugin can be initialized.
116 */
117 private float mDarkAmount;
Robert Snoebergerbe35b762019-03-15 14:33:02 -0400118
Lucas Dupine570af62019-02-10 14:52:30 -0800119 /**
120 * If the Keyguard Slice has a header (big center-aligned text.)
121 */
122 private boolean mShowingHeader;
Robert Snoeberger0397c842019-02-07 14:25:46 -0500123 private boolean mSupportsDarkText;
124 private int[] mColorPalette;
Kunhung Li29007e62018-07-30 19:30:25 +0800125
Robert Snoeberger98312392019-03-15 16:53:51 -0400126 /**
127 * Track the state of the status bar to know when to hide the big_clock_container.
128 */
129 private int mStatusBarState;
130
Robert Snoeberger60854082019-01-04 13:13:17 -0500131 private final StatusBarStateController.StateListener mStateListener =
132 new StatusBarStateController.StateListener() {
133 @Override
134 public void onStateChanged(int newState) {
Robert Snoeberger98312392019-03-15 16:53:51 -0400135 mStatusBarState = newState;
136 updateBigClockVisibility();
Robert Snoeberger60854082019-01-04 13:13:17 -0500137 }
Robert Snoeberger98312392019-03-15 16:53:51 -0400138 };
Kunhung Li29007e62018-07-30 19:30:25 +0800139
Robert Snoeberger15b4af12019-01-18 15:37:27 -0500140 private ClockManager.ClockChangedListener mClockChangedListener = this::setClockPlugin;
Robert Snoeberger046ee9c2019-01-10 18:29:38 -0500141
Robert Snoeberger0397c842019-02-07 14:25:46 -0500142 /**
143 * Listener for changes to the color palette.
144 *
145 * The color palette changes when the wallpaper is changed.
146 */
Robert Snoebergerbe35b762019-03-15 14:33:02 -0400147 private final OnColorsChangedListener mColorsListener = (extractor, which) -> {
Robert Snoeberger0397c842019-02-07 14:25:46 -0500148 if ((which & WallpaperManager.FLAG_LOCK) != 0) {
Robert Snoebergerbe35b762019-03-15 14:33:02 -0400149 updateColors();
Robert Snoeberger0397c842019-02-07 14:25:46 -0500150 }
151 };
152
Robert Snoebergerbe35b762019-03-15 14:33:02 -0400153 @Inject
154 public KeyguardClockSwitch(@Named(VIEW_CONTEXT) Context context, AttributeSet attrs,
155 StatusBarStateController statusBarStateController, SysuiColorExtractor colorExtractor,
156 ClockManager clockManager) {
Kunhung Li29007e62018-07-30 19:30:25 +0800157 super(context, attrs);
Robert Snoebergerbe35b762019-03-15 14:33:02 -0400158 mStatusBarStateController = statusBarStateController;
Robert Snoeberger372e13f2019-04-08 17:07:14 -0400159 mStatusBarState = mStatusBarStateController.getState();
Robert Snoebergerbe35b762019-03-15 14:33:02 -0400160 mSysuiColorExtractor = colorExtractor;
161 mClockManager = clockManager;
Robert Snoeberger7cfa9dd2019-05-06 17:41:36 -0400162
163 mClockTransition = new ClockVisibilityTransition().setCutoff(
164 1 - TO_BOLD_TRANSITION_FRACTION);
165 mClockTransition.addTarget(R.id.default_clock_view);
166 mBoldClockTransition = new ClockVisibilityTransition().setCutoff(
167 TO_BOLD_TRANSITION_FRACTION);
168 mBoldClockTransition.addTarget(R.id.default_clock_view_bold);
169 mTransition = new TransitionSet()
170 .setOrdering(TransitionSet.ORDERING_TOGETHER)
171 .addTransition(mClockTransition)
172 .addTransition(mBoldClockTransition)
173 .setDuration(KeyguardSliceView.DEFAULT_ANIM_DURATION / 2)
174 .setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN);
Kunhung Li29007e62018-07-30 19:30:25 +0800175 }
176
Lucas Dupin7fc9dc12019-01-03 09:19:43 -0800177 /**
178 * Returns if this view is presenting a custom clock, or the default implementation.
179 */
180 public boolean hasCustomClock() {
181 return mClockPlugin != null;
182 }
183
Kunhung Li29007e62018-07-30 19:30:25 +0800184 @Override
185 protected void onFinishInflate() {
186 super.onFinishInflate();
187 mClockView = findViewById(R.id.default_clock_view);
Robert Snoebergerf9030c72019-04-22 16:22:49 -0400188 mClockViewBold = findViewById(R.id.default_clock_view_bold);
Robert Snoeberger6a0140a2018-12-20 12:46:17 -0500189 mSmallClockFrame = findViewById(R.id.clock_view);
Robert Snoebergere3b3e782018-12-17 13:32:15 -0500190 mKeyguardStatusArea = findViewById(R.id.keyguard_status_area);
Kunhung Li29007e62018-07-30 19:30:25 +0800191 }
192
193 @Override
194 protected void onAttachedToWindow() {
195 super.onAttachedToWindow();
Robert Snoeberger61f04732019-06-27 10:31:09 -0400196 if (CUSTOM_CLOCKS_ENABLED) {
197 mClockManager.addOnClockChangedListener(mClockChangedListener);
198 }
Robert Snoebergerbe35b762019-03-15 14:33:02 -0400199 mStatusBarStateController.addCallback(mStateListener);
200 mSysuiColorExtractor.addOnColorsChangedListener(mColorsListener);
201 updateColors();
Kunhung Li29007e62018-07-30 19:30:25 +0800202 }
203
204 @Override
205 protected void onDetachedFromWindow() {
206 super.onDetachedFromWindow();
Robert Snoeberger61f04732019-06-27 10:31:09 -0400207 if (CUSTOM_CLOCKS_ENABLED) {
208 mClockManager.removeOnClockChangedListener(mClockChangedListener);
209 }
Robert Snoebergerbe35b762019-03-15 14:33:02 -0400210 mStatusBarStateController.removeCallback(mStateListener);
211 mSysuiColorExtractor.removeOnColorsChangedListener(mColorsListener);
Robert Snoebergerd7470252019-03-04 16:05:36 -0500212 setClockPlugin(null);
Kunhung Li29007e62018-07-30 19:30:25 +0800213 }
214
Robert Snoeberger8bf1a3c2019-01-10 10:30:09 -0500215 private void setClockPlugin(ClockPlugin plugin) {
216 // Disconnect from existing plugin.
217 if (mClockPlugin != null) {
218 View smallClockView = mClockPlugin.getView();
219 if (smallClockView != null && smallClockView.getParent() == mSmallClockFrame) {
220 mSmallClockFrame.removeView(smallClockView);
221 }
222 if (mBigClockContainer != null) {
223 mBigClockContainer.removeAllViews();
Robert Snoeberger98312392019-03-15 16:53:51 -0400224 updateBigClockVisibility();
Robert Snoeberger8bf1a3c2019-01-10 10:30:09 -0500225 }
Robert Snoeberger3358cfb2019-04-03 13:09:55 -0400226 mClockPlugin.onDestroyView();
Robert Snoeberger8bf1a3c2019-01-10 10:30:09 -0500227 mClockPlugin = null;
228 }
229 if (plugin == null) {
230 mClockView.setVisibility(View.VISIBLE);
Robert Snoebergerf9030c72019-04-22 16:22:49 -0400231 mClockViewBold.setVisibility(View.INVISIBLE);
Robert Snoeberger8bf1a3c2019-01-10 10:30:09 -0500232 mKeyguardStatusArea.setVisibility(View.VISIBLE);
233 return;
234 }
235 // Attach small and big clock views to hierarchy.
236 View smallClockView = plugin.getView();
237 if (smallClockView != null) {
238 mSmallClockFrame.addView(smallClockView, -1,
239 new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
240 ViewGroup.LayoutParams.WRAP_CONTENT));
241 mClockView.setVisibility(View.GONE);
Robert Snoebergerf9030c72019-04-22 16:22:49 -0400242 mClockViewBold.setVisibility(View.GONE);
Robert Snoeberger8bf1a3c2019-01-10 10:30:09 -0500243 }
244 View bigClockView = plugin.getBigClockView();
245 if (bigClockView != null && mBigClockContainer != null) {
246 mBigClockContainer.addView(bigClockView);
Robert Snoeberger98312392019-03-15 16:53:51 -0400247 updateBigClockVisibility();
Robert Snoeberger8bf1a3c2019-01-10 10:30:09 -0500248 }
249 // Hide default clock.
250 if (!plugin.shouldShowStatusArea()) {
251 mKeyguardStatusArea.setVisibility(View.GONE);
252 }
253 // Initialize plugin parameters.
254 mClockPlugin = plugin;
255 mClockPlugin.setStyle(getPaint().getStyle());
256 mClockPlugin.setTextColor(getCurrentTextColor());
Robert Snoeberger58f23152019-01-10 15:51:32 -0500257 mClockPlugin.setDarkAmount(mDarkAmount);
Robert Snoeberger0397c842019-02-07 14:25:46 -0500258 if (mColorPalette != null) {
259 mClockPlugin.setColorPalette(mSupportsDarkText, mColorPalette);
260 }
Robert Snoeberger8bf1a3c2019-01-10 10:30:09 -0500261 }
262
Kunhung Li29007e62018-07-30 19:30:25 +0800263 /**
Robert Snoeberger6a0140a2018-12-20 12:46:17 -0500264 * Set container for big clock face appearing behind NSSL and KeyguardStatusView.
265 */
266 public void setBigClockContainer(ViewGroup container) {
267 if (mClockPlugin != null && container != null) {
268 View bigClockView = mClockPlugin.getBigClockView();
269 if (bigClockView != null) {
270 container.addView(bigClockView);
Robert Snoeberger6a0140a2018-12-20 12:46:17 -0500271 }
272 }
273 mBigClockContainer = container;
Robert Snoeberger98312392019-03-15 16:53:51 -0400274 updateBigClockVisibility();
Robert Snoeberger6a0140a2018-12-20 12:46:17 -0500275 }
276
277 /**
Kunhung Li29007e62018-07-30 19:30:25 +0800278 * It will also update plugin setStyle if plugin is connected.
279 */
280 public void setStyle(Style style) {
281 mClockView.getPaint().setStyle(style);
Robert Snoebergerf9030c72019-04-22 16:22:49 -0400282 mClockViewBold.getPaint().setStyle(style);
Kunhung Li29007e62018-07-30 19:30:25 +0800283 if (mClockPlugin != null) {
284 mClockPlugin.setStyle(style);
285 }
286 }
287
288 /**
289 * It will also update plugin setTextColor if plugin is connected.
290 */
291 public void setTextColor(int color) {
292 mClockView.setTextColor(color);
Robert Snoebergerf9030c72019-04-22 16:22:49 -0400293 mClockViewBold.setTextColor(color);
Kunhung Li29007e62018-07-30 19:30:25 +0800294 if (mClockPlugin != null) {
295 mClockPlugin.setTextColor(color);
296 }
297 }
298
299 public void setShowCurrentUserTime(boolean showCurrentUserTime) {
300 mClockView.setShowCurrentUserTime(showCurrentUserTime);
Robert Snoebergerf9030c72019-04-22 16:22:49 -0400301 mClockViewBold.setShowCurrentUserTime(showCurrentUserTime);
Kunhung Li29007e62018-07-30 19:30:25 +0800302 }
303
Kunhung Li29007e62018-07-30 19:30:25 +0800304 public void setTextSize(int unit, float size) {
305 mClockView.setTextSize(unit, size);
306 }
307
308 public void setFormat12Hour(CharSequence format) {
309 mClockView.setFormat12Hour(format);
Robert Snoebergerf9030c72019-04-22 16:22:49 -0400310 mClockViewBold.setFormat12Hour(format);
Kunhung Li29007e62018-07-30 19:30:25 +0800311 }
312
313 public void setFormat24Hour(CharSequence format) {
314 mClockView.setFormat24Hour(format);
Robert Snoebergerf9030c72019-04-22 16:22:49 -0400315 mClockViewBold.setFormat24Hour(format);
Kunhung Li29007e62018-07-30 19:30:25 +0800316 }
317
Robert Snoebergere32efd72018-11-12 08:38:34 -0500318 /**
319 * Set the amount (ratio) that the device has transitioned to doze.
Robert Snoeberger98312392019-03-15 16:53:51 -0400320 *
Robert Snoebergere32efd72018-11-12 08:38:34 -0500321 * @param darkAmount Amount of transition to doze: 1f for doze and 0f for awake.
322 */
323 public void setDarkAmount(float darkAmount) {
Robert Snoeberger58f23152019-01-10 15:51:32 -0500324 mDarkAmount = darkAmount;
Robert Snoebergere32efd72018-11-12 08:38:34 -0500325 if (mClockPlugin != null) {
326 mClockPlugin.setDarkAmount(darkAmount);
327 }
328 }
329
Kunhung Li29007e62018-07-30 19:30:25 +0800330 public Paint getPaint() {
331 return mClockView.getPaint();
332 }
333
334 public int getCurrentTextColor() {
335 return mClockView.getCurrentTextColor();
336 }
337
338 public float getTextSize() {
339 return mClockView.getTextSize();
340 }
341
Robert Snoebergerae926732019-03-21 11:40:16 -0400342 /**
Robert Snoeberger69956802019-04-16 16:55:21 -0400343 * Returns the preferred Y position of the clock.
344 *
345 * @param totalHeight Height of the parent container.
346 * @return preferred Y position.
347 */
348 int getPreferredY(int totalHeight) {
349 if (mClockPlugin != null) {
350 return mClockPlugin.getPreferredY(totalHeight);
351 } else {
352 return totalHeight / 2;
353 }
354 }
355
356 /**
Robert Snoebergerae926732019-03-21 11:40:16 -0400357 * Refresh the time of the clock, due to either time tick broadcast or doze time tick alarm.
358 */
Kunhung Li29007e62018-07-30 19:30:25 +0800359 public void refresh() {
360 mClockView.refresh();
Robert Snoebergerf9030c72019-04-22 16:22:49 -0400361 mClockViewBold.refresh();
Robert Snoebergerffbe3152018-11-08 15:53:27 -0500362 if (mClockPlugin != null) {
Robert Snoeberger9ad03f42019-02-28 14:47:49 -0500363 mClockPlugin.onTimeTick();
Robert Snoebergerffbe3152018-11-08 15:53:27 -0500364 }
Lucas Dupinf69aa772019-04-26 11:05:23 -0700365 if (Build.IS_DEBUGGABLE) {
366 // Log for debugging b/130888082 (sysui waking up, but clock not updating)
367 Log.d(TAG, "Updating clock: " + mClockView.getText());
368 }
Robert Snoebergerffbe3152018-11-08 15:53:27 -0500369 }
370
371 /**
Robert Snoeberger9c1074f2018-12-07 17:35:21 -0500372 * Notifies that the time zone has changed.
373 */
374 public void onTimeZoneChanged(TimeZone timeZone) {
375 if (mClockPlugin != null) {
376 mClockPlugin.onTimeZoneChanged(timeZone);
377 }
378 }
379
Robert Snoebergerbe35b762019-03-15 14:33:02 -0400380 private void updateColors() {
381 ColorExtractor.GradientColors colors = mSysuiColorExtractor.getColors(
Lucas Dupina476c792019-06-10 18:00:22 -0700382 WallpaperManager.FLAG_LOCK);
Robert Snoeberger0397c842019-02-07 14:25:46 -0500383 mSupportsDarkText = colors.supportsDarkText();
384 mColorPalette = colors.getColorPalette();
385 if (mClockPlugin != null) {
386 mClockPlugin.setColorPalette(mSupportsDarkText, mColorPalette);
387 }
388 }
389
Robert Snoeberger98312392019-03-15 16:53:51 -0400390 private void updateBigClockVisibility() {
391 if (mBigClockContainer == null) {
392 return;
393 }
394 final boolean inDisplayState = mStatusBarState == StatusBarState.KEYGUARD
395 || mStatusBarState == StatusBarState.SHADE_LOCKED;
396 final int visibility =
397 inDisplayState && mBigClockContainer.getChildCount() != 0 ? View.VISIBLE
398 : View.GONE;
399 if (mBigClockContainer.getVisibility() != visibility) {
400 mBigClockContainer.setVisibility(visibility);
401 }
402 }
403
Lucas Dupine570af62019-02-10 14:52:30 -0800404 /**
Robert Snoeberger98312392019-03-15 16:53:51 -0400405 * Sets if the keyguard slice is showing a center-aligned header. We need a smaller clock in
Robert Snoebergerf9030c72019-04-22 16:22:49 -0400406 * these cases.
Lucas Dupine570af62019-02-10 14:52:30 -0800407 */
Robert Snoeberger7cfa9dd2019-05-06 17:41:36 -0400408 void setKeyguardShowingHeader(boolean hasHeader) {
Lucas Dupine570af62019-02-10 14:52:30 -0800409 if (mShowingHeader == hasHeader || hasCustomClock()) {
410 return;
411 }
412 mShowingHeader = hasHeader;
413
Robert Snoeberger7cfa9dd2019-05-06 17:41:36 -0400414 float smallFontSize = mContext.getResources().getDimensionPixelSize(
415 R.dimen.widget_small_font_size);
416 float bigFontSize = mContext.getResources().getDimensionPixelSize(
417 R.dimen.widget_big_font_size);
418 mClockTransition.setScale(smallFontSize / bigFontSize);
419 mBoldClockTransition.setScale(bigFontSize / smallFontSize);
420
Robert Snoebergerb66e9822019-05-16 11:14:43 -0400421 // End any current transitions before starting a new transition so that the new transition
422 // starts from a good state instead of a potentially bad intermediate state arrived at
423 // during a transition animation.
424 TransitionManager.endTransitions((ViewGroup) mClockView.getParent());
Robert Snoeberger7cfa9dd2019-05-06 17:41:36 -0400425
426 if (hasHeader) {
427 // After the transition, make the default clock GONE so that it doesn't make the
428 // KeyguardStatusView appear taller in KeyguardClockPositionAlgorithm and elsewhere.
429 mTransition.addListener(new TransitionListenerAdapter() {
430 @Override
431 public void onTransitionEnd(Transition transition) {
432 super.onTransitionEnd(transition);
433 // Check that header is actually showing. I saw issues where this event was
434 // fired after the big clock transitioned back to visible, which causes the time
435 // to completely disappear.
436 if (mShowingHeader) {
437 mClockView.setVisibility(View.GONE);
438 }
439 transition.removeListener(this);
440 }
441 });
442 }
Robert Snoebergerb66e9822019-05-16 11:14:43 -0400443
444 TransitionManager.beginDelayedTransition((ViewGroup) mClockView.getParent(), mTransition);
445 mClockView.setVisibility(hasHeader ? View.INVISIBLE : View.VISIBLE);
446 mClockViewBold.setVisibility(hasHeader ? View.VISIBLE : View.INVISIBLE);
447 int paddingBottom = mContext.getResources().getDimensionPixelSize(hasHeader
448 ? R.dimen.widget_vertical_padding_clock : R.dimen.title_clock_padding);
449 mClockView.setPadding(mClockView.getPaddingLeft(), mClockView.getPaddingTop(),
450 mClockView.getPaddingRight(), paddingBottom);
451 mClockViewBold.setPadding(mClockViewBold.getPaddingLeft(), mClockViewBold.getPaddingTop(),
452 mClockViewBold.getPaddingRight(), paddingBottom);
Lucas Dupine570af62019-02-10 14:52:30 -0800453 }
454
Robert Snoeberger98312392019-03-15 16:53:51 -0400455 @VisibleForTesting(otherwise = VisibleForTesting.NONE)
Robert Snoeberger15b4af12019-01-18 15:37:27 -0500456 ClockManager.ClockChangedListener getClockChangedListener() {
457 return mClockChangedListener;
Kunhung Li29007e62018-07-30 19:30:25 +0800458 }
Robert Snoeberger60854082019-01-04 13:13:17 -0500459
Robert Snoeberger98312392019-03-15 16:53:51 -0400460 @VisibleForTesting(otherwise = VisibleForTesting.NONE)
Robert Snoeberger60854082019-01-04 13:13:17 -0500461 StatusBarStateController.StateListener getStateListener() {
462 return mStateListener;
463 }
Lucas Dupine570af62019-02-10 14:52:30 -0800464
Lucas Dupin43499522019-03-04 16:45:58 -0800465 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
466 pw.println("KeyguardClockSwitch:");
467 pw.println(" mClockPlugin: " + mClockPlugin);
468 pw.println(" mClockView: " + mClockView);
Robert Snoebergerf9030c72019-04-22 16:22:49 -0400469 pw.println(" mClockViewBold: " + mClockViewBold);
Lucas Dupin43499522019-03-04 16:45:58 -0800470 pw.println(" mSmallClockFrame: " + mSmallClockFrame);
471 pw.println(" mBigClockContainer: " + mBigClockContainer);
472 pw.println(" mKeyguardStatusArea: " + mKeyguardStatusArea);
473 pw.println(" mDarkAmount: " + mDarkAmount);
474 pw.println(" mShowingHeader: " + mShowingHeader);
475 pw.println(" mSupportsDarkText: " + mSupportsDarkText);
476 pw.println(" mColorPalette: " + Arrays.toString(mColorPalette));
477 }
478
Lucas Dupine570af62019-02-10 14:52:30 -0800479 /**
Robert Snoeberger7cfa9dd2019-05-06 17:41:36 -0400480 * {@link Visibility} transformation that scales the view while it is disappearing/appearing and
481 * transitions suddenly at a cutoff fraction during the animation.
Lucas Dupine570af62019-02-10 14:52:30 -0800482 */
Robert Snoeberger7cfa9dd2019-05-06 17:41:36 -0400483 private class ClockVisibilityTransition extends android.transition.Visibility {
484
485 private static final String PROPNAME_VISIBILITY = "systemui:keyguard:visibility";
486
487 private float mCutoff;
488 private float mScale;
Lucas Dupine570af62019-02-10 14:52:30 -0800489
Robert Snoebergerf9030c72019-04-22 16:22:49 -0400490 /**
Robert Snoeberger7cfa9dd2019-05-06 17:41:36 -0400491 * Constructs a transition that switches between visible/invisible at a cutoff and scales in
492 * size while appearing/disappearing.
Robert Snoebergerf9030c72019-04-22 16:22:49 -0400493 */
Robert Snoeberger7cfa9dd2019-05-06 17:41:36 -0400494 ClockVisibilityTransition() {
495 setCutoff(1f);
496 setScale(1f);
497 }
Robert Snoebergerf9030c72019-04-22 16:22:49 -0400498
Robert Snoeberger7cfa9dd2019-05-06 17:41:36 -0400499 /**
500 * Sets the transition point between visible/invisible.
501 *
502 * @param cutoff The fraction in [0, 1] when the view switches between visible/invisible.
503 * @return This transition object
504 */
505 public ClockVisibilityTransition setCutoff(float cutoff) {
506 mCutoff = cutoff;
507 return this;
508 }
509
510 /**
511 * Sets the scale factor applied while appearing/disappearing.
512 *
513 * @param scale Scale factor applied while appearing/disappearing. When factor is less than
514 * one, the view will shrink while disappearing. When it is greater than one,
515 * the view will expand while disappearing.
516 * @return This transition object
517 */
518 public ClockVisibilityTransition setScale(float scale) {
519 mScale = scale;
520 return this;
Lucas Dupine570af62019-02-10 14:52:30 -0800521 }
522
523 @Override
Robert Snoeberger7cfa9dd2019-05-06 17:41:36 -0400524 public void captureStartValues(TransitionValues transitionValues) {
525 super.captureStartValues(transitionValues);
526 captureVisibility(transitionValues);
527 }
528
529 @Override
530 public void captureEndValues(TransitionValues transitionValues) {
531 super.captureStartValues(transitionValues);
532 captureVisibility(transitionValues);
533 }
534
535 private void captureVisibility(TransitionValues transitionValues) {
536 transitionValues.values.put(PROPNAME_VISIBILITY,
537 transitionValues.view.getVisibility());
538 }
539
540 @Override
541 public Animator onAppear(ViewGroup sceneRoot, View view, TransitionValues startValues,
Lucas Dupine570af62019-02-10 14:52:30 -0800542 TransitionValues endValues) {
Robert Snoeberger7cfa9dd2019-05-06 17:41:36 -0400543 final float cutoff = mCutoff;
544 final int startVisibility = View.INVISIBLE;
545 final int endVisibility = (int) endValues.values.get(PROPNAME_VISIBILITY);
546 final float startScale = mScale;
547 final float endScale = 1f;
548 return createAnimator(view, cutoff, startVisibility, endVisibility, startScale,
549 endScale);
550 }
Lucas Dupine570af62019-02-10 14:52:30 -0800551
Robert Snoeberger7cfa9dd2019-05-06 17:41:36 -0400552 @Override
553 public Animator onDisappear(ViewGroup sceneRoot, View view, TransitionValues startValues,
554 TransitionValues endValues) {
555 final float cutoff = 1f - mCutoff;
556 final int startVisibility = View.VISIBLE;
557 final int endVisibility = (int) endValues.values.get(PROPNAME_VISIBILITY);
558 final float startScale = 1f;
559 final float endScale = mScale;
560 return createAnimator(view, cutoff, startVisibility, endVisibility, startScale,
561 endScale);
562 }
563
564 private Animator createAnimator(View view, float cutoff, int startVisibility,
565 int endVisibility, float startScale, float endScale) {
566 view.setPivotY(view.getHeight() - view.getPaddingBottom());
Robert Snoeberger7cfa9dd2019-05-06 17:41:36 -0400567 ValueAnimator animator = ValueAnimator.ofFloat(0f, 1f);
568 animator.addUpdateListener(animation -> {
569 final float fraction = animation.getAnimatedFraction();
570 if (fraction > cutoff) {
571 view.setVisibility(endVisibility);
Lucas Dupine570af62019-02-10 14:52:30 -0800572 }
Robert Snoeberger7cfa9dd2019-05-06 17:41:36 -0400573 final float scale = MathUtils.lerp(startScale, endScale, fraction);
574 view.setScaleX(scale);
575 view.setScaleY(scale);
576 });
Robert Snoebergerb66e9822019-05-16 11:14:43 -0400577 animator.addListener(new AnimatorListenerAdapter() {
578 @Override
579 public void onAnimationStart(Animator animation) {
580 super.onAnimationStart(animation);
581 view.setVisibility(startVisibility);
582 animation.removeListener(this);
583 }
584 });
Robert Snoeberger7cfa9dd2019-05-06 17:41:36 -0400585 addListener(new TransitionListenerAdapter() {
586 @Override
587 public void onTransitionEnd(Transition transition) {
588 view.setVisibility(endVisibility);
589 view.setScaleX(1f);
590 view.setScaleY(1f);
591 transition.removeListener(this);
592 }
593 });
Lucas Dupine570af62019-02-10 14:52:30 -0800594 return animator;
595 }
596 }
Kunhung Li29007e62018-07-30 19:30:25 +0800597}