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