diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java new file mode 100644 index 0000000000000..6a83a5e2226ad --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java @@ -0,0 +1,186 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.systemui.statusbar.phone; + +import android.content.res.Resources; +import android.graphics.Path; +import android.view.animation.PathInterpolator; + +import com.android.systemui.R; + +/** + * Utility class to calculate the clock position and top padding of notifications on Keyguard. + */ +public class KeyguardClockPositionAlgorithm { + + private static final float SLOW_DOWN_FACTOR = 0.4f; + + private static final float CLOCK_RUBBERBAND_FACTOR_MIN = 0.08f; + private static final float CLOCK_RUBBERBAND_FACTOR_MAX = 0.8f; + + private static final float CLOCK_ADJ_TOP_PADDING_MULTIPLIER_MIN = 1.4f; + private static final float CLOCK_ADJ_TOP_PADDING_MULTIPLIER_MAX = 3.2f; + + private int mClockNotificationsMarginMin; + private int mClockNotificationsMarginMax; + private float mClockYFractionMin; + private float mClockYFractionMax; + private int mMaxKeyguardNotifications; + private int mMaxPanelHeight; + private float mExpandedHeight; + private int mNotificationCount; + private int mHeight; + private int mKeyguardStatusHeight; + + /** + * The number (fractional) of notifications the "more" card counts when calculating how many + * notifications are currently visible for the y positioning of the clock. + */ + private float mMoreCardNotificationAmount; + + private static final PathInterpolator sSlowDownInterpolator; + + static { + Path path = new Path(); + path.moveTo(0, 0); + path.cubicTo(0.3f, 0.875f, 0.6f, 1f, 1f, 1f); + sSlowDownInterpolator = new PathInterpolator(path); + } + + /** + * Refreshes the dimension values. + */ + public void loadDimens(Resources res) { + mClockNotificationsMarginMin = res.getDimensionPixelSize( + R.dimen.keyguard_clock_notifications_margin_min); + mClockNotificationsMarginMax = res.getDimensionPixelSize( + R.dimen.keyguard_clock_notifications_margin_max); + mClockYFractionMin = res.getFraction(R.fraction.keyguard_clock_y_fraction_min, 1, 1); + mClockYFractionMax = res.getFraction(R.fraction.keyguard_clock_y_fraction_max, 1, 1); + mMoreCardNotificationAmount = + (float) res.getDimensionPixelSize(R.dimen.notification_summary_height) / + res.getDimensionPixelSize(R.dimen.notification_min_height); + } + + public void setup(int maxKeyguardNotifications, int maxPanelHeight, float expandedHeight, + int notificationCount, int height, int keyguardStatusHeight) { + mMaxKeyguardNotifications = maxKeyguardNotifications; + mMaxPanelHeight = maxPanelHeight; + mExpandedHeight = expandedHeight; + mNotificationCount = notificationCount; + mHeight = height; + mKeyguardStatusHeight = keyguardStatusHeight; + } + + public void run(Result result) { + int y = getClockY() - mKeyguardStatusHeight/2; + float clockAdjustment = getClockYExpansionAdjustment(); + float topPaddingAdjMultiplier = getTopPaddingAdjMultiplier(); + result.stackScrollerPaddingAdjustment = (int) (clockAdjustment*topPaddingAdjMultiplier); + int clockNotificationsPadding = getClockNotificationsPadding() + + result.stackScrollerPaddingAdjustment; + int padding = y + clockNotificationsPadding; + y += clockAdjustment; + result.clockY = y; + result.stackScrollerPadding = mKeyguardStatusHeight + padding; + result.clockAlpha = getClockAlpha(result.stackScrollerPadding + - (y + mKeyguardStatusHeight)); + } + + private int getClockNotificationsPadding() { + float t = getNotificationAmountT(); + t = Math.min(t, 1.0f); + return (int) (t * mClockNotificationsMarginMin + (1 - t) * mClockNotificationsMarginMax); + } + + private float getClockYFraction() { + float t = getNotificationAmountT(); + t = Math.min(t, 1.0f); + return (1 - t) * mClockYFractionMax + t * mClockYFractionMin; + } + + private int getClockY() { + return (int) (getClockYFraction() * mHeight); + } + + private float getClockYExpansionAdjustment() { + float rubberbandFactor = getClockYExpansionRubberbandFactor(); + float value = (rubberbandFactor * (mMaxPanelHeight - mExpandedHeight)); + float t = value / mMaxPanelHeight; + float slowedDownValue = -sSlowDownInterpolator.getInterpolation(t) * SLOW_DOWN_FACTOR + * mMaxPanelHeight; + if (mNotificationCount == 0) { + return (-2*value + slowedDownValue)/3; + } else { + return slowedDownValue; + } + } + + private float getClockYExpansionRubberbandFactor() { + float t = getNotificationAmountT(); + t = Math.min(t, 1.0f); + t = (float) Math.pow(t, 0.3f); + return (1 - t) * CLOCK_RUBBERBAND_FACTOR_MAX + t * CLOCK_RUBBERBAND_FACTOR_MIN; + } + + private float getTopPaddingAdjMultiplier() { + float t = getNotificationAmountT(); + t = Math.min(t, 1.0f); + return (1 - t) * CLOCK_ADJ_TOP_PADDING_MULTIPLIER_MIN + + t * CLOCK_ADJ_TOP_PADDING_MULTIPLIER_MAX; + } + + private float getClockAlpha(int clockNotificationPadding) { + float t = getNotificationAmountT(); + t = (float) Math.pow(t, 0.3f); + float multiplier = 1 + 2 * (1 - t); + float alpha = 1 + (float) clockNotificationPadding * multiplier / mKeyguardStatusHeight * 3; + return Math.max(0, Math.min(1, alpha)); + } + + /** + * @return a value from 0 to 1 depending on how many notification there are + */ + private float getNotificationAmountT() { + return mNotificationCount + / (mMaxKeyguardNotifications + mMoreCardNotificationAmount); + } + + public static class Result { + + /** + * The y translation of the clock. + */ + public int clockY; + + /** + * The alpha value of the clock. + */ + public float clockAlpha; + + /** + * The top padding of the stack scroller, in pixels. + */ + public int stackScrollerPadding; + + /** + * The top padding adjustment of the stack scroller, in pixels. This value is used to adjust + * the padding, but not the overall panel size. + */ + public int stackScrollerPaddingAdjustment; + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java index 123a4f08589ac..fe7546dee29d7 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java @@ -19,10 +19,11 @@ package com.android.systemui.statusbar.phone; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ObjectAnimator; -import android.animation.PropertyValuesHolder; import android.animation.ValueAnimator; import android.content.Context; +import android.graphics.Path; import android.util.AttributeSet; +import android.util.Log; import android.view.MotionEvent; import android.view.VelocityTracker; import android.view.View; @@ -31,6 +32,7 @@ import android.view.ViewTreeObserver; import android.view.accessibility.AccessibilityEvent; import android.view.animation.AnimationUtils; import android.view.animation.Interpolator; +import android.view.animation.PathInterpolator; import android.widget.LinearLayout; import com.android.systemui.R; @@ -82,19 +84,14 @@ public class NotificationPanelView extends PanelView implements private FlingAnimationUtils mFlingAnimationUtils; private int mStatusBarMinHeight; - private int mClockNotificationsMarginMin; - private int mClockNotificationsMarginMax; - private float mClockYFractionMin; - private float mClockYFractionMax; private Interpolator mFastOutSlowInInterpolator; private ObjectAnimator mClockAnimator; private int mClockAnimationTarget = -1; - - /** - * The number (fractional) of notifications the "more" card counts when calculating how many - * notifications are currently visible for the y positioning of the clock. - */ - private float mMoreCardNotificationAmount; + private int mTopPaddingAdjustment; + private KeyguardClockPositionAlgorithm mClockPositionAlgorithm = + new KeyguardClockPositionAlgorithm(); + private KeyguardClockPositionAlgorithm.Result mClockPositionResult = + new KeyguardClockPositionAlgorithm.Result(); public NotificationPanelView(Context context, AttributeSet attrs) { super(context, attrs); @@ -139,20 +136,10 @@ public class NotificationPanelView extends PanelView implements mNotificationTopPadding = getResources().getDimensionPixelSize( R.dimen.notifications_top_padding); mMinStackHeight = getResources().getDimensionPixelSize(R.dimen.collapsed_stack_height); - mClockNotificationsMarginMin = getResources().getDimensionPixelSize( - R.dimen.keyguard_clock_notifications_margin_min); - mClockNotificationsMarginMax = getResources().getDimensionPixelSize( - R.dimen.keyguard_clock_notifications_margin_max); - mClockYFractionMin = - getResources().getFraction(R.fraction.keyguard_clock_y_fraction_min, 1, 1); - mClockYFractionMax = - getResources().getFraction(R.fraction.keyguard_clock_y_fraction_max, 1, 1); - mMoreCardNotificationAmount = - (float) getResources().getDimensionPixelSize(R.dimen.notification_summary_height) / - getResources().getDimensionPixelSize(R.dimen.notification_min_height); mFlingAnimationUtils = new FlingAnimationUtils(getContext(), 0.4f); mStatusBarMinHeight = getResources().getDimensionPixelSize( com.android.internal.R.dimen.status_bar_height); + mClockPositionAlgorithm.loadDimens(getResources()); } @Override @@ -160,6 +147,7 @@ public class NotificationPanelView extends PanelView implements super.onLayout(changed, left, top, right, bottom); if (!mQsExpanded) { positionClockAndNotifications(); + mNotificationStackScroller.setStackHeight(getExpandedHeight()); } // Calculate quick setting heights. @@ -178,16 +166,24 @@ public class NotificationPanelView extends PanelView implements boolean animateClock = mNotificationStackScroller.isAddOrRemoveAnimationPending(); if (mStatusBar.getBarState() != StatusBarState.KEYGUARD) { mStackScrollerIntrinsicPadding = mHeader.getBottom() + mNotificationTopPadding; + mTopPaddingAdjustment = 0; } else { - int notificationCount = mNotificationStackScroller.getNotGoneChildCount(); - int y = getClockY(notificationCount) - mKeyguardStatusView.getHeight()/2; - int padding = getClockNotificationsPadding(notificationCount); + mClockPositionAlgorithm.setup( + mStatusBar.getMaxKeyguardNotifications(), + getMaxPanelHeight(), + getExpandedHeight(), + mNotificationStackScroller.getNotGoneChildCount(), + getHeight(), + mKeyguardStatusView.getHeight()); + mClockPositionAlgorithm.run(mClockPositionResult); if (animateClock || mClockAnimator != null) { - startClockAnimation(y); + startClockAnimation(mClockPositionResult.clockY); } else { - mKeyguardStatusView.setY(y); + mKeyguardStatusView.setY(mClockPositionResult.clockY); } - mStackScrollerIntrinsicPadding = y + mKeyguardStatusView.getHeight() + padding; + applyClockAlpha(mClockPositionResult.clockAlpha); + mStackScrollerIntrinsicPadding = mClockPositionResult.stackScrollerPadding; + mTopPaddingAdjustment = mClockPositionResult.stackScrollerPaddingAdjustment; } mNotificationStackScroller.setTopPadding(mStackScrollerIntrinsicPadding, mAnimateNextTopPaddingChange || animateClock); @@ -224,22 +220,13 @@ public class NotificationPanelView extends PanelView implements }); } - private int getClockNotificationsPadding(int notificationCount) { - float t = notificationCount - / (mStatusBar.getMaxKeyguardNotifications() + mMoreCardNotificationAmount); - t = Math.min(t, 1.0f); - return (int) (t * mClockNotificationsMarginMin + (1 - t) * mClockNotificationsMarginMax); - } - - private float getClockYFraction(int notificationCount) { - float t = notificationCount - / (mStatusBar.getMaxKeyguardNotifications() + mMoreCardNotificationAmount); - t = Math.min(t, 1.0f); - return (1 - t) * mClockYFractionMax + t * mClockYFractionMin; - } - - private int getClockY(int notificationCount) { - return (int) (getClockYFraction(notificationCount) * getHeight()); + private void applyClockAlpha(float alpha) { + if (alpha != 1.0f) { + mKeyguardStatusView.setLayerType(LAYER_TYPE_HARDWARE, null); + } else { + mKeyguardStatusView.setLayerType(LAYER_TYPE_NONE, null); + } + mKeyguardStatusView.setAlpha(alpha); } public void animateToFullShade() { @@ -626,7 +613,7 @@ public class NotificationPanelView extends PanelView implements int emptyBottomMargin = mStackScrollerContainer.getHeight() - mNotificationStackScroller.getHeight() + mNotificationStackScroller.getEmptyBottomMargin(); - int maxHeight = maxPanelHeight - emptyBottomMargin; + int maxHeight = maxPanelHeight - emptyBottomMargin - mTopPaddingAdjustment; maxHeight = Math.max(maxHeight, mStatusBarMinHeight); return maxHeight; } @@ -637,6 +624,9 @@ public class NotificationPanelView extends PanelView implements @Override protected void onHeightUpdated(float expandedHeight) { + if (!mQsExpanded) { + positionClockAndNotifications(); + } mNotificationStackScroller.setStackHeight(expandedHeight); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java index b6a43a7a2b64f..8631e3aefed79 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java @@ -402,7 +402,7 @@ public class PanelView extends FrameLayout { public void setExpandedHeightInternal(float h) { float fh = getMaxPanelHeight(); - mExpandedHeight = h; + mExpandedHeight = Math.min(fh, h); if (DEBUG) { logf("setExpansion: height=%.1f fh=%.1f tracking=%s", h, fh, mTracking ? "T" : "f");