blob: 4e91e4c84e9927fb9f1496162f6a3269c9b3f8e5 [file] [log] [blame]
Jorim Jaggi7d16bb12014-05-22 04:24:50 +02001/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License
15 */
16
17package com.android.systemui.statusbar.phone;
18
Lucas Dupin7da4f262018-09-20 13:41:46 -070019import static com.android.systemui.doze.util.BurnInHelperKt.getBurnInOffset;
Adrian Roosdc747bd2017-06-01 16:09:15 -070020import static com.android.systemui.statusbar.notification.NotificationUtils.interpolate;
21
Jorim Jaggi7d16bb12014-05-22 04:24:50 +020022import android.content.res.Resources;
Lucas Dupind285cf02018-01-18 09:18:23 -080023import android.util.MathUtils;
Jorim Jaggi7d16bb12014-05-22 04:24:50 +020024
Lucas Dupin60661a62018-04-12 10:50:13 -070025import com.android.keyguard.KeyguardStatusView;
Lucas Dupin41ff6952018-02-18 19:39:32 -080026import com.android.systemui.Interpolators;
Jorim Jaggi7d16bb12014-05-22 04:24:50 +020027import com.android.systemui.R;
28
29/**
30 * Utility class to calculate the clock position and top padding of notifications on Keyguard.
31 */
32public class KeyguardClockPositionAlgorithm {
33
Lucas Dupin41ff6952018-02-18 19:39:32 -080034 /**
35 * How much the clock height influences the shade position.
36 * 0 means nothing, 1 means move the shade up by the height of the clock
37 * 0.5f means move the shade up by half of the size of the clock.
38 */
39 private static float CLOCK_HEIGHT_WEIGHT = 0.7f;
40
41 /**
42 * Margin between the bottom of the clock and the notification shade.
43 */
Lucas Dupind285cf02018-01-18 09:18:23 -080044 private int mClockNotificationsMargin;
Lucas Dupin41ff6952018-02-18 19:39:32 -080045
46 /**
Lucas Dupin41ff6952018-02-18 19:39:32 -080047 * Height of the parent view - display size in px.
48 */
Jorim Jaggi7d16bb12014-05-22 04:24:50 +020049 private int mHeight;
Lucas Dupin41ff6952018-02-18 19:39:32 -080050
51 /**
52 * Height of {@link KeyguardStatusView}.
53 */
Jorim Jaggi7d16bb12014-05-22 04:24:50 +020054 private int mKeyguardStatusHeight;
Lucas Dupin41ff6952018-02-18 19:39:32 -080055
56 /**
Robert Snoeberger69956802019-04-16 16:55:21 -040057 * Preferred Y position of clock.
58 */
59 private int mClockPreferredY;
60
61 /**
Robert Snoeberger168949a2019-04-18 09:39:42 -040062 * Whether or not there is a custom clock face on keyguard.
63 */
64 private boolean mHasCustomClock;
65
66 /**
67 * Whether or not the NSSL contains any visible notifications.
68 */
69 private boolean mHasVisibleNotifs;
70
71 /**
Lucas Dupin41ff6952018-02-18 19:39:32 -080072 * Height of notification stack: Sum of height of each notification.
73 */
74 private int mNotificationStackHeight;
75
76 /**
77 * Minimum top margin to avoid overlap with status bar.
78 */
79 private int mMinTopMargin;
80
81 /**
82 * Maximum bottom padding to avoid overlap with {@link KeyguardBottomAreaView} or
83 * the ambient indication.
84 */
85 private int mMaxShadeBottom;
86
87 /**
Lucas Dupinbc9aac12018-03-04 20:18:15 -080088 * Minimum distance from the status bar.
Lucas Dupin41ff6952018-02-18 19:39:32 -080089 */
Lucas Dupinbc9aac12018-03-04 20:18:15 -080090 private int mContainerTopPadding;
Lucas Dupin41ff6952018-02-18 19:39:32 -080091
92 /**
Lucas Dupin60661a62018-04-12 10:50:13 -070093 * @see NotificationPanelView#getExpandedFraction()
Lucas Dupin41ff6952018-02-18 19:39:32 -080094 */
Lucas Dupin60661a62018-04-12 10:50:13 -070095 private float mPanelExpansion;
Lucas Dupin41ff6952018-02-18 19:39:32 -080096
97 /**
98 * Burn-in prevention x translation.
99 */
Adrian Roosdc747bd2017-06-01 16:09:15 -0700100 private int mBurnInPreventionOffsetX;
Lucas Dupin41ff6952018-02-18 19:39:32 -0800101
102 /**
103 * Burn-in prevention y translation.
104 */
Adrian Roosdc747bd2017-06-01 16:09:15 -0700105 private int mBurnInPreventionOffsetY;
Jorim Jaggi7d16bb12014-05-22 04:24:50 +0200106
107 /**
Lucas Dupin41ff6952018-02-18 19:39:32 -0800108 * Doze/AOD transition amount.
Jorim Jaggi7d16bb12014-05-22 04:24:50 +0200109 */
Adrian Roos52414e32017-04-28 09:23:19 -0700110 private float mDarkAmount;
Selim Cinekf99d0002014-06-13 07:36:01 +0200111
Lucas Dupin55c6e802018-09-27 18:07:36 -0700112 private float mEmptyDragAmount;
Lucas Dupin4c2aa392018-03-28 18:00:45 -0700113
114 /**
Selim Cinekb0fada62019-06-17 19:03:59 -0700115 * Setting if bypass is enabled. If true the clock should always be positioned like it's dark
116 * and other minor adjustments.
Selim Cinekc1d9ab22019-05-21 18:08:30 -0700117 */
Selim Cinekb0fada62019-06-17 19:03:59 -0700118 private boolean mBypassEnabled;
119
120 /**
121 * The stackscroller padding when unlocked
122 */
123 private int mUnlockedStackScrollerPadding;
Selim Cinekc1d9ab22019-05-21 18:08:30 -0700124
125 /**
Jorim Jaggi7d16bb12014-05-22 04:24:50 +0200126 * Refreshes the dimension values.
127 */
128 public void loadDimens(Resources res) {
Lucas Dupind285cf02018-01-18 09:18:23 -0800129 mClockNotificationsMargin = res.getDimensionPixelSize(
130 R.dimen.keyguard_clock_notifications_margin);
Robert Snoeberger69969c22019-05-02 16:44:11 -0400131 // Consider the lock icon when determining the minimum top padding between the status bar
132 // and top of the clock.
133 mContainerTopPadding = Math.max(res.getDimensionPixelSize(
134 R.dimen.keyguard_clock_top_margin),
135 res.getDimensionPixelSize(R.dimen.keyguard_lock_height)
136 + res.getDimensionPixelSize(R.dimen.keyguard_lock_padding)
137 + res.getDimensionPixelSize(R.dimen.keyguard_clock_lock_margin));
Adrian Roosdc747bd2017-06-01 16:09:15 -0700138 mBurnInPreventionOffsetX = res.getDimensionPixelSize(
139 R.dimen.burn_in_prevention_offset_x);
140 mBurnInPreventionOffsetY = res.getDimensionPixelSize(
141 R.dimen.burn_in_prevention_offset_y);
Jorim Jaggi7d16bb12014-05-22 04:24:50 +0200142 }
143
Lucas Dupin41ff6952018-02-18 19:39:32 -0800144 public void setup(int minTopMargin, int maxShadeBottom, int notificationStackHeight,
Robert Snoeberger69956802019-04-16 16:55:21 -0400145 float panelExpansion, int parentHeight, int keyguardStatusHeight, int clockPreferredY,
Selim Cinekc1d9ab22019-05-21 18:08:30 -0700146 boolean hasCustomClock, boolean hasVisibleNotifs, float dark, float emptyDragAmount,
Selim Cinekb0fada62019-06-17 19:03:59 -0700147 boolean bypassEnabled, int unlockedStackScrollerPadding) {
Lucas Dupinbc9aac12018-03-04 20:18:15 -0800148 mMinTopMargin = minTopMargin + mContainerTopPadding;
Lucas Dupin41ff6952018-02-18 19:39:32 -0800149 mMaxShadeBottom = maxShadeBottom;
150 mNotificationStackHeight = notificationStackHeight;
Lucas Dupin60661a62018-04-12 10:50:13 -0700151 mPanelExpansion = panelExpansion;
Lucas Dupin41ff6952018-02-18 19:39:32 -0800152 mHeight = parentHeight;
Jorim Jaggi7d16bb12014-05-22 04:24:50 +0200153 mKeyguardStatusHeight = keyguardStatusHeight;
Robert Snoeberger69956802019-04-16 16:55:21 -0400154 mClockPreferredY = clockPreferredY;
Robert Snoeberger168949a2019-04-18 09:39:42 -0400155 mHasCustomClock = hasCustomClock;
156 mHasVisibleNotifs = hasVisibleNotifs;
Adrian Roos52414e32017-04-28 09:23:19 -0700157 mDarkAmount = dark;
Lucas Dupin55c6e802018-09-27 18:07:36 -0700158 mEmptyDragAmount = emptyDragAmount;
Selim Cinekb0fada62019-06-17 19:03:59 -0700159 mBypassEnabled = bypassEnabled;
160 mUnlockedStackScrollerPadding = unlockedStackScrollerPadding;
Selim Cinek5f71bee2015-11-18 10:25:23 -0800161 }
162
Jorim Jaggi7d16bb12014-05-22 04:24:50 +0200163 public void run(Result result) {
Selim Cinekdb6d6df2019-05-22 20:39:59 -0700164 final int y = getClockY(mPanelExpansion);
Lucas Dupind285cf02018-01-18 09:18:23 -0800165 result.clockY = y;
Lucas Dupin41ff6952018-02-18 19:39:32 -0800166 result.clockAlpha = getClockAlpha(y);
Selim Cinekb0fada62019-06-17 19:03:59 -0700167 result.stackScrollerPadding = mBypassEnabled ? mUnlockedStackScrollerPadding
168 : y + mKeyguardStatusHeight;
169 result.stackScrollerPaddingExpanded = mBypassEnabled ? mUnlockedStackScrollerPadding
170 : getClockY(1.0f) + mKeyguardStatusHeight;
Adrian Roosdc747bd2017-06-01 16:09:15 -0700171 result.clockX = (int) interpolate(0, burnInPreventionOffsetX(), mDarkAmount);
Selim Cinekf99d0002014-06-13 07:36:01 +0200172 }
173
Lucas Dupin41ff6952018-02-18 19:39:32 -0800174 public float getMinStackScrollerPadding() {
Selim Cinekb0fada62019-06-17 19:03:59 -0700175 return mBypassEnabled ? mUnlockedStackScrollerPadding
176 : mMinTopMargin + mKeyguardStatusHeight + mClockNotificationsMargin;
Jorim Jaggi7d16bb12014-05-22 04:24:50 +0200177 }
178
Lucas Dupin41ff6952018-02-18 19:39:32 -0800179 private int getMaxClockY() {
180 return mHeight / 2 - mKeyguardStatusHeight - mClockNotificationsMargin;
181 }
182
Robert Snoeberger69956802019-04-16 16:55:21 -0400183 private int getPreferredClockY() {
Robert Snoeberger4cbd1592019-04-24 14:20:38 -0400184 return mClockPreferredY;
185 }
186
187 private int getExpandedPreferredClockY() {
Selim Cinekb0fada62019-06-17 19:03:59 -0700188 return (mHasCustomClock && (!mHasVisibleNotifs || mBypassEnabled)) ? getPreferredClockY()
Robert Snoeberger4cbd1592019-04-24 14:20:38 -0400189 : getExpandedClockPosition();
Robert Snoeberger69956802019-04-16 16:55:21 -0400190 }
191
Lucas Dupin41ff6952018-02-18 19:39:32 -0800192 /**
193 * Vertically align the clock and the shade in the available space considering only
194 * a percentage of the clock height defined by {@code CLOCK_HEIGHT_WEIGHT}.
195 * @return Clock Y in pixels.
196 */
Lucas Dupin60661a62018-04-12 10:50:13 -0700197 public int getExpandedClockPosition() {
Lucas Dupin41ff6952018-02-18 19:39:32 -0800198 final int availableHeight = mMaxShadeBottom - mMinTopMargin;
199 final int containerCenter = mMinTopMargin + availableHeight / 2;
200
201 float y = containerCenter - mKeyguardStatusHeight * CLOCK_HEIGHT_WEIGHT
202 - mClockNotificationsMargin - mNotificationStackHeight / 2;
Lucas Dupinbc9aac12018-03-04 20:18:15 -0800203 if (y < mMinTopMargin) {
204 y = mMinTopMargin;
Lucas Dupin41ff6952018-02-18 19:39:32 -0800205 }
206
207 // Don't allow the clock base to be under half of the screen
208 final float maxClockY = getMaxClockY();
209 if (y > maxClockY) {
210 y = maxClockY;
211 }
212
213 return (int) y;
Jorim Jaggi7d16bb12014-05-22 04:24:50 +0200214 }
215
Selim Cinekdb6d6df2019-05-22 20:39:59 -0700216 private int getClockY(float panelExpansion) {
Lucas Dupind285cf02018-01-18 09:18:23 -0800217 // Dark: Align the bottom edge of the clock at about half of the screen:
Robert Snoeberger4cbd1592019-04-24 14:20:38 -0400218 float clockYDark = (mHasCustomClock ? getPreferredClockY() : getMaxClockY())
219 + burnInPreventionOffsetY();
Robert Snoeberger10b63532018-11-07 16:14:11 -0500220 clockYDark = MathUtils.max(0, clockYDark);
Lucas Dupin56057342018-04-10 11:49:18 -0700221
Robert Snoeberger4cbd1592019-04-24 14:20:38 -0400222 float clockYRegular = getExpandedPreferredClockY();
Lucas Dupin55c6e802018-09-27 18:07:36 -0700223 float clockYBouncer = -mKeyguardStatusHeight;
Lucas Dupin41ff6952018-02-18 19:39:32 -0800224
225 // Move clock up while collapsing the shade
Selim Cinekdb6d6df2019-05-22 20:39:59 -0700226 float shadeExpansion = Interpolators.FAST_OUT_LINEAR_IN.getInterpolation(panelExpansion);
Lucas Dupin55c6e802018-09-27 18:07:36 -0700227 float clockY = MathUtils.lerp(clockYBouncer, clockYRegular, shadeExpansion);
228 clockYDark = MathUtils.lerp(clockYBouncer, clockYDark, shadeExpansion);
Lucas Dupin41ff6952018-02-18 19:39:32 -0800229
Selim Cinekb0fada62019-06-17 19:03:59 -0700230 float darkAmount = mBypassEnabled && !mHasCustomClock ? 1.0f : mDarkAmount;
Selim Cinekc1d9ab22019-05-21 18:08:30 -0700231 return (int) (MathUtils.lerp(clockY, clockYDark, darkAmount) + mEmptyDragAmount);
Lucas Dupin41ff6952018-02-18 19:39:32 -0800232 }
233
Lucas Dupinbc9aac12018-03-04 20:18:15 -0800234 /**
235 * We might want to fade out the clock when the user is swiping up.
236 * One exception is when the bouncer will become visible, in this cause the clock
237 * should always persist.
238 *
239 * @param y Current clock Y.
240 * @return Alpha from 0 to 1.
241 */
Lucas Dupin41ff6952018-02-18 19:39:32 -0800242 private float getClockAlpha(int y) {
Lucas Dupindf4ee3c2019-10-21 15:56:55 -0700243 float alphaKeyguard = Math.max(0, y / Math.max(1f, getClockY(1f)));
Lucas Dupin2e838ac2019-04-17 16:50:58 -0700244 alphaKeyguard = Interpolators.ACCELERATE.getInterpolation(alphaKeyguard);
Lucas Dupin41ff6952018-02-18 19:39:32 -0800245 return MathUtils.lerp(alphaKeyguard, 1f, mDarkAmount);
Adrian Roosdc747bd2017-06-01 16:09:15 -0700246 }
247
248 private float burnInPreventionOffsetY() {
Lucas Dupin7da4f262018-09-20 13:41:46 -0700249 return getBurnInOffset(mBurnInPreventionOffsetY * 2, false /* xAxis */)
Adrian Roosdc747bd2017-06-01 16:09:15 -0700250 - mBurnInPreventionOffsetY;
251 }
252
253 private float burnInPreventionOffsetX() {
Lucas Dupin7da4f262018-09-20 13:41:46 -0700254 return getBurnInOffset(mBurnInPreventionOffsetX * 2, true /* xAxis */)
Adrian Roosdc747bd2017-06-01 16:09:15 -0700255 - mBurnInPreventionOffsetX;
256 }
257
Jorim Jaggi7d16bb12014-05-22 04:24:50 +0200258 public static class Result {
259
260 /**
Lucas Dupin41ff6952018-02-18 19:39:32 -0800261 * The x translation of the clock.
262 */
263 public int clockX;
264
265 /**
Jorim Jaggi7d16bb12014-05-22 04:24:50 +0200266 * The y translation of the clock.
267 */
268 public int clockY;
269
270 /**
Jorim Jaggi7d16bb12014-05-22 04:24:50 +0200271 * The alpha value of the clock.
272 */
273 public float clockAlpha;
274
275 /**
276 * The top padding of the stack scroller, in pixels.
277 */
278 public int stackScrollerPadding;
Selim Cinekdb6d6df2019-05-22 20:39:59 -0700279
280 /**
281 * The top padding of the stack scroller, in pixels when fully expanded.
282 */
283 public int stackScrollerPaddingExpanded;
Jorim Jaggi7d16bb12014-05-22 04:24:50 +0200284 }
285}