Kunhung Li | 29007e6 | 2018-07-30 19:30:25 +0800 | [diff] [blame] | 1 | package com.android.keyguard; |
| 2 | |
Lucas Dupin | e570af6 | 2019-02-10 14:52:30 -0800 | [diff] [blame] | 3 | import android.animation.Animator; |
| 4 | import android.animation.AnimatorSet; |
| 5 | import android.animation.ValueAnimator; |
Robert Snoeberger | 0397c84 | 2019-02-07 14:25:46 -0500 | [diff] [blame] | 6 | import android.app.WallpaperManager; |
Kunhung Li | 29007e6 | 2018-07-30 19:30:25 +0800 | [diff] [blame] | 7 | import android.content.Context; |
| 8 | import android.graphics.Paint; |
| 9 | import android.graphics.Paint.Style; |
Lucas Dupin | e570af6 | 2019-02-10 14:52:30 -0800 | [diff] [blame] | 10 | import android.transition.ChangeBounds; |
| 11 | import android.transition.Transition; |
| 12 | import android.transition.TransitionManager; |
| 13 | import android.transition.TransitionValues; |
Kunhung Li | 29007e6 | 2018-07-30 19:30:25 +0800 | [diff] [blame] | 14 | import android.util.AttributeSet; |
Lucas Dupin | e570af6 | 2019-02-10 14:52:30 -0800 | [diff] [blame] | 15 | import android.util.MathUtils; |
| 16 | import android.util.TypedValue; |
Kunhung Li | 29007e6 | 2018-07-30 19:30:25 +0800 | [diff] [blame] | 17 | import android.view.View; |
| 18 | import android.view.ViewGroup; |
| 19 | import android.widget.FrameLayout; |
Robert Snoeberger | e3b3e78 | 2018-12-17 13:32:15 -0500 | [diff] [blame] | 20 | import android.widget.RelativeLayout; |
Kunhung Li | 29007e6 | 2018-07-30 19:30:25 +0800 | [diff] [blame] | 21 | import android.widget.TextClock; |
| 22 | |
| 23 | import androidx.annotation.VisibleForTesting; |
| 24 | |
Robert Snoeberger | 0397c84 | 2019-02-07 14:25:46 -0500 | [diff] [blame] | 25 | import com.android.internal.colorextraction.ColorExtractor; |
Robert Snoeberger | 15b4af1 | 2019-01-18 15:37:27 -0500 | [diff] [blame] | 26 | import com.android.keyguard.clock.ClockManager; |
Kunhung Li | 29007e6 | 2018-07-30 19:30:25 +0800 | [diff] [blame] | 27 | import com.android.systemui.Dependency; |
Lucas Dupin | e570af6 | 2019-02-10 14:52:30 -0800 | [diff] [blame] | 28 | import com.android.systemui.Interpolators; |
Robert Snoeberger | 0397c84 | 2019-02-07 14:25:46 -0500 | [diff] [blame] | 29 | import com.android.systemui.colorextraction.SysuiColorExtractor; |
Kunhung Li | 29007e6 | 2018-07-30 19:30:25 +0800 | [diff] [blame] | 30 | import com.android.systemui.plugins.ClockPlugin; |
Beverly | 8fdb533 | 2019-02-04 14:29:49 -0500 | [diff] [blame] | 31 | import com.android.systemui.plugins.statusbar.StatusBarStateController; |
Robert Snoeberger | 6085408 | 2019-01-04 13:13:17 -0500 | [diff] [blame] | 32 | import com.android.systemui.statusbar.StatusBarState; |
Kunhung Li | 29007e6 | 2018-07-30 19:30:25 +0800 | [diff] [blame] | 33 | |
Robert Snoeberger | 9c1074f | 2018-12-07 17:35:21 -0500 | [diff] [blame] | 34 | import java.util.TimeZone; |
Robert Snoeberger | 33ce6d9 | 2018-10-26 10:52:38 -0400 | [diff] [blame] | 35 | |
Kunhung Li | 29007e6 | 2018-07-30 19:30:25 +0800 | [diff] [blame] | 36 | /** |
| 37 | * Switch to show plugin clock when plugin is connected, otherwise it will show default clock. |
| 38 | */ |
Robert Snoeberger | e3b3e78 | 2018-12-17 13:32:15 -0500 | [diff] [blame] | 39 | public class KeyguardClockSwitch extends RelativeLayout { |
Robert Snoeberger | 046ee9c | 2019-01-10 18:29:38 -0500 | [diff] [blame] | 40 | |
Lucas Dupin | e570af6 | 2019-02-10 14:52:30 -0800 | [diff] [blame] | 41 | private final Transition mTransition; |
Kunhung Li | 29007e6 | 2018-07-30 19:30:25 +0800 | [diff] [blame] | 42 | /** |
| 43 | * Optional/alternative clock injected via plugin. |
| 44 | */ |
| 45 | private ClockPlugin mClockPlugin; |
| 46 | /** |
| 47 | * Default clock. |
| 48 | */ |
| 49 | private TextClock mClockView; |
Robert Snoeberger | e3b3e78 | 2018-12-17 13:32:15 -0500 | [diff] [blame] | 50 | /** |
| 51 | * Frame for default and custom clock. |
| 52 | */ |
Robert Snoeberger | 6a0140a | 2018-12-20 12:46:17 -0500 | [diff] [blame] | 53 | private FrameLayout mSmallClockFrame; |
| 54 | /** |
| 55 | * Container for big custom clock. |
| 56 | */ |
| 57 | private ViewGroup mBigClockContainer; |
Robert Snoeberger | e3b3e78 | 2018-12-17 13:32:15 -0500 | [diff] [blame] | 58 | /** |
| 59 | * Status area (date and other stuff) shown below the clock. Plugin can decide whether |
| 60 | * or not to show it below the alternate clock. |
| 61 | */ |
| 62 | private View mKeyguardStatusArea; |
Robert Snoeberger | 8bf1a3c | 2019-01-10 10:30:09 -0500 | [diff] [blame] | 63 | /** |
Robert Snoeberger | 58f2315 | 2019-01-10 15:51:32 -0500 | [diff] [blame] | 64 | * Maintain state so that a newly connected plugin can be initialized. |
| 65 | */ |
| 66 | private float mDarkAmount; |
Lucas Dupin | e570af6 | 2019-02-10 14:52:30 -0800 | [diff] [blame] | 67 | /** |
| 68 | * If the Keyguard Slice has a header (big center-aligned text.) |
| 69 | */ |
| 70 | private boolean mShowingHeader; |
Robert Snoeberger | 0397c84 | 2019-02-07 14:25:46 -0500 | [diff] [blame] | 71 | private boolean mSupportsDarkText; |
| 72 | private int[] mColorPalette; |
Kunhung Li | 29007e6 | 2018-07-30 19:30:25 +0800 | [diff] [blame] | 73 | |
Robert Snoeberger | 6085408 | 2019-01-04 13:13:17 -0500 | [diff] [blame] | 74 | private final StatusBarStateController.StateListener mStateListener = |
| 75 | new StatusBarStateController.StateListener() { |
| 76 | @Override |
| 77 | public void onStateChanged(int newState) { |
| 78 | if (mBigClockContainer == null) { |
| 79 | return; |
| 80 | } |
| 81 | if (newState == StatusBarState.SHADE) { |
| 82 | if (mBigClockContainer.getVisibility() == View.VISIBLE) { |
| 83 | mBigClockContainer.setVisibility(View.INVISIBLE); |
| 84 | } |
| 85 | } else { |
| 86 | if (mBigClockContainer.getVisibility() == View.INVISIBLE) { |
| 87 | mBigClockContainer.setVisibility(View.VISIBLE); |
| 88 | } |
| 89 | } |
| 90 | } |
| 91 | }; |
Kunhung Li | 29007e6 | 2018-07-30 19:30:25 +0800 | [diff] [blame] | 92 | |
Robert Snoeberger | 15b4af1 | 2019-01-18 15:37:27 -0500 | [diff] [blame] | 93 | private ClockManager.ClockChangedListener mClockChangedListener = this::setClockPlugin; |
Robert Snoeberger | 046ee9c | 2019-01-10 18:29:38 -0500 | [diff] [blame] | 94 | |
Robert Snoeberger | 0397c84 | 2019-02-07 14:25:46 -0500 | [diff] [blame] | 95 | /** |
| 96 | * Listener for changes to the color palette. |
| 97 | * |
| 98 | * The color palette changes when the wallpaper is changed. |
| 99 | */ |
| 100 | private SysuiColorExtractor.OnColorsChangedListener mColorsListener = (extractor, which) -> { |
| 101 | if ((which & WallpaperManager.FLAG_LOCK) != 0) { |
| 102 | if (extractor instanceof SysuiColorExtractor) { |
| 103 | updateColors((SysuiColorExtractor) extractor); |
| 104 | } else { |
| 105 | updateColors(Dependency.get(SysuiColorExtractor.class)); |
| 106 | } |
| 107 | } |
| 108 | }; |
| 109 | |
Kunhung Li | 29007e6 | 2018-07-30 19:30:25 +0800 | [diff] [blame] | 110 | public KeyguardClockSwitch(Context context) { |
| 111 | this(context, null); |
| 112 | } |
| 113 | |
| 114 | public KeyguardClockSwitch(Context context, AttributeSet attrs) { |
| 115 | super(context, attrs); |
Lucas Dupin | e570af6 | 2019-02-10 14:52:30 -0800 | [diff] [blame] | 116 | mTransition = new ClockBoundsTransition(); |
Kunhung Li | 29007e6 | 2018-07-30 19:30:25 +0800 | [diff] [blame] | 117 | } |
| 118 | |
Lucas Dupin | 7fc9dc1 | 2019-01-03 09:19:43 -0800 | [diff] [blame] | 119 | /** |
| 120 | * Returns if this view is presenting a custom clock, or the default implementation. |
| 121 | */ |
| 122 | public boolean hasCustomClock() { |
| 123 | return mClockPlugin != null; |
| 124 | } |
| 125 | |
Kunhung Li | 29007e6 | 2018-07-30 19:30:25 +0800 | [diff] [blame] | 126 | @Override |
| 127 | protected void onFinishInflate() { |
| 128 | super.onFinishInflate(); |
| 129 | mClockView = findViewById(R.id.default_clock_view); |
Robert Snoeberger | 6a0140a | 2018-12-20 12:46:17 -0500 | [diff] [blame] | 130 | mSmallClockFrame = findViewById(R.id.clock_view); |
Robert Snoeberger | e3b3e78 | 2018-12-17 13:32:15 -0500 | [diff] [blame] | 131 | mKeyguardStatusArea = findViewById(R.id.keyguard_status_area); |
Kunhung Li | 29007e6 | 2018-07-30 19:30:25 +0800 | [diff] [blame] | 132 | } |
| 133 | |
| 134 | @Override |
| 135 | protected void onAttachedToWindow() { |
| 136 | super.onAttachedToWindow(); |
Robert Snoeberger | 15b4af1 | 2019-01-18 15:37:27 -0500 | [diff] [blame] | 137 | Dependency.get(ClockManager.class).addOnClockChangedListener(mClockChangedListener); |
Robert Snoeberger | 6085408 | 2019-01-04 13:13:17 -0500 | [diff] [blame] | 138 | Dependency.get(StatusBarStateController.class).addCallback(mStateListener); |
Robert Snoeberger | 0397c84 | 2019-02-07 14:25:46 -0500 | [diff] [blame] | 139 | SysuiColorExtractor colorExtractor = Dependency.get(SysuiColorExtractor.class); |
| 140 | colorExtractor.addOnColorsChangedListener(mColorsListener); |
| 141 | updateColors(colorExtractor); |
Kunhung Li | 29007e6 | 2018-07-30 19:30:25 +0800 | [diff] [blame] | 142 | } |
| 143 | |
| 144 | @Override |
| 145 | protected void onDetachedFromWindow() { |
| 146 | super.onDetachedFromWindow(); |
Robert Snoeberger | 15b4af1 | 2019-01-18 15:37:27 -0500 | [diff] [blame] | 147 | Dependency.get(ClockManager.class).removeOnClockChangedListener(mClockChangedListener); |
Robert Snoeberger | 6085408 | 2019-01-04 13:13:17 -0500 | [diff] [blame] | 148 | Dependency.get(StatusBarStateController.class).removeCallback(mStateListener); |
Robert Snoeberger | 0397c84 | 2019-02-07 14:25:46 -0500 | [diff] [blame] | 149 | Dependency.get(SysuiColorExtractor.class) |
| 150 | .removeOnColorsChangedListener(mColorsListener); |
Kunhung Li | 29007e6 | 2018-07-30 19:30:25 +0800 | [diff] [blame] | 151 | } |
| 152 | |
Robert Snoeberger | 8bf1a3c | 2019-01-10 10:30:09 -0500 | [diff] [blame] | 153 | private void setClockPlugin(ClockPlugin plugin) { |
| 154 | // Disconnect from existing plugin. |
| 155 | if (mClockPlugin != null) { |
| 156 | View smallClockView = mClockPlugin.getView(); |
| 157 | if (smallClockView != null && smallClockView.getParent() == mSmallClockFrame) { |
| 158 | mSmallClockFrame.removeView(smallClockView); |
| 159 | } |
| 160 | if (mBigClockContainer != null) { |
| 161 | mBigClockContainer.removeAllViews(); |
| 162 | mBigClockContainer.setVisibility(View.GONE); |
| 163 | } |
| 164 | mClockPlugin = null; |
| 165 | } |
| 166 | if (plugin == null) { |
| 167 | mClockView.setVisibility(View.VISIBLE); |
| 168 | mKeyguardStatusArea.setVisibility(View.VISIBLE); |
| 169 | return; |
| 170 | } |
| 171 | // Attach small and big clock views to hierarchy. |
| 172 | View smallClockView = plugin.getView(); |
| 173 | if (smallClockView != null) { |
| 174 | mSmallClockFrame.addView(smallClockView, -1, |
| 175 | new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, |
| 176 | ViewGroup.LayoutParams.WRAP_CONTENT)); |
| 177 | mClockView.setVisibility(View.GONE); |
| 178 | } |
| 179 | View bigClockView = plugin.getBigClockView(); |
| 180 | if (bigClockView != null && mBigClockContainer != null) { |
| 181 | mBigClockContainer.addView(bigClockView); |
| 182 | mBigClockContainer.setVisibility(View.VISIBLE); |
| 183 | } |
| 184 | // Hide default clock. |
| 185 | if (!plugin.shouldShowStatusArea()) { |
| 186 | mKeyguardStatusArea.setVisibility(View.GONE); |
| 187 | } |
| 188 | // Initialize plugin parameters. |
| 189 | mClockPlugin = plugin; |
| 190 | mClockPlugin.setStyle(getPaint().getStyle()); |
| 191 | mClockPlugin.setTextColor(getCurrentTextColor()); |
Robert Snoeberger | 58f2315 | 2019-01-10 15:51:32 -0500 | [diff] [blame] | 192 | mClockPlugin.setDarkAmount(mDarkAmount); |
Robert Snoeberger | 0397c84 | 2019-02-07 14:25:46 -0500 | [diff] [blame] | 193 | if (mColorPalette != null) { |
| 194 | mClockPlugin.setColorPalette(mSupportsDarkText, mColorPalette); |
| 195 | } |
Robert Snoeberger | 8bf1a3c | 2019-01-10 10:30:09 -0500 | [diff] [blame] | 196 | } |
| 197 | |
Kunhung Li | 29007e6 | 2018-07-30 19:30:25 +0800 | [diff] [blame] | 198 | /** |
Robert Snoeberger | 6a0140a | 2018-12-20 12:46:17 -0500 | [diff] [blame] | 199 | * Set container for big clock face appearing behind NSSL and KeyguardStatusView. |
| 200 | */ |
| 201 | public void setBigClockContainer(ViewGroup container) { |
| 202 | if (mClockPlugin != null && container != null) { |
| 203 | View bigClockView = mClockPlugin.getBigClockView(); |
| 204 | if (bigClockView != null) { |
| 205 | container.addView(bigClockView); |
Robert Snoeberger | a1df7fb | 2019-02-11 14:00:14 -0500 | [diff] [blame] | 206 | if (container.getVisibility() == View.GONE) { |
| 207 | container.setVisibility(View.VISIBLE); |
| 208 | } |
Robert Snoeberger | 6a0140a | 2018-12-20 12:46:17 -0500 | [diff] [blame] | 209 | } |
| 210 | } |
| 211 | mBigClockContainer = container; |
| 212 | } |
| 213 | |
| 214 | /** |
Kunhung Li | 29007e6 | 2018-07-30 19:30:25 +0800 | [diff] [blame] | 215 | * It will also update plugin setStyle if plugin is connected. |
| 216 | */ |
| 217 | public void setStyle(Style style) { |
| 218 | mClockView.getPaint().setStyle(style); |
| 219 | if (mClockPlugin != null) { |
| 220 | mClockPlugin.setStyle(style); |
| 221 | } |
| 222 | } |
| 223 | |
| 224 | /** |
| 225 | * It will also update plugin setTextColor if plugin is connected. |
| 226 | */ |
| 227 | public void setTextColor(int color) { |
| 228 | mClockView.setTextColor(color); |
| 229 | if (mClockPlugin != null) { |
| 230 | mClockPlugin.setTextColor(color); |
| 231 | } |
| 232 | } |
| 233 | |
| 234 | public void setShowCurrentUserTime(boolean showCurrentUserTime) { |
| 235 | mClockView.setShowCurrentUserTime(showCurrentUserTime); |
| 236 | } |
| 237 | |
Kunhung Li | 29007e6 | 2018-07-30 19:30:25 +0800 | [diff] [blame] | 238 | public void setTextSize(int unit, float size) { |
| 239 | mClockView.setTextSize(unit, size); |
| 240 | } |
| 241 | |
| 242 | public void setFormat12Hour(CharSequence format) { |
| 243 | mClockView.setFormat12Hour(format); |
| 244 | } |
| 245 | |
| 246 | public void setFormat24Hour(CharSequence format) { |
| 247 | mClockView.setFormat24Hour(format); |
| 248 | } |
| 249 | |
Robert Snoeberger | e32efd7 | 2018-11-12 08:38:34 -0500 | [diff] [blame] | 250 | /** |
| 251 | * Set the amount (ratio) that the device has transitioned to doze. |
| 252 | * @param darkAmount Amount of transition to doze: 1f for doze and 0f for awake. |
| 253 | */ |
| 254 | public void setDarkAmount(float darkAmount) { |
Robert Snoeberger | 58f2315 | 2019-01-10 15:51:32 -0500 | [diff] [blame] | 255 | mDarkAmount = darkAmount; |
Robert Snoeberger | e32efd7 | 2018-11-12 08:38:34 -0500 | [diff] [blame] | 256 | if (mClockPlugin != null) { |
| 257 | mClockPlugin.setDarkAmount(darkAmount); |
| 258 | } |
| 259 | } |
| 260 | |
Kunhung Li | 29007e6 | 2018-07-30 19:30:25 +0800 | [diff] [blame] | 261 | public Paint getPaint() { |
| 262 | return mClockView.getPaint(); |
| 263 | } |
| 264 | |
| 265 | public int getCurrentTextColor() { |
| 266 | return mClockView.getCurrentTextColor(); |
| 267 | } |
| 268 | |
| 269 | public float getTextSize() { |
| 270 | return mClockView.getTextSize(); |
| 271 | } |
| 272 | |
| 273 | public void refresh() { |
| 274 | mClockView.refresh(); |
| 275 | } |
| 276 | |
| 277 | /** |
Robert Snoeberger | ffbe315 | 2018-11-08 15:53:27 -0500 | [diff] [blame] | 278 | * Notifies that time tick alarm from doze service fired. |
| 279 | */ |
| 280 | public void dozeTimeTick() { |
| 281 | if (mClockPlugin != null) { |
| 282 | mClockPlugin.dozeTimeTick(); |
| 283 | } |
| 284 | } |
| 285 | |
| 286 | /** |
Robert Snoeberger | 9c1074f | 2018-12-07 17:35:21 -0500 | [diff] [blame] | 287 | * Notifies that the time zone has changed. |
| 288 | */ |
| 289 | public void onTimeZoneChanged(TimeZone timeZone) { |
| 290 | if (mClockPlugin != null) { |
| 291 | mClockPlugin.onTimeZoneChanged(timeZone); |
| 292 | } |
| 293 | } |
| 294 | |
Robert Snoeberger | 0397c84 | 2019-02-07 14:25:46 -0500 | [diff] [blame] | 295 | private void updateColors(SysuiColorExtractor colorExtractor) { |
| 296 | ColorExtractor.GradientColors colors = colorExtractor.getColors(WallpaperManager.FLAG_LOCK, |
| 297 | true); |
| 298 | mSupportsDarkText = colors.supportsDarkText(); |
| 299 | mColorPalette = colors.getColorPalette(); |
| 300 | if (mClockPlugin != null) { |
| 301 | mClockPlugin.setColorPalette(mSupportsDarkText, mColorPalette); |
| 302 | } |
| 303 | } |
| 304 | |
Lucas Dupin | e570af6 | 2019-02-10 14:52:30 -0800 | [diff] [blame] | 305 | /** |
| 306 | * Sets if the keyguard slice is showing a center-aligned header. We need a smaller clock |
| 307 | * in these cases. |
| 308 | */ |
| 309 | public void setKeyguardShowingHeader(boolean hasHeader) { |
| 310 | if (mShowingHeader == hasHeader || hasCustomClock()) { |
| 311 | return; |
| 312 | } |
| 313 | mShowingHeader = hasHeader; |
| 314 | |
| 315 | TransitionManager.beginDelayedTransition((ViewGroup) mClockView.getParent(), mTransition); |
| 316 | int fontSize = mContext.getResources().getDimensionPixelSize(mShowingHeader |
| 317 | ? R.dimen.widget_small_font_size : R.dimen.widget_big_font_size); |
| 318 | int paddingBottom = mContext.getResources().getDimensionPixelSize(mShowingHeader |
| 319 | ? R.dimen.widget_vertical_padding_clock : R.dimen.header_subtitle_padding); |
| 320 | mClockView.setTextSize(TypedValue.COMPLEX_UNIT_PX, fontSize); |
| 321 | mClockView.setPadding(mClockView.getPaddingLeft(), mClockView.getPaddingTop(), |
| 322 | mClockView.getPaddingRight(), paddingBottom); |
| 323 | } |
| 324 | |
Kunhung Li | 29007e6 | 2018-07-30 19:30:25 +0800 | [diff] [blame] | 325 | @VisibleForTesting (otherwise = VisibleForTesting.NONE) |
Robert Snoeberger | 15b4af1 | 2019-01-18 15:37:27 -0500 | [diff] [blame] | 326 | ClockManager.ClockChangedListener getClockChangedListener() { |
| 327 | return mClockChangedListener; |
Kunhung Li | 29007e6 | 2018-07-30 19:30:25 +0800 | [diff] [blame] | 328 | } |
Robert Snoeberger | 6085408 | 2019-01-04 13:13:17 -0500 | [diff] [blame] | 329 | |
| 330 | @VisibleForTesting (otherwise = VisibleForTesting.NONE) |
| 331 | StatusBarStateController.StateListener getStateListener() { |
| 332 | return mStateListener; |
| 333 | } |
Lucas Dupin | e570af6 | 2019-02-10 14:52:30 -0800 | [diff] [blame] | 334 | |
| 335 | /** |
| 336 | * Special layout transition that scales the clock view as its bounds change, to make it look |
| 337 | * like the text is shrinking. |
| 338 | */ |
| 339 | private class ClockBoundsTransition extends ChangeBounds { |
| 340 | |
| 341 | ClockBoundsTransition() { |
| 342 | setDuration(KeyguardSliceView.DEFAULT_ANIM_DURATION / 2); |
| 343 | setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN); |
| 344 | } |
| 345 | |
| 346 | @Override |
| 347 | public Animator createAnimator(ViewGroup sceneRoot, TransitionValues startValues, |
| 348 | TransitionValues endValues) { |
| 349 | Animator animator = super.createAnimator(sceneRoot, startValues, endValues); |
| 350 | if (animator == null || startValues.view != mClockView) { |
| 351 | return animator; |
| 352 | } |
| 353 | |
| 354 | ValueAnimator boundsAnimator = null; |
| 355 | if (animator instanceof AnimatorSet) { |
| 356 | Animator first = ((AnimatorSet) animator).getChildAnimations().get(0); |
| 357 | if (first instanceof ValueAnimator) { |
| 358 | boundsAnimator = (ValueAnimator) first; |
| 359 | } |
| 360 | } else if (animator instanceof ValueAnimator) { |
| 361 | boundsAnimator = (ValueAnimator) animator; |
| 362 | } |
| 363 | |
| 364 | if (boundsAnimator != null) { |
| 365 | float bigFontSize = mContext.getResources() |
| 366 | .getDimensionPixelSize(R.dimen.widget_big_font_size); |
| 367 | float smallFontSize = mContext.getResources() |
| 368 | .getDimensionPixelSize(R.dimen.widget_small_font_size); |
| 369 | float startScale = mShowingHeader |
| 370 | ? bigFontSize / smallFontSize : smallFontSize / bigFontSize; |
| 371 | boundsAnimator.addUpdateListener(animation -> { |
| 372 | float scale = MathUtils.lerp(startScale, 1f /* stop */, |
| 373 | animation.getAnimatedFraction()); |
| 374 | mClockView.setPivotX(mClockView.getWidth() / 2); |
| 375 | mClockView.setPivotY(0); |
| 376 | mClockView.setScaleX(scale); |
| 377 | mClockView.setScaleY(scale); |
| 378 | }); |
| 379 | } |
| 380 | |
| 381 | return animator; |
| 382 | } |
| 383 | } |
Kunhung Li | 29007e6 | 2018-07-30 19:30:25 +0800 | [diff] [blame] | 384 | } |