Refactored the viewstates for more modularity

Viewstates are now much more independent of the
Stack scroller and can be used on their own.

Test: Add notification, everything still works
Bug: 32437839
Change-Id: I535ea9200dcaafef9eb833c2f0301cb09731542f
This commit is contained in:
Selim Cinek
2016-11-09 18:28:20 -08:00
parent 76932df9ec
commit bbcebde5f4
12 changed files with 290 additions and 202 deletions

View File

@@ -22,12 +22,17 @@ import android.util.AttributeSet;
import android.view.View;
import com.android.systemui.R;
import com.android.systemui.statusbar.stack.ExpandableViewState;
import com.android.systemui.statusbar.stack.StackScrollState;
public class DismissView extends StackScrollerDecorView {
private final int mClearAllTopPadding;
private DismissViewButton mDismissButton;
public DismissView(Context context, AttributeSet attrs) {
super(context, attrs);
mClearAllTopPadding = context.getResources().getDimensionPixelSize(
R.dimen.clear_all_padding_top);
}
@Override
@@ -63,4 +68,21 @@ public class DismissView extends StackScrollerDecorView {
public boolean isButtonVisible() {
return mDismissButton.getAlpha() != 0.0f;
}
@Override
public ExpandableViewState createNewViewState(StackScrollState stackScrollState) {
return new DismissViewState();
}
public class DismissViewState extends ExpandableViewState {
@Override
public void applyToView(View view) {
super.applyToView(view);
if (view instanceof DismissView) {
DismissView dismissView = (DismissView) view;
boolean visible = this.clipTopAmount < mClearAllTopPadding;
dismissView.performVisibilityAnimation(visible && !dismissView.willBeGone());
}
}
}
}

View File

@@ -23,6 +23,8 @@ import android.view.View;
import android.widget.TextView;
import com.android.systemui.R;
import com.android.systemui.statusbar.stack.ExpandableViewState;
import com.android.systemui.statusbar.stack.StackScrollState;
public class EmptyShadeView extends StackScrollerDecorView {
@@ -40,4 +42,22 @@ public class EmptyShadeView extends StackScrollerDecorView {
protected View findContentView() {
return findViewById(R.id.no_notifications);
}
@Override
public ExpandableViewState createNewViewState(StackScrollState stackScrollState) {
return new EmptyShadeViewState();
}
public static class EmptyShadeViewState extends ExpandableViewState {
@Override
public void applyToView(View view) {
super.applyToView(view);
if (view instanceof EmptyShadeView) {
EmptyShadeView emptyShadeView = (EmptyShadeView) view;
boolean visible = this.clipTopAmount <= 0;
emptyShadeView.performVisibilityAnimation(
visible && !emptyShadeView.willBeGone());
}
}
}
}

View File

@@ -54,7 +54,7 @@ import com.android.systemui.statusbar.stack.NotificationChildrenContainer;
import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
import com.android.systemui.statusbar.stack.StackScrollState;
import com.android.systemui.statusbar.stack.StackStateAnimator;
import com.android.systemui.statusbar.stack.StackViewState;
import com.android.systemui.statusbar.stack.ExpandableViewState;
import java.util.ArrayList;
import java.util.List;
@@ -459,7 +459,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
public void getChildrenStates(StackScrollState resultState) {
if (mIsSummaryWithChildren) {
StackViewState parentState = resultState.getViewStateForView(this);
ExpandableViewState parentState = resultState.getViewStateForView(this);
mChildrenContainer.getState(resultState, parentState);
}
}
@@ -1679,4 +1679,30 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
public interface OnExpandClickListener {
void onExpandClicked(NotificationData.Entry clickedEntry, boolean nowExpanded);
}
@Override
public ExpandableViewState createNewViewState(StackScrollState stackScrollState) {
return new NotificationViewState(stackScrollState);
}
public static class NotificationViewState extends ExpandableViewState {
private final StackScrollState mOverallState;
private NotificationViewState(StackScrollState stackScrollState) {
mOverallState = stackScrollState;
}
@Override
public void applyToView(View view) {
super.applyToView(view);
if (view instanceof ExpandableNotificationRow) {
ExpandableNotificationRow row = (ExpandableNotificationRow) view;
if (this.isBottomClipped) {
row.setClipToActualHeight(true);
}
row.applyChildrenState(mOverallState);
}
}
}
}

View File

@@ -25,6 +25,8 @@ import android.view.ViewGroup;
import android.widget.FrameLayout;
import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
import com.android.systemui.statusbar.stack.ExpandableViewState;
import com.android.systemui.statusbar.stack.StackScrollState;
import java.util.ArrayList;
@@ -438,6 +440,10 @@ public abstract class ExpandableView extends FrameLayout {
public void setActualHeightAnimating(boolean animating) {}
public ExpandableViewState createNewViewState(StackScrollState stackScrollState) {
return new ExpandableViewState();
}
/**
* A listener notifying when {@link #getActualHeight} changes.
*/

View File

@@ -197,7 +197,7 @@ import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
import com.android.systemui.statusbar.stack.NotificationStackScrollLayout
.OnChildLocationsChangedListener;
import com.android.systemui.statusbar.stack.StackStateAnimator;
import com.android.systemui.statusbar.stack.StackViewState;
import com.android.systemui.statusbar.stack.ExpandableViewState;
import com.android.systemui.volume.VolumeComponent;
import java.io.FileDescriptor;
@@ -569,8 +569,8 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
*/
protected boolean mStartedGoingToSleep;
private static final int VISIBLE_LOCATIONS = StackViewState.LOCATION_FIRST_HUN
| StackViewState.LOCATION_MAIN_AREA;
private static final int VISIBLE_LOCATIONS = ExpandableViewState.LOCATION_FIRST_HUN
| ExpandableViewState.LOCATION_MAIN_AREA;
private final OnChildLocationsChangedListener mNotificationLocationsChangedListener =
new OnChildLocationsChangedListener() {

View File

@@ -16,20 +16,51 @@
package com.android.systemui.statusbar.stack;
import android.view.View;
import com.android.systemui.statusbar.ExpandableView;
/**
* A state of an expandable view
*/
public class StackViewState extends ViewState {
public class ExpandableViewState extends ViewState {
// These are flags such that we can create masks for filtering.
/**
* No known location. This is the default and should not be set after an invocation of the
* algorithm.
*/
public static final int LOCATION_UNKNOWN = 0x00;
/**
* The location is the first heads up notification, so on the very top.
*/
public static final int LOCATION_FIRST_HUN = 0x01;
/**
* The location is hidden / scrolled away on the top.
*/
public static final int LOCATION_HIDDEN_TOP = 0x02;
/**
* The location is in the main area of the screen and visible.
*/
public static final int LOCATION_MAIN_AREA = 0x04;
/**
* The location is in the bottom stack and it's peeking
*/
public static final int LOCATION_BOTTOM_STACK_PEEKING = 0x08;
/**
* The location is in the bottom stack and it's hidden.
*/
public static final int LOCATION_BOTTOM_STACK_HIDDEN = 0x10;
/** The view isn't layouted at all. */
/**
* The view isn't layouted at all.
* */
public static final int LOCATION_GONE = 0x40;
public int height;
@@ -65,8 +96,8 @@ public class StackViewState extends ViewState {
@Override
public void copyFrom(ViewState viewState) {
super.copyFrom(viewState);
if (viewState instanceof StackViewState) {
StackViewState svs = (StackViewState) viewState;
if (viewState instanceof ExpandableViewState) {
ExpandableViewState svs = (ExpandableViewState) viewState;
height = svs.height;
dimmed = svs.dimmed;
shadowAlpha = svs.shadowAlpha;
@@ -79,4 +110,50 @@ public class StackViewState extends ViewState {
isBottomClipped = svs.isBottomClipped;
}
}
/**
* Applies a {@link ExpandableViewState} to a {@link ExpandableView}.
*/
@Override
public void applyToView(View view) {
super.applyToView(view);
if (view instanceof ExpandableView) {
ExpandableView expandableView = (ExpandableView) view;
int height = expandableView.getActualHeight();
int newHeight = this.height;
// apply height
if (height != newHeight) {
expandableView.setActualHeight(newHeight, false /* notifyListeners */);
}
float shadowAlpha = expandableView.getShadowAlpha();
float newShadowAlpha = this.shadowAlpha;
// apply shadowAlpha
if (shadowAlpha != newShadowAlpha) {
expandableView.setShadowAlpha(newShadowAlpha);
}
// apply dimming
expandableView.setDimmed(this.dimmed, false /* animate */);
// apply hiding sensitive
expandableView.setHideSensitive(
this.hideSensitive, false /* animated */, 0 /* delay */, 0 /* duration */);
// apply below shelf speedBump
expandableView.setBelowSpeedBump(this.belowSpeedBump);
// apply dark
expandableView.setDark(this.dark, false /* animate */, 0 /* delay */);
// apply clipping
float oldClipTopAmount = expandableView.getClipTopAmount();
if (oldClipTopAmount != this.clipTopAmount) {
expandableView.setClipTopAmount(this.clipTopAmount);
}
}
}
}

View File

@@ -412,7 +412,7 @@ public class NotificationChildrenContainer extends ViewGroup {
* @param resultState the state to update
* @param parentState the state of the parent
*/
public void getState(StackScrollState resultState, StackViewState parentState) {
public void getState(StackScrollState resultState, ExpandableViewState parentState) {
int childCount = mChildren.size();
int yPosition = mNotificationHeaderMargin;
boolean firstChild = true;
@@ -449,7 +449,7 @@ public class NotificationChildrenContainer extends ViewGroup {
firstChild = false;
}
StackViewState childState = resultState.getViewStateForView(child);
ExpandableViewState childState = resultState.getViewStateForView(child);
int intrinsicHeight = child.getIntrinsicHeight();
if (childrenExpanded) {
// When a group is expanded and moving into bottom stack, the bottom visible child
@@ -530,7 +530,7 @@ public class NotificationChildrenContainer extends ViewGroup {
* @return true if children after this one should be hidden.
*/
private boolean updateChildStateForExpandedGroup(ExpandableNotificationRow child,
int parentHeight, StackViewState childState, int yPosition) {
int parentHeight, ExpandableViewState childState, int yPosition) {
final int top = yPosition + child.getClipTopAmount();
final int intrinsicHeight = child.getIntrinsicHeight();
final int bottom = top + intrinsicHeight;
@@ -570,8 +570,8 @@ public class NotificationChildrenContainer extends ViewGroup {
|| mNotificationParent.isGroupExpansionChanging();
for (int i = 0; i < childCount; i++) {
ExpandableNotificationRow child = mChildren.get(i);
StackViewState viewState = state.getViewStateForView(child);
state.applyState(child, viewState);
ExpandableViewState viewState = state.getViewStateForView(child);
viewState.applyToView(child);
// layout the divider
View divider = mDividers.get(i);
@@ -584,16 +584,16 @@ public class NotificationChildrenContainer extends ViewGroup {
}
tmpState.hidden = !dividersVisible;
tmpState.alpha = alpha;
state.applyViewState(divider, tmpState);
tmpState.applyToView(divider);
// There is no fake shadow to be drawn on the children
child.setFakeShadowIntensity(0.0f, 0.0f, 0, 0);
}
if (mOverflowNumber != null) {
state.applyViewState(mOverflowNumber, mGroupOverFlowState);
mGroupOverFlowState.applyToView(mOverflowNumber);
mNeverAppliedGroupState = false;
}
if (mNotificationHeader != null) {
state.applyViewState(mNotificationHeader, mHeaderViewState);
mHeaderViewState.applyToView(mNotificationHeader);
}
}
@@ -617,7 +617,7 @@ public class NotificationChildrenContainer extends ViewGroup {
|| mNotificationParent.isGroupExpansionChanging();
for (int i = childCount - 1; i >= 0; i--) {
ExpandableNotificationRow child = mChildren.get(i);
StackViewState viewState = state.getViewStateForView(child);
ExpandableViewState viewState = state.getViewStateForView(child);
stateAnimator.startStackAnimations(child, viewState, state, -1, baseDelay);
// layout the divider
@@ -639,7 +639,7 @@ public class NotificationChildrenContainer extends ViewGroup {
if (mNeverAppliedGroupState) {
float alpha = mGroupOverFlowState.alpha;
mGroupOverFlowState.alpha = 0;
state.applyViewState(mOverflowNumber, mGroupOverFlowState);
mGroupOverFlowState.applyToView(mOverflowNumber);
mGroupOverFlowState.alpha = alpha;
mNeverAppliedGroupState = false;
}
@@ -647,7 +647,7 @@ public class NotificationChildrenContainer extends ViewGroup {
baseDelay, duration);
}
if (mNotificationHeader != null) {
state.applyViewState(mNotificationHeader, mHeaderViewState);
mHeaderViewState.applyToView(mNotificationHeader);
}
}

View File

@@ -541,15 +541,15 @@ public class NotificationStackScrollLayout extends ViewGroup
* Returns the location the given child is currently rendered at.
*
* @param child the child to get the location for
* @return one of {@link StackViewState}'s <code>LOCATION_*</code> constants
* @return one of {@link ExpandableViewState}'s <code>LOCATION_*</code> constants
*/
public int getChildLocation(View child) {
StackViewState childViewState = mCurrentStackScrollState.getViewStateForView(child);
ExpandableViewState childViewState = mCurrentStackScrollState.getViewStateForView(child);
if (childViewState == null) {
return StackViewState.LOCATION_UNKNOWN;
return ExpandableViewState.LOCATION_UNKNOWN;
}
if (childViewState.gone) {
return StackViewState.LOCATION_GONE;
return ExpandableViewState.LOCATION_GONE;
}
return childViewState.location;
}
@@ -1072,7 +1072,7 @@ public class NotificationStackScrollLayout extends ViewGroup
row.getStatusBarNotification());
mGroupExpandedForMeasure = false;
row.setForceUnlocked(false);
StackViewState viewState = mCurrentStackScrollState.getViewStateForView(view);
ExpandableViewState viewState = mCurrentStackScrollState.getViewStateForView(view);
if (viewState != null) {
// The view could have been removed
return Math.min(viewState.height, maxContentHeight);
@@ -2730,7 +2730,7 @@ public class NotificationStackScrollLayout extends ViewGroup
row.setHeadsupDisappearRunning(false);
}
} else {
StackViewState viewState = mCurrentStackScrollState.getViewStateForView(row);
ExpandableViewState viewState = mCurrentStackScrollState.getViewStateForView(row);
if (viewState == null) {
// A view state was never generated for this view, so we don't need to animate
// this. This may happen with notification children.
@@ -2755,7 +2755,7 @@ public class NotificationStackScrollLayout extends ViewGroup
mAddedHeadsUpChildren.clear();
}
private boolean shouldHunAppearFromBottom(StackViewState viewState) {
private boolean shouldHunAppearFromBottom(ExpandableViewState viewState) {
if (viewState.yTranslation + viewState.height < mAmbientState.getMaxHeadsUpTranslation()) {
return false;
}

View File

@@ -128,7 +128,7 @@ public class StackScrollAlgorithm {
int childCount = algorithmState.visibleChildren.size();
for (int i = 0; i < childCount; i++) {
View child = algorithmState.visibleChildren.get(i);
StackViewState childViewState = resultState.getViewStateForView(child);
ExpandableViewState childViewState = resultState.getViewStateForView(child);
// The speed bump can also be gone, so equality needs to be taken when comparing
// indices.
@@ -144,7 +144,7 @@ public class StackScrollAlgorithm {
int childCount = algorithmState.visibleChildren.size();
for (int i = 0; i < childCount; i++) {
ExpandableView child = algorithmState.visibleChildren.get(i);
StackViewState state = resultState.getViewStateForView(child);
ExpandableViewState state = resultState.getViewStateForView(child);
if (!child.mustStayOnScreen()) {
previousNotificationEnd = Math.max(drawStart, previousNotificationEnd);
previousNotificationStart = Math.max(drawStart, previousNotificationStart);
@@ -195,7 +195,7 @@ public class StackScrollAlgorithm {
int childCount = algorithmState.visibleChildren.size();
for (int i = 0; i < childCount; i++) {
View child = algorithmState.visibleChildren.get(i);
StackViewState childViewState = resultState.getViewStateForView(child);
ExpandableViewState childViewState = resultState.getViewStateForView(child);
childViewState.dimmed = dimmed;
childViewState.dark = dark;
childViewState.hideSensitive = hideSensitive;
@@ -219,7 +219,7 @@ public class StackScrollAlgorithm {
if (!draggedViews.contains(nextChild)) {
// only if the view is not dragged itself we modify its state to be fully
// visible
StackViewState viewState = resultState.getViewStateForView(
ExpandableViewState viewState = resultState.getViewStateForView(
nextChild);
// The child below the dragged one must be fully visible
if (ambientState.isShadeExpanded()) {
@@ -229,7 +229,7 @@ public class StackScrollAlgorithm {
}
// Lets set the alpha to the one it currently has, as its currently being dragged
StackViewState viewState = resultState.getViewStateForView(draggedView);
ExpandableViewState viewState = resultState.getViewStateForView(draggedView);
// The dragged child should keep the set alpha
viewState.alpha = draggedView.getAlpha();
}
@@ -284,7 +284,7 @@ public class StackScrollAlgorithm {
if (row.isSummaryWithChildren() && children != null) {
for (ExpandableNotificationRow childRow : children) {
if (childRow.getVisibility() != View.GONE) {
StackViewState childState
ExpandableViewState childState
= resultState.getViewStateForView(childRow);
childState.notGoneIndex = notGoneIndex;
notGoneIndex++;
@@ -300,7 +300,7 @@ public class StackScrollAlgorithm {
private int updateNotGoneIndex(StackScrollState resultState,
StackScrollAlgorithmState state, int notGoneIndex,
ExpandableView v) {
StackViewState viewState = resultState.getViewStateForView(v);
ExpandableViewState viewState = resultState.getViewStateForView(v);
viewState.notGoneIndex = notGoneIndex;
state.visibleChildren.add(v);
notGoneIndex++;
@@ -336,8 +336,8 @@ public class StackScrollAlgorithm {
StackScrollAlgorithmState algorithmState, AmbientState ambientState,
float currentYPosition, float bottomStackStart) {
ExpandableView child = algorithmState.visibleChildren.get(i);
StackViewState childViewState = resultState.getViewStateForView(child);
childViewState.location = StackViewState.LOCATION_UNKNOWN;
ExpandableViewState childViewState = resultState.getViewStateForView(child);
childViewState.location = ExpandableViewState.LOCATION_UNKNOWN;
int paddingAfterChild = getPaddingAfterChild(algorithmState, child);
int childHeight = getMaxAllowedChildHeight(child);
int collapsedHeight = child.getCollapsedHeight();
@@ -367,7 +367,7 @@ public class StackScrollAlgorithm {
} else {
// Case 2:
// We are in the regular scroll area.
childViewState.location = StackViewState.LOCATION_MAIN_AREA;
childViewState.location = ExpandableViewState.LOCATION_MAIN_AREA;
clampPositionToBottomStackStart(childViewState, childViewState.height, childHeight,
ambientState);
}
@@ -380,9 +380,9 @@ public class StackScrollAlgorithm {
}
currentYPosition = childViewState.yTranslation + childHeight + paddingAfterChild;
if (currentYPosition <= 0) {
childViewState.location = StackViewState.LOCATION_HIDDEN_TOP;
childViewState.location = ExpandableViewState.LOCATION_HIDDEN_TOP;
}
if (childViewState.location == StackViewState.LOCATION_UNKNOWN) {
if (childViewState.location == ExpandableViewState.LOCATION_UNKNOWN) {
Log.wtf(LOG_TAG, "Failed to assign location for child " + i);
}
@@ -414,10 +414,10 @@ public class StackScrollAlgorithm {
if (!row.isHeadsUp()) {
break;
}
StackViewState childState = resultState.getViewStateForView(row);
ExpandableViewState childState = resultState.getViewStateForView(row);
if (topHeadsUpEntry == null) {
topHeadsUpEntry = row;
childState.location = StackViewState.LOCATION_FIRST_HUN;
childState.location = ExpandableViewState.LOCATION_FIRST_HUN;
}
boolean isTopEntry = topHeadsUpEntry == row;
float unmodifiedEndLocation = childState.yTranslation + childState.height;
@@ -429,7 +429,7 @@ public class StackScrollAlgorithm {
if (row.isPinned()) {
childState.yTranslation = Math.max(childState.yTranslation, 0);
childState.height = Math.max(row.getIntrinsicHeight(), childState.height);
StackViewState topState = resultState.getViewStateForView(topHeadsUpEntry);
ExpandableViewState 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
@@ -443,7 +443,7 @@ public class StackScrollAlgorithm {
}
private void clampHunToTop(AmbientState ambientState, ExpandableNotificationRow row,
StackViewState childState) {
ExpandableViewState childState) {
float newTranslation = Math.max(ambientState.getTopPadding()
+ ambientState.getStackTranslation(), childState.yTranslation);
childState.height = (int) Math.max(childState.height - (newTranslation
@@ -452,7 +452,7 @@ public class StackScrollAlgorithm {
}
private void clampHunToMaxTranslation(AmbientState ambientState, ExpandableNotificationRow row,
StackViewState childState) {
ExpandableViewState childState) {
float newTranslation;
float bottomPosition = ambientState.getMaxHeadsUpTranslation() - row.getCollapsedHeight();
newTranslation = Math.min(childState.yTranslation, bottomPosition);
@@ -469,7 +469,7 @@ public class StackScrollAlgorithm {
* @param childHeight the height of this child
* @param minHeight the minumum Height of the View
*/
private void clampPositionToBottomStackStart(StackViewState childViewState,
private void clampPositionToBottomStackStart(ExpandableViewState childViewState,
int childHeight, int minHeight, AmbientState ambientState) {
int bottomStackStart = ambientState.getInnerHeight()
@@ -495,7 +495,7 @@ public class StackScrollAlgorithm {
private void updateStateForChildTransitioningInBottom(StackScrollAlgorithmState algorithmState,
float transitioningPositionStart, ExpandableView child, float currentYPosition,
StackViewState childViewState, int childHeight) {
ExpandableViewState childViewState, int childHeight) {
// This is the transitioning element on top of bottom stack, calculate how far we are in.
algorithmState.partialInBottom = 1.0f - (
@@ -514,11 +514,11 @@ public class StackScrollAlgorithm {
}
childViewState.yTranslation = transitioningPositionStart + offset - newHeight
- getPaddingAfterChild(algorithmState, child);
childViewState.location = StackViewState.LOCATION_MAIN_AREA;
childViewState.location = ExpandableViewState.LOCATION_MAIN_AREA;
}
private void updateStateForChildFullyInBottomStack(StackScrollAlgorithmState algorithmState,
float transitioningPositionStart, StackViewState childViewState,
float transitioningPositionStart, ExpandableViewState childViewState,
int collapsedHeight, AmbientState ambientState, ExpandableView child) {
float currentYPosition;
algorithmState.itemsInBottomStack += 1.0f;
@@ -527,7 +527,7 @@ public class StackScrollAlgorithm {
currentYPosition = transitioningPositionStart
+ mBottomStackIndentationFunctor.getValue(algorithmState.itemsInBottomStack)
- getPaddingAfterChild(algorithmState, child);
childViewState.location = StackViewState.LOCATION_BOTTOM_STACK_PEEKING;
childViewState.location = ExpandableViewState.LOCATION_BOTTOM_STACK_PEEKING;
} else {
// we are fully inside the stack
if (algorithmState.itemsInBottomStack > MAX_ITEMS_IN_BOTTOM_STACK + 2) {
@@ -537,7 +537,7 @@ public class StackScrollAlgorithm {
> MAX_ITEMS_IN_BOTTOM_STACK + 1) {
childViewState.shadowAlpha = 1.0f - algorithmState.partialInBottom;
}
childViewState.location = StackViewState.LOCATION_BOTTOM_STACK_HIDDEN;
childViewState.location = ExpandableViewState.LOCATION_BOTTOM_STACK_HIDDEN;
currentYPosition = ambientState.getInnerHeight();
}
childViewState.height = collapsedHeight;
@@ -553,7 +553,7 @@ public class StackScrollAlgorithm {
* @param childHeight the height of the child
* @param ambientState The ambient state of the algorithm
*/
protected void updateFirstChildHeight(ExpandableView child, StackViewState childViewState,
protected void updateFirstChildHeight(ExpandableView child, ExpandableViewState childViewState,
int childHeight, AmbientState ambientState) {
// The starting position of the bottom stack peek
@@ -585,7 +585,7 @@ public class StackScrollAlgorithm {
StackScrollState resultState, StackScrollAlgorithmState algorithmState,
AmbientState ambientState) {
ExpandableView child = algorithmState.visibleChildren.get(i);
StackViewState childViewState = resultState.getViewStateForView(child);
ExpandableViewState childViewState = resultState.getViewStateForView(child);
if (i > (childCount - 1 - algorithmState.itemsInBottomStack)) {
// We are in the bottom stack
float numItemsAbove = i - (childCount - 1 - algorithmState.itemsInBottomStack);

View File

@@ -21,8 +21,6 @@ import android.view.View;
import android.view.ViewGroup;
import com.android.systemui.R;
import com.android.systemui.statusbar.DismissView;
import com.android.systemui.statusbar.EmptyShadeView;
import com.android.systemui.statusbar.ExpandableNotificationRow;
import com.android.systemui.statusbar.ExpandableView;
@@ -38,14 +36,11 @@ public class StackScrollState {
private static final String CHILD_NOT_FOUND_TAG = "StackScrollStateNoSuchChild";
private final ViewGroup mHostView;
private WeakHashMap<ExpandableView, StackViewState> mStateMap;
private final int mClearAllTopPadding;
private WeakHashMap<ExpandableView, ExpandableViewState> mStateMap;
public StackScrollState(ViewGroup hostView) {
mHostView = hostView;
mStateMap = new WeakHashMap<>();
mClearAllTopPadding = hostView.getContext().getResources().getDimensionPixelSize(
R.dimen.clear_all_padding_top);
}
public ViewGroup getHostView() {
@@ -73,9 +68,9 @@ public class StackScrollState {
}
private void resetViewState(ExpandableView view) {
StackViewState viewState = mStateMap.get(view);
ExpandableViewState viewState = mStateMap.get(view);
if (viewState == null) {
viewState = new StackViewState();
viewState = view.createNewViewState(this);
mStateMap.put(view, viewState);
}
// initialize with the default values of the view
@@ -87,7 +82,7 @@ public class StackScrollState {
viewState.hidden = false;
}
public StackViewState getViewStateForView(View requestedView) {
public ExpandableViewState getViewStateForView(View requestedView) {
return mStateMap.get(requestedView);
}
@@ -103,130 +98,16 @@ public class StackScrollState {
int numChildren = mHostView.getChildCount();
for (int i = 0; i < numChildren; i++) {
ExpandableView child = (ExpandableView) mHostView.getChildAt(i);
StackViewState state = mStateMap.get(child);
if (!applyState(child, state)) {
ExpandableViewState state = mStateMap.get(child);
if (state == null) {
Log.wtf(CHILD_NOT_FOUND_TAG, "No child state was found when applying this state " +
"to the hostView");
continue;
}
if (child instanceof DismissView) {
DismissView dismissView = (DismissView) child;
boolean visible = state.clipTopAmount < mClearAllTopPadding;
dismissView.performVisibilityAnimation(visible && !dismissView.willBeGone());
} else if (child instanceof EmptyShadeView) {
EmptyShadeView emptyShadeView = (EmptyShadeView) child;
boolean visible = state.clipTopAmount <= 0;
emptyShadeView.performVisibilityAnimation(
visible && !emptyShadeView.willBeGone());
if (state.gone) {
continue;
}
}
}
/**
* Applies a {@link StackViewState} to an {@link ExpandableView}.
*
* @return whether the state was applied correctly
*/
public boolean applyState(ExpandableView view, StackViewState state) {
if (state == null) {
Log.wtf(CHILD_NOT_FOUND_TAG, "No child state was found when applying this state " +
"to the hostView");
return false;
}
if (state.gone) {
return false;
}
applyViewState(view, state);
int height = view.getActualHeight();
int newHeight = state.height;
// apply height
if (height != newHeight) {
view.setActualHeight(newHeight, false /* notifyListeners */);
}
float shadowAlpha = view.getShadowAlpha();
float newShadowAlpha = state.shadowAlpha;
// apply shadowAlpha
if (shadowAlpha != newShadowAlpha) {
view.setShadowAlpha(newShadowAlpha);
}
// apply dimming
view.setDimmed(state.dimmed, false /* animate */);
// apply hiding sensitive
view.setHideSensitive(
state.hideSensitive, false /* animated */, 0 /* delay */, 0 /* duration */);
// apply speed bump state
view.setBelowSpeedBump(state.belowSpeedBump);
// apply dark
view.setDark(state.dark, false /* animate */, 0 /* delay */);
// apply clipping
float oldClipTopAmount = view.getClipTopAmount();
if (oldClipTopAmount != state.clipTopAmount) {
view.setClipTopAmount(state.clipTopAmount);
}
if (view instanceof ExpandableNotificationRow) {
ExpandableNotificationRow row = (ExpandableNotificationRow) view;
if (state.isBottomClipped) {
row.setClipToActualHeight(true);
}
row.applyChildrenState(this);
}
return true;
}
/**
* Applies a {@link ViewState} to a normal view.
*/
public void applyViewState(View view, ViewState state) {
float alpha = view.getAlpha();
float yTranslation = view.getTranslationY();
float xTranslation = view.getTranslationX();
float zTranslation = view.getTranslationZ();
float newAlpha = state.alpha;
float newYTranslation = state.yTranslation;
float newZTranslation = state.zTranslation;
boolean becomesInvisible = newAlpha == 0.0f || state.hidden;
if (alpha != newAlpha && xTranslation == 0) {
// apply layer type
boolean becomesFullyVisible = newAlpha == 1.0f;
boolean newLayerTypeIsHardware = !becomesInvisible && !becomesFullyVisible
&& view.hasOverlappingRendering();
int layerType = view.getLayerType();
int newLayerType = newLayerTypeIsHardware
? View.LAYER_TYPE_HARDWARE
: View.LAYER_TYPE_NONE;
if (layerType != newLayerType) {
view.setLayerType(newLayerType, null);
}
// apply alpha
view.setAlpha(newAlpha);
}
// apply visibility
int oldVisibility = view.getVisibility();
int newVisibility = becomesInvisible ? View.INVISIBLE : View.VISIBLE;
if (newVisibility != oldVisibility) {
if (!(view instanceof ExpandableView) || !((ExpandableView) view).willBeGone()) {
// We don't want views to change visibility when they are animating to GONE
view.setVisibility(newVisibility);
}
}
// apply yTranslation
if (yTranslation != newYTranslation) {
view.setTranslationY(newYTranslation);
}
// apply zTranslation
if (zTranslation != newZTranslation) {
view.setTranslationZ(newZTranslation);
state.applyToView(child);
}
}
}

View File

@@ -75,7 +75,7 @@ public class StackStateAnimator {
private final Interpolator mHeadsUpAppearInterpolator;
private final int mGoToFullShadeAppearingTranslation;
private final StackViewState mTmpState = new StackViewState();
private final ExpandableViewState mTmpState = new ExpandableViewState();
public NotificationStackScrollLayout mHostLayout;
private ArrayList<NotificationStackScrollLayout.AnimationEvent> mNewEvents =
new ArrayList<>();
@@ -122,7 +122,7 @@ public class StackStateAnimator {
for (int i = 0; i < childCount; i++) {
final ExpandableView child = (ExpandableView) mHostLayout.getChildAt(i);
StackViewState viewState = finalState.getViewStateForView(child);
ExpandableViewState viewState = finalState.getViewStateForView(child);
if (viewState == null || child.getVisibility() == View.GONE
|| applyWithoutAnimation(child, viewState, finalState)) {
continue;
@@ -145,7 +145,7 @@ public class StackStateAnimator {
*
* @return true if no animation should be performed
*/
private boolean applyWithoutAnimation(ExpandableView child, StackViewState viewState,
private boolean applyWithoutAnimation(ExpandableView child, ExpandableViewState viewState,
StackScrollState finalState) {
if (mShadeExpanded) {
return false;
@@ -162,7 +162,7 @@ public class StackStateAnimator {
// This is another headsUp which might move. Let's animate!
return false;
}
finalState.applyState(child, viewState);
viewState.applyToView(child);
return true;
}
@@ -171,7 +171,7 @@ public class StackStateAnimator {
for (int i = childCount - 1; i >= 0; i--) {
final ExpandableView child = (ExpandableView) mHostLayout.getChildAt(i);
StackViewState viewState = finalState.getViewStateForView(child);
ExpandableViewState viewState = finalState.getViewStateForView(child);
if (viewState == null || child.getVisibility() == View.GONE) {
continue;
}
@@ -184,16 +184,16 @@ public class StackStateAnimator {
/**
* Start an animation to the given {@link StackViewState}.
* Start an animation to the given {@link ExpandableViewState}.
*
* @param child the child to start the animation on
* @param viewState the {@link StackViewState} of the view to animate to
* @param viewState the {@link ExpandableViewState} of the view to animate to
* @param finalState the final state after the animation
* @param i the index of the view; only relevant if the view is the speed bump and is
* ignored otherwise
* @param fixedDelay a fixed delay if desired or -1 if the delay should be calculated
*/
public void startStackAnimations(final ExpandableView child, StackViewState viewState,
public void startStackAnimations(final ExpandableView child, ExpandableViewState viewState,
StackScrollState finalState, int i, long fixedDelay) {
boolean wasAdded = mNewAddChildren.contains(child);
long duration = mCurrentLength;
@@ -270,7 +270,7 @@ public class StackStateAnimator {
* Start an animation to a new {@link ViewState}.
*
* @param child the child to start the animation on
* @param viewState the {@link StackViewState} of the view to animate to
* @param viewState the {@link ExpandableViewState} of the view to animate to
* @param delay a fixed delay
* @param duration the duration of the animation
*/
@@ -319,7 +319,7 @@ public class StackStateAnimator {
}
}
private long calculateChildAnimationDelay(StackViewState viewState,
private long calculateChildAnimationDelay(ExpandableViewState viewState,
StackScrollState finalState) {
if (mAnimationFilter.hasDarkEvent) {
return calculateDelayDark(viewState);
@@ -374,7 +374,7 @@ public class StackStateAnimator {
return minDelay;
}
private long calculateDelayDark(StackViewState viewState) {
private long calculateDelayDark(ExpandableViewState viewState) {
int referenceIndex;
if (mAnimationFilter.darkAnimationOriginIndex ==
NotificationStackScrollLayout.AnimationEvent.DARK_ANIMATION_ORIGIN_INDEX_ABOVE) {
@@ -388,14 +388,14 @@ public class StackStateAnimator {
return Math.abs(referenceIndex - viewState.notGoneIndex) * ANIMATION_DELAY_PER_ELEMENT_DARK;
}
private long calculateDelayGoToFullShade(StackViewState viewState) {
private long calculateDelayGoToFullShade(ExpandableViewState viewState) {
float index = viewState.notGoneIndex;
index = (float) Math.pow(index, 0.7f);
return (long) (index * ANIMATION_DELAY_PER_ELEMENT_GO_TO_FULL_SHADE);
}
private void startShadowAlphaAnimation(final ExpandableView child,
StackViewState viewState, long duration, long delay) {
ExpandableViewState viewState, long duration, long delay) {
Float previousStartValue = getChildTag(child, TAG_START_SHADOW_ALPHA);
Float previousEndValue = getChildTag(child, TAG_END_SHADOW_ALPHA);
float newEndValue = viewState.shadowAlpha;
@@ -454,7 +454,7 @@ public class StackStateAnimator {
}
private void startHeightAnimation(final ExpandableView child,
StackViewState viewState, long duration, long delay) {
ExpandableViewState viewState, long duration, long delay) {
Integer previousStartValue = getChildTag(child, TAG_START_HEIGHT);
Integer previousEndValue = getChildTag(child, TAG_END_HEIGHT);
int newEndValue = viewState.height;
@@ -532,7 +532,7 @@ public class StackStateAnimator {
}
private void startInsetAnimation(final ExpandableView child,
StackViewState viewState, long duration, long delay) {
ExpandableViewState viewState, long duration, long delay) {
Integer previousStartValue = getChildTag(child, TAG_START_TOP_INSET);
Integer previousEndValue = getChildTag(child, TAG_END_TOP_INSET);
int newEndValue = viewState.clipTopAmount;
@@ -864,13 +864,13 @@ public class StackStateAnimator {
NotificationStackScrollLayout.AnimationEvent.ANIMATION_TYPE_ADD) {
// This item is added, initialize it's properties.
StackViewState viewState = finalState
ExpandableViewState viewState = finalState
.getViewStateForView(changingView);
if (viewState == null) {
// The position for this child was never generated, let's continue.
continue;
}
finalState.applyState(changingView, viewState);
viewState.applyToView(changingView);
mNewAddChildren.add(changingView);
} else if (event.animationType ==
@@ -882,7 +882,7 @@ public class StackStateAnimator {
// Find the amount to translate up. This is needed in order to understand the
// direction of the remove animation (either downwards or upwards)
StackViewState viewState = finalState
ExpandableViewState viewState = finalState
.getViewStateForView(event.viewAfterChangingView);
int actualHeight = changingView.getActualHeight();
// upwards by default
@@ -920,7 +920,7 @@ public class StackStateAnimator {
} else if (event.animationType == NotificationStackScrollLayout
.AnimationEvent.ANIMATION_TYPE_HEADS_UP_APPEAR) {
// This item is added, initialize it's properties.
StackViewState viewState = finalState.getViewStateForView(changingView);
ExpandableViewState viewState = finalState.getViewStateForView(changingView);
mTmpState.copyFrom(viewState);
if (event.headsUpFromBottom) {
mTmpState.yTranslation = mHeadsUpAppearHeightBottom;
@@ -928,7 +928,7 @@ public class StackStateAnimator {
mTmpState.yTranslation = -mTmpState.height;
}
mHeadsUpAppearChildren.add(changingView);
finalState.applyState(changingView, mTmpState);
mTmpState.applyToView(changingView);
} else if (event.animationType == NotificationStackScrollLayout
.AnimationEvent.ANIMATION_TYPE_HEADS_UP_DISAPPEAR ||
event.animationType == NotificationStackScrollLayout

View File

@@ -18,6 +18,8 @@ package com.android.systemui.statusbar.stack;
import android.view.View;
import com.android.systemui.statusbar.ExpandableView;
/**
* A state of a view. This can be used to apply a set of view properties to a view with
* {@link com.android.systemui.statusbar.stack.StackScrollState} or start animations with
@@ -46,4 +48,58 @@ public class ViewState {
gone = view.getVisibility() == View.GONE;
hidden = false;
}
/**
* Applies a {@link ViewState} to a normal view.
*/
public void applyToView(View view) {
if (this.gone) {
// don't do anything with it
return;
}
float alpha = view.getAlpha();
float yTranslation = view.getTranslationY();
float xTranslation = view.getTranslationX();
float zTranslation = view.getTranslationZ();
float newAlpha = this.alpha;
float newYTranslation = this.yTranslation;
float newZTranslation = this.zTranslation;
boolean becomesInvisible = newAlpha == 0.0f || this.hidden;
if (alpha != newAlpha && xTranslation == 0) {
// apply layer type
boolean becomesFullyVisible = newAlpha == 1.0f;
boolean newLayerTypeIsHardware = !becomesInvisible && !becomesFullyVisible
&& view.hasOverlappingRendering();
int layerType = view.getLayerType();
int newLayerType = newLayerTypeIsHardware
? View.LAYER_TYPE_HARDWARE
: View.LAYER_TYPE_NONE;
if (layerType != newLayerType) {
view.setLayerType(newLayerType, null);
}
// apply alpha
view.setAlpha(newAlpha);
}
// apply visibility
int oldVisibility = view.getVisibility();
int newVisibility = becomesInvisible ? View.INVISIBLE : View.VISIBLE;
if (newVisibility != oldVisibility) {
if (!(view instanceof ExpandableView) || !((ExpandableView) view).willBeGone()) {
// We don't want views to change visibility when they are animating to GONE
view.setVisibility(newVisibility);
}
}
// apply yTranslation
if (yTranslation != newYTranslation) {
view.setTranslationY(newYTranslation);
}
// apply zTranslation
if (zTranslation != newZTranslation) {
view.setTranslationZ(newZTranslation);
}
}
}