diff options
8 files changed, 163 insertions, 342 deletions
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index e5e5710cd68a..6702cefeb3e8 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -282,9 +282,6 @@ <!-- The padding between freeform workspace tasks --> <dimen name="recents_freeform_workspace_task_padding">8dp</dimen> - <!-- Space reserved for the cards behind the top card in the top stack --> - <dimen name="top_stack_peek_amount">12dp</dimen> - <!-- Space reserved for the cards behind the top card in the bottom stack --> <dimen name="bottom_stack_peek_amount">12dp</dimen> @@ -295,9 +292,6 @@ <!-- The height of the area before the bottom stack in which the notifications slow down --> <dimen name="bottom_stack_slow_down_length">12dp</dimen> - <!-- The height of the area before the top stack in which the notifications slow down --> - <dimen name="top_stack_slow_down_length">12dp</dimen> - <!-- Z distance between notifications if they are in the stack --> <dimen name="z_distance_between_notifications">0.5dp</dimen> diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java index 7f1316fe2de7..84b2031491fd 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java @@ -947,6 +947,10 @@ public class ExpandableNotificationRow extends ActivatableNotificationView { } } + public boolean mustStayOnScreen() { + return mIsHeadsUp; + } + private void updateClearability() { // public versions cannot be dismissed mVetoButton.setVisibility(isClearable() && !mShowingPublic ? View.VISIBLE : View.GONE); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java index a0fb34aecbf9..8042b60714b2 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java @@ -399,6 +399,10 @@ public abstract class ExpandableView extends FrameLayout { return false; } + public boolean mustStayOnScreen() { + return false; + } + /** * A listener notifying when {@link #getActualHeight} changes. */ diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java index b5b7f4383917..79c21f348270 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java @@ -79,7 +79,8 @@ public class HeadsUpTouchHelper implements Gefingerpoken { mTouchingHeadsUpView = false; if (child instanceof ExpandableNotificationRow) { mPickedChild = (ExpandableNotificationRow) child; - mTouchingHeadsUpView = mPickedChild.isHeadsUp() && mPickedChild.isPinned(); + mTouchingHeadsUpView = !mStackScroller.isExpanded() + && mPickedChild.isHeadsUp() && mPickedChild.isPinned(); } break; case MotionEvent.ACTION_POINTER_UP: diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java index 09a7bf08ec19..50a49a1dbd2c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java @@ -519,7 +519,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, */ protected boolean mStartedGoingToSleep; - private static final int VISIBLE_LOCATIONS = StackViewState.LOCATION_FIRST_CARD + private static final int VISIBLE_LOCATIONS = StackViewState.LOCATION_FIRST_HUN | StackViewState.LOCATION_MAIN_AREA; private final OnChildLocationsChangedListener mNotificationLocationsChangedListener = diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java index cc0e67df39cb..49e9c3db9f30 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java @@ -75,7 +75,7 @@ public class NotificationStackScrollLayout extends ViewGroup ExpandableView.OnHeightChangedListener, NotificationGroupManager.OnGroupChangeListener { public static final float BACKGROUND_ALPHA_DIMMED = 0.7f; - private static final String TAG = "NotificationStackScrollLayout"; + private static final String TAG = "StackScroller"; private static final boolean DEBUG = false; private static final float RUBBER_BAND_FACTOR_NORMAL = 0.35f; private static final float RUBBER_BAND_FACTOR_AFTER_EXPAND = 0.15f; @@ -136,7 +136,7 @@ public class NotificationStackScrollLayout extends ViewGroup private StackScrollState mCurrentStackScrollState = new StackScrollState(this); private AmbientState mAmbientState = new AmbientState(); private NotificationGroupManager mGroupManager; - private ArrayList<View> mChildrenToAddAnimated = new ArrayList<>(); + private HashSet<View> mChildrenToAddAnimated = new HashSet<>(); private ArrayList<View> mAddedHeadsUpChildren = new ArrayList<>(); private ArrayList<View> mChildrenToRemoveAnimated = new ArrayList<>(); private ArrayList<View> mSnappedBackChildren = new ArrayList<>(); @@ -474,6 +474,7 @@ public class NotificationStackScrollLayout extends ViewGroup * modifications to {@link #mOwnScrollY} are performed to reflect it in the view layout. */ private void updateChildren() { + updateScrollStateForAddedChildren(); mAmbientState.setScrollY(mOwnScrollY); mStackScrollAlgorithm.getStackScrollState(mAmbientState, mCurrentStackScrollState); if (!isCurrentlyAnimating() && !mNeedsAnimation) { @@ -483,6 +484,28 @@ public class NotificationStackScrollLayout extends ViewGroup } } + private void updateScrollStateForAddedChildren() { + if (mChildrenToAddAnimated.isEmpty()) { + return; + } + for (int i = 0; i < getChildCount(); i++) { + ExpandableView child = (ExpandableView) getChildAt(i); + if (mChildrenToAddAnimated.contains(child)) { + int startingPosition = getPositionInLinearLayout(child); + int padding = child.needsIncreasedPadding() + ? mIncreasedPaddingBetweenElements : + mPaddingBetweenElements; + int childHeight = getIntrinsicHeight(child) + padding; + if (startingPosition < mOwnScrollY) { + // This child starts off screen, so let's keep it offscreen to keep the others visible + + mOwnScrollY += childHeight; + } + } + } + clampScrollPosition(); + } + private void requestChildrenUpdate() { if (!mChildrenUpdateRequested) { getViewTreeObserver().addOnPreDrawListener(mChildrenUpdater); @@ -1648,12 +1671,17 @@ public class NotificationStackScrollLayout extends ViewGroup bottom = (int) (lastView.getTranslationY() + lastView.getActualHeight()); bottom = Math.min(bottom, getHeight()); } - } else if (mPhoneStatusBar.getBarState() == StatusBarState.KEYGUARD) { - top = mTopPadding; + } else { + top = (int) (mTopPadding + mStackTranslation); bottom = top; } - mBackgroundBounds.top = Math.max(0, top); - mBackgroundBounds.bottom = Math.min(getHeight(), bottom); + if (mPhoneStatusBar.getBarState() != StatusBarState.KEYGUARD) { + mBackgroundBounds.top = (int) Math.max(mTopPadding + mStackTranslation, top); + } else { + // otherwise the animation from the shade to the keyguard will jump as it's maxed + mBackgroundBounds.top = Math.max(0, top); + } + mBackgroundBounds.bottom = Math.min(getHeight(), Math.max(bottom, top)); } private ActivatableNotificationView getFirstPinnedHeadsUp() { @@ -3206,6 +3234,10 @@ public class NotificationStackScrollLayout extends ViewGroup } } + public boolean isExpanded() { + return mIsExpanded; + } + /** * A listener that is notified when some child locations might have changed. */ diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java index f6959f0dfcbb..e87b36397c7a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java @@ -39,17 +39,14 @@ public class StackScrollAlgorithm { private static final String LOG_TAG = "StackScrollAlgorithm"; private static final int MAX_ITEMS_IN_BOTTOM_STACK = 3; - private static final int MAX_ITEMS_IN_TOP_STACK = 3; private int mPaddingBetweenElements; private int mIncreasedPaddingBetweenElements; private int mCollapsedSize; - private int mTopStackPeekSize; private int mBottomStackPeekSize; private int mZDistanceBetweenElements; private int mZBasicHeight; - private StackIndentationFunctor mTopStackIndentationFunctor; private StackIndentationFunctor mBottomStackIndentationFunctor; private StackScrollAlgorithmState mTempAlgorithmState = new StackScrollAlgorithmState(); @@ -58,12 +55,8 @@ public class StackScrollAlgorithm { private boolean mIsExpanded; private ExpandableView mFirstChildWhileExpanding; private boolean mExpandedOnStart; - private int mTopStackTotalSize; private int mBottomStackSlowDownLength; - private int mTopStackSlowDownLength; private int mCollapseSecondCardPadding; - private ExpandableView mFirstChild; - private int mFirstChildMinHeight; public StackScrollAlgorithm(Context context) { initView(context); @@ -71,22 +64,6 @@ public class StackScrollAlgorithm { public void initView(Context context) { initConstants(context); - updatePadding(); - } - - private void updatePadding() { - mTopStackTotalSize = mTopStackSlowDownLength + mPaddingBetweenElements - + mTopStackPeekSize; - mTopStackIndentationFunctor = new PiecewiseLinearIndentationFunctor( - MAX_ITEMS_IN_TOP_STACK, - mTopStackPeekSize, - mTopStackTotalSize - mTopStackPeekSize, - 0.5f); - mBottomStackIndentationFunctor = new PiecewiseLinearIndentationFunctor( - MAX_ITEMS_IN_BOTTOM_STACK, - mBottomStackPeekSize, - getBottomStackSlowDownLength(), - 0.5f); } public int getBottomStackSlowDownLength() { @@ -100,8 +77,6 @@ public class StackScrollAlgorithm { .getDimensionPixelSize(R.dimen.notification_divider_height_increased); mCollapsedSize = context.getResources() .getDimensionPixelSize(R.dimen.notification_min_height); - mTopStackPeekSize = context.getResources() - .getDimensionPixelSize(R.dimen.top_stack_peek_amount); mBottomStackPeekSize = context.getResources() .getDimensionPixelSize(R.dimen.bottom_stack_peek_amount); mZDistanceBetweenElements = Math.max(1, context.getResources() @@ -109,10 +84,13 @@ public class StackScrollAlgorithm { mZBasicHeight = (MAX_ITEMS_IN_BOTTOM_STACK + 1) * mZDistanceBetweenElements; mBottomStackSlowDownLength = context.getResources() .getDimensionPixelSize(R.dimen.bottom_stack_slow_down_length); - mTopStackSlowDownLength = context.getResources() - .getDimensionPixelSize(R.dimen.top_stack_slow_down_length); mCollapseSecondCardPadding = context.getResources().getDimensionPixelSize( R.dimen.notification_collapse_second_card_padding); + mBottomStackIndentationFunctor = new PiecewiseLinearIndentationFunctor( + MAX_ITEMS_IN_BOTTOM_STACK, + mBottomStackPeekSize, + getBottomStackSlowDownLength(), + 0.5f); } public void getStackScrollState(AmbientState ambientState, StackScrollState resultState) { @@ -123,32 +101,13 @@ public class StackScrollAlgorithm { // First we reset the view states to their default values. resultState.resetViewStates(); - algorithmState.itemsInTopStack = 0.0f; - algorithmState.partialInTop = 0.0f; - algorithmState.lastTopStackIndex = 0; - algorithmState.scrolledPixelsTop = 0; - algorithmState.itemsInBottomStack = 0.0f; - algorithmState.partialInBottom = 0.0f; - mFirstChildMinHeight = mFirstChild == null ? 0 : mFirstChild.getMinHeight(); - float bottomOverScroll = ambientState.getOverScrollAmount(false /* onTop */); - - int scrollY = ambientState.getScrollY(); - - // Due to the overScroller, the stackscroller can have negative scroll state. This is - // already accounted for by the top padding and doesn't need an additional adaption - scrollY = Math.max(0, scrollY); - algorithmState.scrollY = (int) (scrollY + mFirstChildMinHeight + bottomOverScroll); - - initAlgorithmState(resultState, algorithmState); - - // Phase 1: - findNumberOfItemsInTopStackAndUpdateState(resultState, algorithmState, ambientState); + initAlgorithmState(resultState, algorithmState, ambientState); - // Phase 2: updatePositionsForState(resultState, algorithmState, ambientState); - // Phase 3: - updateZValuesForState(resultState, algorithmState); + updateZValuesForState(resultState, algorithmState, ambientState); + + updateHeadsUpStates(resultState, algorithmState, ambientState); handleDraggedViews(ambientState, resultState, algorithmState); updateDimmedActivatedHideSensitive(ambientState, resultState, algorithmState); @@ -185,6 +144,7 @@ public class StackScrollAlgorithm { private void updateClipping(StackScrollState resultState, StackScrollAlgorithmState algorithmState, AmbientState ambientState) { boolean dismissAllInProgress = ambientState.isDismissAllInProgress(); + float drawStart = ambientState.getTopPadding() + ambientState.getStackTranslation(); float previousNotificationEnd = 0; float previousNotificationStart = 0; boolean previousNotificationIsSwiped = false; @@ -192,6 +152,10 @@ public class StackScrollAlgorithm { for (int i = 0; i < childCount; i++) { ExpandableView child = algorithmState.visibleChildren.get(i); StackViewState state = resultState.getViewStateForView(child); + if (!child.mustStayOnScreen()) { + previousNotificationEnd = Math.max(drawStart, previousNotificationEnd); + previousNotificationStart = Math.max(drawStart, previousNotificationStart); + } float newYTranslation = state.yTranslation; float newHeight = state.height; // apply clipping and shadow @@ -222,7 +186,7 @@ public class StackScrollAlgorithm { } else { previousNotificationIsSwiped = ambientState.getDraggedViews().contains(child); previousNotificationEnd = newNotificationEnd; - previousNotificationStart = newYTranslation + state.clipTopAmount; + previousNotificationStart =newYTranslation + state.clipTopAmount; } } } @@ -314,8 +278,20 @@ public class StackScrollAlgorithm { /** * Initialize the algorithm state like updating the visible children. */ - private void initAlgorithmState(StackScrollState resultState, - StackScrollAlgorithmState state) { + private void initAlgorithmState(StackScrollState resultState, StackScrollAlgorithmState state, + AmbientState ambientState) { + state.itemsInBottomStack = 0.0f; + state.partialInBottom = 0.0f; + float bottomOverScroll = ambientState.getOverScrollAmount(false /* onTop */); + + int scrollY = ambientState.getScrollY(); + + // Due to the overScroller, the stackscroller can have negative scroll state. This is + // already accounted for by the top padding and doesn't need an additional adaption + scrollY = Math.max(0, scrollY); + state.scrollY = (int) (scrollY + bottomOverScroll); + + //now init the visible children and update paddings ViewGroup hostView = resultState.getHostView(); int childCount = hostView.getChildCount(); state.visibleChildren.clear(); @@ -383,15 +359,9 @@ public class StackScrollAlgorithm { float bottomStackStart = bottomPeekStart - mBottomStackSlowDownLength; // The y coordinate of the current child. - float currentYPosition = 0.0f; - - // How far in is the element currently transitioning into the bottom stack. - float yPositionInScrollView = 0.0f; + float currentYPosition = -algorithmState.scrollY; int childCount = algorithmState.visibleChildren.size(); - int numberOfElementsCompletelyIn = algorithmState.partialInTop == 1.0f - ? algorithmState.lastTopStackIndex - : (int) algorithmState.itemsInTopStack; int paddingAfterChild; for (int i = 0; i < childCount; i++) { ExpandableView child = algorithmState.visibleChildren.get(i); @@ -400,47 +370,16 @@ public class StackScrollAlgorithm { paddingAfterChild = getPaddingAfterChild(algorithmState, child); int childHeight = getMaxAllowedChildHeight(child); int minHeight = child.getMinHeight(); - float yPositionInScrollViewAfterElement = yPositionInScrollView - + childHeight - + paddingAfterChild; - float scrollOffset = yPositionInScrollView - algorithmState.scrollY + - mFirstChildMinHeight; - - if (i == algorithmState.lastTopStackIndex + 1) { - // Normally the position of this child is the position in the regular scrollview, - // but if the two stacks are very close to each other, - // then have have to push it even more upwards to the position of the bottom - // stack start. - currentYPosition = Math.min(scrollOffset, bottomStackStart); - } childViewState.yTranslation = currentYPosition; + if (i == 0) { + updateFirstChildHeight(child, childViewState, childHeight, ambientState); + } // The y position after this element float nextYPosition = currentYPosition + childHeight + paddingAfterChild; - - if (i <= algorithmState.lastTopStackIndex) { + if (nextYPosition >= bottomStackStart) { // Case 1: - // We are in the top Stack - updateStateForTopStackChild(algorithmState, child, - numberOfElementsCompletelyIn, i, childHeight, childViewState, scrollOffset); - clampPositionToTopStackEnd(childViewState, childHeight); - - // check if we are overlapping with the bottom stack - if (childViewState.yTranslation + childHeight + paddingAfterChild - >= bottomStackStart && !mIsExpansionChanging && i != 0) { - // we just collapse this element slightly - int newSize = (int) Math.max(bottomStackStart - paddingAfterChild - - childViewState.yTranslation, minHeight); - childViewState.height = newSize; - updateStateForChildTransitioningInBottom(algorithmState, bottomStackStart, - child, childViewState.yTranslation, childViewState, - childHeight); - } - clampPositionToBottomStackStart(childViewState, childViewState.height, - minHeight, ambientState); - } else if (nextYPosition >= bottomStackStart) { - // Case 2: // We are in the bottom stack. if (currentYPosition >= bottomStackStart) { // According to the regular scroll view we are fully translated out of the @@ -455,36 +394,30 @@ public class StackScrollAlgorithm { childViewState, childHeight); } } else { - // Case 3: + // Case 2: // We are in the regular scroll area. childViewState.location = StackViewState.LOCATION_MAIN_AREA; - clampYTranslation(childViewState, childHeight, ambientState); + clampPositionToBottomStackStart(childViewState, childViewState.height, childHeight, + ambientState); } - // The first card is always rendered. - if (i == 0) { - childViewState.hidden = false; - childViewState.shadowAlpha = 1.0f; - childViewState.yTranslation = Math.max( - mFirstChildMinHeight - algorithmState.scrollY, 0); - if (childViewState.yTranslation + childViewState.height - > bottomPeekStart - mCollapseSecondCardPadding) { - childViewState.height = (int) Math.max( - bottomPeekStart - mCollapseSecondCardPadding - - childViewState.yTranslation, mFirstChildMinHeight); - } - childViewState.location = StackViewState.LOCATION_FIRST_CARD; + if (i == 0 && ambientState.getScrollY() <= 0) { + // The first card can get into the bottom stack if it's the only one + // on the lockscreen which pushes it up. Let's make sure that doesn't happen and + // it stays at the top + childViewState.yTranslation = Math.max(0, childViewState.yTranslation); + } + currentYPosition = childViewState.yTranslation + childHeight + paddingAfterChild; + if (currentYPosition <= 0) { + childViewState.location = StackViewState.LOCATION_HIDDEN_TOP; } if (childViewState.location == StackViewState.LOCATION_UNKNOWN) { Log.wtf(LOG_TAG, "Failed to assign location for child " + i); } - currentYPosition = childViewState.yTranslation + childHeight + paddingAfterChild; - yPositionInScrollView = yPositionInScrollViewAfterElement; childViewState.yTranslation += ambientState.getTopPadding() + ambientState.getStackTranslation(); } - updateHeadsUpStates(resultState, algorithmState, ambientState); } private int getPaddingAfterChild(StackScrollAlgorithmState algorithmState, @@ -506,24 +439,27 @@ public class StackScrollAlgorithm { ExpandableNotificationRow row = (ExpandableNotificationRow) child; if (!row.isHeadsUp()) { break; - } else if (topHeadsUpEntry == null) { - topHeadsUpEntry = row; } StackViewState childState = resultState.getViewStateForView(row); + if (topHeadsUpEntry == null) { + topHeadsUpEntry = row; + childState.location = StackViewState.LOCATION_FIRST_HUN; + } boolean isTopEntry = topHeadsUpEntry == row; + float unmodifiedEndLocation = childState.yTranslation + childState.height; if (mIsExpanded) { - // Ensure that the heads up is always visible even when scrolled off from the bottom - float bottomPosition = ambientState.getMaxHeadsUpTranslation() - childState.height; - childState.yTranslation = Math.min(childState.yTranslation, - bottomPosition); + // Ensure that the heads up is always visible even when scrolled off + clampHunToTop(ambientState, row, childState); + clampHunToMaxTranslation(ambientState, row, childState); } if (row.isPinned()) { childState.yTranslation = Math.max(childState.yTranslation, 0); childState.height = Math.max(row.getIntrinsicHeight(), childState.height); - if (!isTopEntry) { + StackViewState topState = resultState.getViewStateForView(topHeadsUpEntry); + if (!isTopEntry && (!mIsExpanded + || unmodifiedEndLocation < topState.yTranslation + topState.height)) { // Ensure that a headsUp doesn't vertically extend further than the heads-up at // the top most z-position - StackViewState topState = resultState.getViewStateForView(topHeadsUpEntry); childState.height = row.getIntrinsicHeight(); childState.yTranslation = topState.yTranslation + topState.height - childState.height; @@ -532,17 +468,23 @@ public class StackScrollAlgorithm { } } - /** - * Clamp the yTranslation both up and down to valid positions. - * - * @param childViewState the view state of the child - * @param minHeight the minimum height of this child - */ - private void clampYTranslation(StackViewState childViewState, int minHeight, - AmbientState ambientState) { - clampPositionToBottomStackStart(childViewState, childViewState.height, minHeight, - ambientState); - clampPositionToTopStackEnd(childViewState, childViewState.height); + private void clampHunToTop(AmbientState ambientState, ExpandableNotificationRow row, + StackViewState childState) { + float newTranslation = Math.max(ambientState.getTopPadding() + + ambientState.getStackTranslation(), childState.yTranslation); + childState.height = (int) Math.max(childState.height - (newTranslation + - childState.yTranslation), row.getMinHeight()); + childState.yTranslation = newTranslation; + } + + private void clampHunToMaxTranslation(AmbientState ambientState, ExpandableNotificationRow row, + StackViewState childState) { + float newTranslation; + float bottomPosition = ambientState.getMaxHeadsUpTranslation() - row.getMinHeight(); + newTranslation = Math.min(childState.yTranslation, bottomPosition); + childState.height = (int) Math.max(childState.height + - (childState.yTranslation - newTranslation), row.getMinHeight()); + childState.yTranslation = newTranslation; } /** @@ -569,19 +511,6 @@ public class StackScrollAlgorithm { } } - /** - * Clamp the yTranslation of the child up such that its end is at lest on the end of the top - * stack. - * - * @param childViewState the view state of the child - * @param childHeight the height of this child - */ - private void clampPositionToTopStackEnd(StackViewState childViewState, - int childHeight) { - childViewState.yTranslation = Math.max(childViewState.yTranslation, - mFirstChildMinHeight - childHeight); - } - private int getMaxAllowedChildHeight(View child) { if (child instanceof ExpandableView) { ExpandableView expandableView = (ExpandableView) child; @@ -611,9 +540,6 @@ public class StackScrollAlgorithm { } childViewState.yTranslation = transitioningPositionStart + offset - newHeight - getPaddingAfterChild(algorithmState, child); - - // We want at least to be at the end of the top stack when collapsing - clampPositionToTopStackEnd(childViewState, newHeight); childViewState.location = StackViewState.LOCATION_MAIN_AREA; } @@ -642,177 +568,59 @@ public class StackScrollAlgorithm { } childViewState.height = minHeight; childViewState.yTranslation = currentYPosition - minHeight; - clampPositionToTopStackEnd(childViewState, minHeight); } - private void updateStateForTopStackChild(StackScrollAlgorithmState algorithmState, - ExpandableView child, int numberOfElementsCompletelyIn, int i, int childHeight, - StackViewState childViewState, float scrollOffset) { - - - // First we calculate the index relative to the current stack window of size at most - // {@link #MAX_ITEMS_IN_TOP_STACK} - int paddedIndex = i - 1 - - Math.max(numberOfElementsCompletelyIn - MAX_ITEMS_IN_TOP_STACK, 0); - if (paddedIndex >= 0) { - - // We are currently visually entering the top stack - float distanceToStack = (childHeight + getPaddingAfterChild(algorithmState, child)) - - algorithmState.scrolledPixelsTop; - if (i == algorithmState.lastTopStackIndex - && distanceToStack > (mTopStackTotalSize - + getPaddingAfterChild(algorithmState, child))) { - - // Child is currently translating into stack but not yet inside slow down zone. - // Handle it like the regular scrollview. - childViewState.yTranslation = scrollOffset; - } else { - // Apply stacking logic. - float numItemsBefore; - if (i == algorithmState.lastTopStackIndex) { - numItemsBefore = 1.0f - - (distanceToStack / (mTopStackTotalSize - + getPaddingAfterChild(algorithmState, child))); - } else { - numItemsBefore = algorithmState.itemsInTopStack - i; - } - // The end position of the current child - float currentChildEndY = mFirstChildMinHeight + mTopStackTotalSize - - mTopStackIndentationFunctor.getValue(numItemsBefore); - childViewState.yTranslation = currentChildEndY - childHeight; - } - childViewState.location = StackViewState.LOCATION_TOP_STACK_PEEKING; - } else { - if (paddedIndex == -1) { - childViewState.shadowAlpha = 1.0f - algorithmState.partialInTop; - } else { - // We are hidden behind the top card and faded out, so we can hide ourselves. - childViewState.hidden = true; - childViewState.shadowAlpha = 0.0f; - } - childViewState.yTranslation = mFirstChildMinHeight - childHeight; - childViewState.location = StackViewState.LOCATION_TOP_STACK_HIDDEN; - } - - - } /** - * Find the number of items in the top stack and update the result state if needed. + * Update the height of the first child i.e clamp it to the bottom stack + * * - * @param resultState The result state to update if a height change of an child occurs - * @param algorithmState The state in which the current pass of the algorithm is currently in - */ - private void findNumberOfItemsInTopStackAndUpdateState(StackScrollState resultState, - StackScrollAlgorithmState algorithmState, AmbientState ambientState) { - // The y Position if the element would be in a regular scrollView - float yPositionInScrollView = 0.0f; - int childCount = algorithmState.visibleChildren.size(); - // find the number of elements in the top stack. - for (int i = 0; i < childCount; i++) { - ExpandableView child = algorithmState.visibleChildren.get(i); - StackViewState childViewState = resultState.getViewStateForView(child); - int childHeight = getMaxAllowedChildHeight(child); - int paddingAfterChild = getPaddingAfterChild(algorithmState, child); - float yPositionInScrollViewAfterElement = yPositionInScrollView - + childHeight - + paddingAfterChild; - if (yPositionInScrollView < algorithmState.scrollY) { - if (i == 0 && algorithmState.scrollY <= mFirstChildMinHeight) { - - // The starting position of the bottom stack peek - int bottomPeekStart = ambientState.getInnerHeight() - mBottomStackPeekSize - - mCollapseSecondCardPadding; - // Collapse and expand the first child while the shade is being expanded - float maxHeight = mIsExpansionChanging && child == mFirstChildWhileExpanding - ? mFirstChildMaxHeight - : childHeight; - childViewState.height = (int) Math.max(Math.min(bottomPeekStart, maxHeight), - mFirstChildMinHeight); - algorithmState.itemsInTopStack = 1.0f; - - } else if (yPositionInScrollViewAfterElement < algorithmState.scrollY) { - // According to the regular scroll view we are fully off screen - algorithmState.itemsInTopStack += 1.0f; - if (i == 0) { - childViewState.height = child.getMinHeight(); - } - } else { - // According to the regular scroll view we are partially off screen - - // How much did we scroll into this child - algorithmState.scrolledPixelsTop = algorithmState.scrollY - - yPositionInScrollView; - algorithmState.partialInTop = (algorithmState.scrolledPixelsTop) / (childHeight - + paddingAfterChild); - - // Our element can be expanded, so this can get negative - algorithmState.partialInTop = Math.max(0.0f, algorithmState.partialInTop); - algorithmState.itemsInTopStack += algorithmState.partialInTop; - - if (i == 0) { - // If it is expanded we have to collapse it to a new size - float newSize = yPositionInScrollViewAfterElement - - paddingAfterChild - - algorithmState.scrollY + mFirstChildMinHeight; - newSize = Math.max(mFirstChildMinHeight, newSize); - algorithmState.itemsInTopStack = 1.0f; - childViewState.height = (int) newSize; - } - algorithmState.lastTopStackIndex = i; - break; - } - } else { - algorithmState.lastTopStackIndex = i - 1; - // We are already past the stack so we can end the loop - break; - } - yPositionInScrollView = yPositionInScrollViewAfterElement; - } + * @param child the child to update + * @param childViewState the viewstate of the child + * @param childHeight the height of the child + * @param ambientState The ambient state of the algorithm + */ + private void updateFirstChildHeight(ExpandableView child, StackViewState childViewState, + int childHeight, AmbientState ambientState) { + + // The starting position of the bottom stack peek + int bottomPeekStart = ambientState.getInnerHeight() - mBottomStackPeekSize - + mCollapseSecondCardPadding + ambientState.getScrollY(); + // Collapse and expand the first child while the shade is being expanded + float maxHeight = mIsExpansionChanging && child == mFirstChildWhileExpanding + ? mFirstChildMaxHeight + : childHeight; + childViewState.height = (int) Math.max(Math.min(bottomPeekStart, maxHeight), + child.getMinHeight()); } /** * Calculate the Z positions for all children based on the number of items in both stacks and * save it in the resultState - * - * @param resultState The result state to update the zTranslation values + * @param resultState The result state to update the zTranslation values * @param algorithmState The state in which the current pass of the algorithm is currently in + * @param ambientState The ambient state of the algorithm */ private void updateZValuesForState(StackScrollState resultState, - StackScrollAlgorithmState algorithmState) { + StackScrollAlgorithmState algorithmState, AmbientState ambientState) { int childCount = algorithmState.visibleChildren.size(); - for (int i = 0; i < childCount; i++) { - View child = algorithmState.visibleChildren.get(i); + int childrenOnTop = 0; + for (int i = childCount - 1; i >= 0; i--) { + ExpandableView child = algorithmState.visibleChildren.get(i); StackViewState childViewState = resultState.getViewStateForView(child); - if (i < algorithmState.itemsInTopStack) { - float stackIndex = algorithmState.itemsInTopStack - i; - - // Ensure that the topmost item is a little bit higher than the rest when fully - // scrolled, to avoid drawing errors when swiping it out - float max = MAX_ITEMS_IN_TOP_STACK + (i == 0 ? 2.5f : 2); - stackIndex = Math.min(stackIndex, max); - if (i == 0 && algorithmState.itemsInTopStack < 2.0f) { - - // We only have the top item and an additional item in the top stack, - // Interpolate the index from 0 to 2 while the second item is - // translating in. - stackIndex -= 1.0f; - if (algorithmState.scrollY > mFirstChildMinHeight) { - - // Since there is a shadow treshhold, we cant just interpolate from 0 to - // 2 but we interpolate from 0.1f to 2.0f when scrolled in. The jump in - // height will not be noticable since we have padding in between. - stackIndex = 0.1f + stackIndex * 1.9f; - } - } - childViewState.zTranslation = mZBasicHeight - + stackIndex * mZDistanceBetweenElements; - } else if (i > (childCount - 1 - algorithmState.itemsInBottomStack)) { + if (i > (childCount - 1 - algorithmState.itemsInBottomStack)) { + // We are in the bottom stack float numItemsAbove = i - (childCount - 1 - algorithmState.itemsInBottomStack); - float translationZ = mZBasicHeight + childViewState.zTranslation = mZBasicHeight - numItemsAbove * mZDistanceBetweenElements; - childViewState.zTranslation = translationZ; + } else if (child.mustStayOnScreen() + && childViewState.yTranslation < ambientState.getTopPadding() + + ambientState.getStackTranslation()) { + // TODO; do this more cleanly + childrenOnTop++; + childViewState.zTranslation = mZBasicHeight + + childrenOnTop * mZDistanceBetweenElements; } else { childViewState.zTranslation = mZBasicHeight; } @@ -897,7 +705,6 @@ public class StackScrollAlgorithm { } public void notifyChildrenChanged(final NotificationStackScrollLayout hostView) { - mFirstChild = hostView.getFirstChildNotGone(); if (mIsExpansionChanging) { hostView.post(new Runnable() { @Override @@ -922,26 +729,6 @@ public class StackScrollAlgorithm { public int scrollY; /** - * The quantity of items which are in the top stack. - */ - public float itemsInTopStack; - - /** - * how far in is the element currently transitioning into the top stack - */ - public float partialInTop; - - /** - * The number of pixels the last child in the top stack has scrolled in to the stack - */ - public float scrolledPixelsTop; - - /** - * The last item index which is in the top stack. - */ - public int lastTopStackIndex; - - /** * The quantity of items which are in the bottom stack. */ public float itemsInBottomStack; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackViewState.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackViewState.java index 05fa27d04e4e..fa151950c1cc 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackViewState.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackViewState.java @@ -24,12 +24,11 @@ public class StackViewState extends ViewState { // These are flags such that we can create masks for filtering. public static final int LOCATION_UNKNOWN = 0x00; - public static final int LOCATION_FIRST_CARD = 0x01; - public static final int LOCATION_TOP_STACK_HIDDEN = 0x02; - public static final int LOCATION_TOP_STACK_PEEKING = 0x04; - public static final int LOCATION_MAIN_AREA = 0x08; - public static final int LOCATION_BOTTOM_STACK_PEEKING = 0x10; - public static final int LOCATION_BOTTOM_STACK_HIDDEN = 0x20; + public static final int LOCATION_FIRST_HUN = 0x01; + public static final int LOCATION_HIDDEN_TOP = 0x02; + public static final int LOCATION_MAIN_AREA = 0x04; + public static final int LOCATION_BOTTOM_STACK_PEEKING = 0x08; + public static final int LOCATION_BOTTOM_STACK_HIDDEN = 0x10; /** The view isn't layouted at all. */ public static final int LOCATION_GONE = 0x40; |