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