• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 
17 package com.android.systemui.statusbar.phone;
18 
19 import android.content.res.Resources;
20 import android.graphics.Path;
21 import android.view.animation.AccelerateInterpolator;
22 import android.view.animation.PathInterpolator;
23 
24 import com.android.systemui.R;
25 
26 /**
27  * Utility class to calculate the clock position and top padding of notifications on Keyguard.
28  */
29 public class KeyguardClockPositionAlgorithm {
30 
31     private static final float SLOW_DOWN_FACTOR = 0.4f;
32 
33     private static final float CLOCK_RUBBERBAND_FACTOR_MIN = 0.08f;
34     private static final float CLOCK_RUBBERBAND_FACTOR_MAX = 0.8f;
35     private static final float CLOCK_SCALE_FADE_START = 0.95f;
36     private static final float CLOCK_SCALE_FADE_END = 0.75f;
37     private static final float CLOCK_SCALE_FADE_END_NO_NOTIFS = 0.5f;
38 
39     private static final float CLOCK_ADJ_TOP_PADDING_MULTIPLIER_MIN = 1.4f;
40     private static final float CLOCK_ADJ_TOP_PADDING_MULTIPLIER_MAX = 3.2f;
41 
42     private int mClockNotificationsMarginMin;
43     private int mClockNotificationsMarginMax;
44     private float mClockYFractionMin;
45     private float mClockYFractionMax;
46     private int mMaxKeyguardNotifications;
47     private int mMaxPanelHeight;
48     private float mExpandedHeight;
49     private int mNotificationCount;
50     private int mHeight;
51     private int mKeyguardStatusHeight;
52     private float mEmptyDragAmount;
53     private float mDensity;
54 
55     /**
56      * The number (fractional) of notifications the "more" card counts when calculating how many
57      * notifications are currently visible for the y positioning of the clock.
58      */
59     private float mMoreCardNotificationAmount;
60 
61     private static final PathInterpolator sSlowDownInterpolator;
62 
63     static {
64         Path path = new Path();
65         path.moveTo(0, 0);
66         path.cubicTo(0.3f, 0.875f, 0.6f, 1f, 1f, 1f);
67         sSlowDownInterpolator = new PathInterpolator(path);
68     }
69 
70     private AccelerateInterpolator mAccelerateInterpolator = new AccelerateInterpolator();
71 
72     /**
73      * Refreshes the dimension values.
74      */
loadDimens(Resources res)75     public void loadDimens(Resources res) {
76         mClockNotificationsMarginMin = res.getDimensionPixelSize(
77                 R.dimen.keyguard_clock_notifications_margin_min);
78         mClockNotificationsMarginMax = res.getDimensionPixelSize(
79                 R.dimen.keyguard_clock_notifications_margin_max);
80         mClockYFractionMin = res.getFraction(R.fraction.keyguard_clock_y_fraction_min, 1, 1);
81         mClockYFractionMax = res.getFraction(R.fraction.keyguard_clock_y_fraction_max, 1, 1);
82         mMoreCardNotificationAmount =
83                 (float) res.getDimensionPixelSize(R.dimen.notification_summary_height) /
84                         res.getDimensionPixelSize(R.dimen.notification_min_height);
85         mDensity = res.getDisplayMetrics().density;
86     }
87 
setup(int maxKeyguardNotifications, int maxPanelHeight, float expandedHeight, int notificationCount, int height, int keyguardStatusHeight, float emptyDragAmount)88     public void setup(int maxKeyguardNotifications, int maxPanelHeight, float expandedHeight,
89             int notificationCount, int height, int keyguardStatusHeight, float emptyDragAmount) {
90         mMaxKeyguardNotifications = maxKeyguardNotifications;
91         mMaxPanelHeight = maxPanelHeight;
92         mExpandedHeight = expandedHeight;
93         mNotificationCount = notificationCount;
94         mHeight = height;
95         mKeyguardStatusHeight = keyguardStatusHeight;
96         mEmptyDragAmount = emptyDragAmount;
97     }
98 
getMinStackScrollerPadding(int height, int keyguardStatusHeight)99     public float getMinStackScrollerPadding(int height, int keyguardStatusHeight) {
100         return mClockYFractionMin * height + keyguardStatusHeight / 2
101                 + mClockNotificationsMarginMin;
102     }
103 
run(Result result)104     public void run(Result result) {
105         int y = getClockY() - mKeyguardStatusHeight / 2;
106         float clockAdjustment = getClockYExpansionAdjustment();
107         float topPaddingAdjMultiplier = getTopPaddingAdjMultiplier();
108         result.stackScrollerPaddingAdjustment = (int) (clockAdjustment*topPaddingAdjMultiplier);
109         int clockNotificationsPadding = getClockNotificationsPadding()
110                 + result.stackScrollerPaddingAdjustment;
111         int padding = y + clockNotificationsPadding;
112         result.clockY = y;
113         result.stackScrollerPadding = mKeyguardStatusHeight + padding;
114         result.clockScale = getClockScale(result.stackScrollerPadding,
115                 result.clockY,
116                 y + getClockNotificationsPadding() + mKeyguardStatusHeight);
117         result.clockAlpha = getClockAlpha(result.clockScale);
118     }
119 
getClockScale(int notificationPadding, int clockY, int startPadding)120     private float getClockScale(int notificationPadding, int clockY, int startPadding) {
121         float scaleMultiplier = getNotificationAmountT() == 0 ? 6.0f : 5.0f;
122         float scaleEnd = clockY - mKeyguardStatusHeight * scaleMultiplier;
123         float distanceToScaleEnd = notificationPadding - scaleEnd;
124         float progress = distanceToScaleEnd / (startPadding - scaleEnd);
125         progress = Math.max(0.0f, Math.min(progress, 1.0f));
126         progress = mAccelerateInterpolator.getInterpolation(progress);
127         progress *= Math.pow(1 + mEmptyDragAmount / mDensity / 300, 0.3f);
128         return progress;
129     }
130 
getClockNotificationsPadding()131     private int getClockNotificationsPadding() {
132         float t = getNotificationAmountT();
133         t = Math.min(t, 1.0f);
134         return (int) (t * mClockNotificationsMarginMin + (1 - t) * mClockNotificationsMarginMax);
135     }
136 
getClockYFraction()137     private float getClockYFraction() {
138         float t = getNotificationAmountT();
139         t = Math.min(t, 1.0f);
140         return (1 - t) * mClockYFractionMax + t * mClockYFractionMin;
141     }
142 
getClockY()143     private int getClockY() {
144         return (int) (getClockYFraction() * mHeight);
145     }
146 
getClockYExpansionAdjustment()147     private float getClockYExpansionAdjustment() {
148         float rubberbandFactor = getClockYExpansionRubberbandFactor();
149         float value = (rubberbandFactor * (mMaxPanelHeight - mExpandedHeight));
150         float t = value / mMaxPanelHeight;
151         float slowedDownValue = -sSlowDownInterpolator.getInterpolation(t) * SLOW_DOWN_FACTOR
152                 * mMaxPanelHeight;
153         if (mNotificationCount == 0) {
154             return (-2*value + slowedDownValue)/3;
155         } else {
156             return slowedDownValue;
157         }
158     }
159 
getClockYExpansionRubberbandFactor()160     private float getClockYExpansionRubberbandFactor() {
161         float t = getNotificationAmountT();
162         t = Math.min(t, 1.0f);
163         t = (float) Math.pow(t, 0.3f);
164         return (1 - t) * CLOCK_RUBBERBAND_FACTOR_MAX + t * CLOCK_RUBBERBAND_FACTOR_MIN;
165     }
166 
getTopPaddingAdjMultiplier()167     private float getTopPaddingAdjMultiplier() {
168         float t = getNotificationAmountT();
169         t = Math.min(t, 1.0f);
170         return (1 - t) * CLOCK_ADJ_TOP_PADDING_MULTIPLIER_MIN
171                 + t * CLOCK_ADJ_TOP_PADDING_MULTIPLIER_MAX;
172     }
173 
getClockAlpha(float scale)174     private float getClockAlpha(float scale) {
175         float fadeEnd = getNotificationAmountT() == 0.0f
176                 ? CLOCK_SCALE_FADE_END_NO_NOTIFS
177                 : CLOCK_SCALE_FADE_END;
178         float alpha = (scale - fadeEnd)
179                 / (CLOCK_SCALE_FADE_START - fadeEnd);
180         return Math.max(0, Math.min(1, alpha));
181     }
182 
183     /**
184      * @return a value from 0 to 1 depending on how many notification there are
185      */
getNotificationAmountT()186     private float getNotificationAmountT() {
187         return mNotificationCount
188                 / (mMaxKeyguardNotifications + mMoreCardNotificationAmount);
189     }
190 
191     public static class Result {
192 
193         /**
194          * The y translation of the clock.
195          */
196         public int clockY;
197 
198         /**
199          * The scale of the Clock
200          */
201         public float clockScale;
202 
203         /**
204          * The alpha value of the clock.
205          */
206         public float clockAlpha;
207 
208         /**
209          * The top padding of the stack scroller, in pixels.
210          */
211         public int stackScrollerPadding;
212 
213         /**
214          * The top padding adjustment of the stack scroller, in pixels. This value is used to adjust
215          * the padding, but not the overall panel size.
216          */
217         public int stackScrollerPaddingAdjustment;
218     }
219 }
220