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 run(Result result)99 public void run(Result result) { 100 int y = getClockY() - mKeyguardStatusHeight / 2; 101 float clockAdjustment = getClockYExpansionAdjustment(); 102 float topPaddingAdjMultiplier = getTopPaddingAdjMultiplier(); 103 result.stackScrollerPaddingAdjustment = (int) (clockAdjustment*topPaddingAdjMultiplier); 104 int clockNotificationsPadding = getClockNotificationsPadding() 105 + result.stackScrollerPaddingAdjustment; 106 int padding = y + clockNotificationsPadding; 107 result.clockY = y; 108 result.stackScrollerPadding = mKeyguardStatusHeight + padding; 109 result.clockScale = getClockScale(result.stackScrollerPadding, 110 result.clockY, 111 y + getClockNotificationsPadding() + mKeyguardStatusHeight); 112 result.clockAlpha = getClockAlpha(result.clockScale); 113 } 114 getClockScale(int notificationPadding, int clockY, int startPadding)115 private float getClockScale(int notificationPadding, int clockY, int startPadding) { 116 float scaleMultiplier = getNotificationAmountT() == 0 ? 6.0f : 5.0f; 117 float scaleEnd = clockY - mKeyguardStatusHeight * scaleMultiplier; 118 float distanceToScaleEnd = notificationPadding - scaleEnd; 119 float progress = distanceToScaleEnd / (startPadding - scaleEnd); 120 progress = Math.max(0.0f, Math.min(progress, 1.0f)); 121 progress = mAccelerateInterpolator.getInterpolation(progress); 122 progress *= Math.pow(1 + mEmptyDragAmount / mDensity / 300, 0.3f); 123 return progress; 124 } 125 getClockNotificationsPadding()126 private int getClockNotificationsPadding() { 127 float t = getNotificationAmountT(); 128 t = Math.min(t, 1.0f); 129 return (int) (t * mClockNotificationsMarginMin + (1 - t) * mClockNotificationsMarginMax); 130 } 131 getClockYFraction()132 private float getClockYFraction() { 133 float t = getNotificationAmountT(); 134 t = Math.min(t, 1.0f); 135 return (1 - t) * mClockYFractionMax + t * mClockYFractionMin; 136 } 137 getClockY()138 private int getClockY() { 139 return (int) (getClockYFraction() * mHeight); 140 } 141 getClockYExpansionAdjustment()142 private float getClockYExpansionAdjustment() { 143 float rubberbandFactor = getClockYExpansionRubberbandFactor(); 144 float value = (rubberbandFactor * (mMaxPanelHeight - mExpandedHeight)); 145 float t = value / mMaxPanelHeight; 146 float slowedDownValue = -sSlowDownInterpolator.getInterpolation(t) * SLOW_DOWN_FACTOR 147 * mMaxPanelHeight; 148 if (mNotificationCount == 0) { 149 return (-2*value + slowedDownValue)/3; 150 } else { 151 return slowedDownValue; 152 } 153 } 154 getClockYExpansionRubberbandFactor()155 private float getClockYExpansionRubberbandFactor() { 156 float t = getNotificationAmountT(); 157 t = Math.min(t, 1.0f); 158 t = (float) Math.pow(t, 0.3f); 159 return (1 - t) * CLOCK_RUBBERBAND_FACTOR_MAX + t * CLOCK_RUBBERBAND_FACTOR_MIN; 160 } 161 getTopPaddingAdjMultiplier()162 private float getTopPaddingAdjMultiplier() { 163 float t = getNotificationAmountT(); 164 t = Math.min(t, 1.0f); 165 return (1 - t) * CLOCK_ADJ_TOP_PADDING_MULTIPLIER_MIN 166 + t * CLOCK_ADJ_TOP_PADDING_MULTIPLIER_MAX; 167 } 168 getClockAlpha(float scale)169 private float getClockAlpha(float scale) { 170 float fadeEnd = getNotificationAmountT() == 0.0f 171 ? CLOCK_SCALE_FADE_END_NO_NOTIFS 172 : CLOCK_SCALE_FADE_END; 173 float alpha = (scale - fadeEnd) 174 / (CLOCK_SCALE_FADE_START - fadeEnd); 175 return Math.max(0, Math.min(1, alpha)); 176 } 177 178 /** 179 * @return a value from 0 to 1 depending on how many notification there are 180 */ getNotificationAmountT()181 private float getNotificationAmountT() { 182 return mNotificationCount 183 / (mMaxKeyguardNotifications + mMoreCardNotificationAmount); 184 } 185 186 public static class Result { 187 188 /** 189 * The y translation of the clock. 190 */ 191 public int clockY; 192 193 /** 194 * The scale of the Clock 195 */ 196 public float clockScale; 197 198 /** 199 * The alpha value of the clock. 200 */ 201 public float clockAlpha; 202 203 /** 204 * The top padding of the stack scroller, in pixels. 205 */ 206 public int stackScrollerPadding; 207 208 /** 209 * The top padding adjustment of the stack scroller, in pixels. This value is used to adjust 210 * the padding, but not the overall panel size. 211 */ 212 public int stackScrollerPaddingAdjustment; 213 } 214 } 215