diff --git a/packages/SystemUI/res/layout/qs_panel.xml b/packages/SystemUI/res/layout/qs_panel.xml
index 28b9a5e684b6b..bb37b83af3366 100644
--- a/packages/SystemUI/res/layout/qs_panel.xml
+++ b/packages/SystemUI/res/layout/qs_panel.xml
@@ -19,15 +19,12 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/qs_background_primary"
- android:paddingBottom="8dp">
+ android:paddingBottom="8dp"
+ android:elevation="2dp">
-
-
-
diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml
index 0ebbdd87657af..89abe2dc2c4c3 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded.xml
@@ -31,12 +31,6 @@
android:layout_height="wrap_content"
android:visibility="gone" />
-
-
+
@@ -91,6 +90,12 @@
layout="@layout/keyguard_bottom_area"
android:visibility="gone" />
+
+
= 1f ? amount : 0f;
- setOverScrolling(rounded != 0f && isRubberbanded);
+ mStackScrollerOverscrolling = rounded != 0f && isRubberbanded;
mQsExpansionFromOverscroll = rounded != 0f;
mLastOverscroll = rounded;
updateQsState();
@@ -952,17 +964,12 @@ public class NotificationPanelView extends PanelView implements
@Override
public void run() {
mStackScrollerOverscrolling = false;
- setOverScrolling(false);
+ mQsExpansionFromOverscroll = false;
updateQsState();
}
}, false /* isClick */);
}
- private void setOverScrolling(boolean overscrolling) {
- mStackScrollerOverscrolling = overscrolling;
- mQsContainer.setOverscrolling(overscrolling);
- }
-
private void onQsExpansionStarted() {
onQsExpansionStarted(0);
}
@@ -990,6 +997,7 @@ public class NotificationPanelView extends PanelView implements
mFalsingManager.setQsExpanded(expanded);
mNotificationStackScroller.setInterceptDelegateEnabled(expanded);
mStatusBar.setQsExpanded(expanded);
+ mQsPanel.setExpanded(expanded);
mNotificationContainerParent.setQsExpanded(expanded);
}
}
@@ -1003,18 +1011,15 @@ public class NotificationPanelView extends PanelView implements
mStatusBarState = statusBarState;
mKeyguardShowing = keyguardShowing;
- mQsContainer.setKeyguardShowing(mKeyguardShowing);
if (goingToFullShade || (oldState == StatusBarState.KEYGUARD
&& statusBarState == StatusBarState.SHADE_LOCKED)) {
animateKeyguardStatusBarOut();
- long delay = mStatusBarState == StatusBarState.SHADE_LOCKED
- ? 0 : mStatusBar.calculateGoingToFullShadeDelay();
- mQsContainer.animateHeaderSlidingIn(delay);
+ animateHeaderSlidingIn();
} else if (oldState == StatusBarState.SHADE_LOCKED
&& statusBarState == StatusBarState.KEYGUARD) {
animateKeyguardStatusBarIn(StackStateAnimator.ANIMATION_DURATION_STANDARD);
- mQsContainer.animateHeaderSlidingOut();
+ animateHeaderSlidingOut();
} else {
mKeyguardStatusBar.setAlpha(1f);
mKeyguardStatusBar.setVisibility(keyguardShowing ? View.VISIBLE : View.INVISIBLE);
@@ -1045,6 +1050,95 @@ public class NotificationPanelView extends PanelView implements
}
};
+ private final Animator.AnimatorListener mAnimateHeaderSlidingInListener
+ = new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mHeaderAnimating = false;
+ mQsContainerAnimator = null;
+ mQsContainer.removeOnLayoutChangeListener(mQsContainerAnimatorUpdater);
+ }
+ };
+
+ private final OnLayoutChangeListener mQsContainerAnimatorUpdater
+ = new OnLayoutChangeListener() {
+ @Override
+ public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft,
+ int oldTop, int oldRight, int oldBottom) {
+ int oldHeight = oldBottom - oldTop;
+ int height = bottom - top;
+ if (height != oldHeight && mQsContainerAnimator != null) {
+ PropertyValuesHolder[] values = mQsContainerAnimator.getValues();
+ float newEndValue = mHeader.getCollapsedHeight() + mQsPeekHeight - height - top;
+ float newStartValue = -height - top;
+ values[0].setFloatValues(newStartValue, newEndValue);
+ mQsContainerAnimator.setCurrentPlayTime(mQsContainerAnimator.getCurrentPlayTime());
+ }
+ }
+ };
+
+ private final ViewTreeObserver.OnPreDrawListener mStartHeaderSlidingIn
+ = new ViewTreeObserver.OnPreDrawListener() {
+ @Override
+ public boolean onPreDraw() {
+ getViewTreeObserver().removeOnPreDrawListener(this);
+ long delay = mStatusBarState == StatusBarState.SHADE_LOCKED
+ ? 0
+ : mStatusBar.calculateGoingToFullShadeDelay();
+ mHeader.setTranslationY(-mHeader.getCollapsedHeight() - mQsPeekHeight);
+ mHeader.animate()
+ .translationY(0f)
+ .setStartDelay(delay)
+ .setDuration(StackStateAnimator.ANIMATION_DURATION_GO_TO_FULL_SHADE)
+ .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
+ .start();
+ mQsContainer.setY(-mQsContainer.getHeight());
+ mQsContainerAnimator = ObjectAnimator.ofFloat(mQsContainer, View.TRANSLATION_Y,
+ mQsContainer.getTranslationY(),
+ mHeader.getCollapsedHeight() + mQsPeekHeight - mQsContainer.getHeight()
+ - mQsContainer.getTop());
+ mQsContainerAnimator.setStartDelay(delay);
+ mQsContainerAnimator.setDuration(StackStateAnimator.ANIMATION_DURATION_GO_TO_FULL_SHADE);
+ mQsContainerAnimator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
+ mQsContainerAnimator.addListener(mAnimateHeaderSlidingInListener);
+ mQsContainerAnimator.start();
+ mQsContainer.addOnLayoutChangeListener(mQsContainerAnimatorUpdater);
+ return true;
+ }
+ };
+
+ private void animateHeaderSlidingIn() {
+ // If the QS is already expanded we don't need to slide in the header as it's already
+ // visible.
+ if (!mQsExpanded) {
+ mHeaderAnimating = true;
+ getViewTreeObserver().addOnPreDrawListener(mStartHeaderSlidingIn);
+ }
+ }
+
+ private void animateHeaderSlidingOut() {
+ mHeaderAnimating = true;
+ mHeader.animate().y(-mHeader.getHeight())
+ .setStartDelay(0)
+ .setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD)
+ .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
+ .setListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mHeader.animate().setListener(null);
+ mHeaderAnimating = false;
+ updateQsState();
+ }
+ })
+ .start();
+ mQsContainer.animate()
+ .y(-mQsContainer.getHeight())
+ .setStartDelay(0)
+ .setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD)
+ .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
+ .start();
+ }
+
private final Runnable mAnimateKeyguardStatusBarInvisibleEndRunnable = new Runnable() {
@Override
public void run() {
@@ -1168,10 +1262,18 @@ public class NotificationPanelView extends PanelView implements
}
private void updateQsState() {
- mQsContainer.setExpanded(mQsExpanded);
+ boolean expandVisually = mQsExpanded || mStackScrollerOverscrolling || mHeaderAnimating;
+ mHeader.setVisibility((mQsExpanded || !mKeyguardShowing || mHeaderAnimating)
+ ? View.VISIBLE
+ : View.INVISIBLE);
+ mHeader.setExpanded((mKeyguardShowing && !mHeaderAnimating)
+ || (mQsExpanded && !mStackScrollerOverscrolling));
mNotificationStackScroller.setScrollingEnabled(
mStatusBarState != StatusBarState.KEYGUARD && (!mQsExpanded
|| mQsExpansionFromOverscroll));
+ mQsPanel.setVisibility(expandVisually ? View.VISIBLE : View.INVISIBLE);
+ mQsContainer.setVisibility(
+ mKeyguardShowing && !expandVisually ? View.INVISIBLE : View.VISIBLE);
mScrollView.setTouchEnabled(mQsExpanded);
updateEmptyShadeView();
mQsNavbarScrim.setVisibility(mStatusBarState == StatusBarState.SHADE && mQsExpanded
@@ -1196,10 +1298,11 @@ public class NotificationPanelView extends PanelView implements
}
}
mQsExpansionHeight = height;
- updateQsExpansion();
+ mHeader.setExpansion(getHeaderExpansionFraction());
+ setQsTranslation(height);
requestScrollerTopPaddingUpdate(false /* animate */);
if (mKeyguardShowing) {
- updateHeaderKeyguardAlpha();
+ updateHeaderKeyguard();
}
if (mStatusBarState == StatusBarState.SHADE_LOCKED
|| mStatusBarState == StatusBarState.KEYGUARD) {
@@ -1226,10 +1329,6 @@ public class NotificationPanelView extends PanelView implements
}
}
- private void updateQsExpansion() {
- mQsContainer.setQsExpansion(getQsExpansionFraction(), getHeaderTranslation());
- }
-
private String getKeyguardOrLockScreenString() {
if (mStatusBarState == StatusBarState.KEYGUARD) {
return getContext().getString(R.string.accessibility_desc_lock_screen);
@@ -1238,6 +1337,23 @@ public class NotificationPanelView extends PanelView implements
}
}
+ private float getHeaderExpansionFraction() {
+ if (!mKeyguardShowing) {
+ return getQsExpansionFraction();
+ } else {
+ return 1f;
+ }
+ }
+
+ private void setQsTranslation(float height) {
+ if (!mHeaderAnimating) {
+ mQsContainer.setY(height - mQsContainer.getDesiredHeight() + getHeaderTranslation());
+ }
+ if (mKeyguardShowing && !mHeaderAnimating) {
+ mHeader.setY(interpolate(getQsExpansionFraction(), -mHeader.getHeight(), 0));
+ }
+ }
+
private float calculateQsTopPadding() {
if (mKeyguardShowing
&& (mQsExpandImmediate || mIsExpanding && mQsExpandedWhenExpandingStarted)) {
@@ -1362,7 +1478,7 @@ public class NotificationPanelView extends PanelView implements
if (!mQsExpansionEnabled || mCollapsedOnDown) {
return false;
}
- View header = mKeyguardShowing ? mKeyguardStatusBar : mQsContainer;
+ View header = mKeyguardShowing ? mKeyguardStatusBar : mHeader;
boolean onHeader = x >= header.getX() && x <= header.getX() + header.getWidth()
&& y >= header.getTop() && y <= header.getBottom();
if (mQsExpanded) {
@@ -1562,9 +1678,18 @@ public class NotificationPanelView extends PanelView implements
*/
private void updateHeader() {
if (mStatusBar.getBarState() == StatusBarState.KEYGUARD) {
- updateHeaderKeyguardAlpha();
+ updateHeaderKeyguard();
+ } else {
+ updateHeaderShade();
}
- updateQsExpansion();
+
+ }
+
+ private void updateHeaderShade() {
+ if (!mHeaderAnimating) {
+ mHeader.setTranslationY(getHeaderTranslation());
+ }
+ setQsTranslation(mQsExpansionHeight);
}
private float getHeaderTranslation() {
@@ -1619,6 +1744,11 @@ public class NotificationPanelView extends PanelView implements
&& !mDozing ? VISIBLE : INVISIBLE);
}
+ private void updateHeaderKeyguard() {
+ updateHeaderKeyguardAlpha();
+ setQsTranslation(mQsExpansionHeight);
+ }
+
private void updateKeyguardBottomAreaAlpha() {
float alpha = Math.min(getKeyguardContentsAlpha(), 1 - getQsExpansionFraction());
mKeyguardBottomArea.setAlpha(alpha);
@@ -1681,8 +1811,9 @@ public class NotificationPanelView extends PanelView implements
}
private void setListening(boolean listening) {
- mQsContainer.setListening(listening);
+ mHeader.setListening(listening);
mKeyguardStatusBar.setListening(listening);
+ mQsPanel.setListening(listening);
}
@Override
@@ -1800,7 +1931,7 @@ public class NotificationPanelView extends PanelView implements
@Override
public void onClick(View v) {
- if (v == mQsContainer.getHeader()) {
+ if (v == mHeader) {
onQsExpansionStarted();
if (mQsExpanded) {
flingSettings(0 /* vel */, false /* expand */, null, true /* isClick */);
@@ -2031,11 +2162,11 @@ public class NotificationPanelView extends PanelView implements
}
public boolean isQsDetailShowing() {
- return mQsContainer.getQsPanel().isShowingDetail();
+ return mQsPanel.isShowingDetail();
}
public void closeQsDetail() {
- mQsContainer.getQsPanel().closeDetail();
+ mQsPanel.closeDetail();
}
@Override
@@ -2123,7 +2254,7 @@ public class NotificationPanelView extends PanelView implements
private final Runnable mUpdateHeader = new Runnable() {
@Override
public void run() {
- mQsContainer.getHeader().updateEverything();
+ mHeader.updateEverything();
}
};
@@ -2270,7 +2401,7 @@ public class NotificationPanelView extends PanelView implements
protected void setVerticalPanelTranslation(float translation) {
mNotificationStackScroller.setTranslationX(translation);
mScrollView.setTranslationX(translation);
- mQsContainer.setTranslationX(translation);
+ mHeader.setTranslationX(translation);
}
private void updateStackHeight(float stackHeight) {