diff options
author | Selim Cinek <cinek@google.com> | 2015-02-20 15:56:28 +0100 |
---|---|---|
committer | Selim Cinek <cinek@google.com> | 2015-03-12 15:53:40 -0700 |
commit | b036ca4de8e93d83bcdc093fbf8f096dc18a810d (patch) | |
tree | af042b833704fdae53139513b85cc9087788bffc /packages/SystemUI | |
parent | 67cf4a06c7f12389ccf131627bfcdfe8409fa598 (diff) | |
download | frameworks_base-b036ca4de8e93d83bcdc093fbf8f096dc18a810d.zip frameworks_base-b036ca4de8e93d83bcdc093fbf8f096dc18a810d.tar.gz frameworks_base-b036ca4de8e93d83bcdc093fbf8f096dc18a810d.tar.bz2 |
Made stack scroller animation and apply logic reusable
Change-Id: I5d513dfc91b2a041ccefaa65074a64d1f211ec4a
Diffstat (limited to 'packages/SystemUI')
7 files changed, 396 insertions, 289 deletions
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 b14a70d..3bdc250 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java @@ -161,7 +161,7 @@ import com.android.systemui.statusbar.policy.UserSwitcherController; import com.android.systemui.statusbar.policy.ZenModeController; import com.android.systemui.statusbar.stack.NotificationStackScrollLayout; import com.android.systemui.statusbar.stack.NotificationStackScrollLayout.OnChildLocationsChangedListener; -import com.android.systemui.statusbar.stack.StackScrollState.ViewState; +import com.android.systemui.statusbar.stack.StackViewState; import com.android.systemui.volume.VolumeComponent; import java.io.FileDescriptor; @@ -444,10 +444,10 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, // Fingerprint (as computed by getLoggingFingerprint() of the last logged state. private int mLastLoggedStateFingerprint; - private static final int VISIBLE_LOCATIONS = ViewState.LOCATION_FIRST_CARD - | ViewState.LOCATION_TOP_STACK_PEEKING - | ViewState.LOCATION_MAIN_AREA - | ViewState.LOCATION_BOTTOM_STACK_PEEKING; + private static final int VISIBLE_LOCATIONS = StackViewState.LOCATION_FIRST_CARD + | StackViewState.LOCATION_TOP_STACK_PEEKING + | StackViewState.LOCATION_MAIN_AREA + | StackViewState.LOCATION_BOTTOM_STACK_PEEKING; private final OnChildLocationsChangedListener mNotificationLocationsChangedListener = new OnChildLocationsChangedListener() { 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 6dcbed6..e30ab8d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java @@ -46,7 +46,6 @@ import com.android.systemui.statusbar.StackScrollerDecorView; import com.android.systemui.statusbar.StatusBarState; import com.android.systemui.statusbar.phone.PhoneStatusBar; import com.android.systemui.statusbar.policy.ScrollAdapter; -import com.android.systemui.statusbar.stack.StackScrollState.ViewState; import java.util.ArrayList; import java.util.HashSet; @@ -375,15 +374,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 ViewState}'s <code>LOCATION_*</code> constants + * @return one of {@link StackViewState}'s <code>LOCATION_*</code> constants */ public int getChildLocation(View child) { - ViewState childViewState = mCurrentStackScrollState.getViewStateForView(child); + StackViewState childViewState = mCurrentStackScrollState.getViewStateForView(child); if (childViewState == null) { - return ViewState.LOCATION_UNKNOWN; + return StackViewState.LOCATION_UNKNOWN; } if (childViewState.gone) { - return ViewState.LOCATION_GONE; + return StackViewState.LOCATION_GONE; } return childViewState.location; } 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 ddc4251..2c124d0 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java @@ -178,7 +178,7 @@ public class StackScrollAlgorithm { int childCount = algorithmState.visibleChildren.size(); for (int i = 0; i < childCount; i++) { View child = algorithmState.visibleChildren.get(i); - StackScrollState.ViewState childViewState = resultState.getViewStateForView(child); + StackViewState childViewState = resultState.getViewStateForView(child); // The speed bump can also be gone, so equality needs to be taken when comparing // indices. @@ -194,7 +194,7 @@ public class StackScrollAlgorithm { int childCount = algorithmState.visibleChildren.size(); for (int i = 0; i < childCount; i++) { ExpandableView child = algorithmState.visibleChildren.get(i); - StackScrollState.ViewState state = resultState.getViewStateForView(child); + StackViewState state = resultState.getViewStateForView(child); float newYTranslation = state.yTranslation + state.height * (1f - state.scale) / 2f; float newHeight = state.height * state.scale; // apply clipping and shadow @@ -242,8 +242,8 @@ public class StackScrollAlgorithm { * @param backgroundHeight the desired background height. The shadows of the view will be * based on this height and the content will be clipped from the top */ - private void updateChildClippingAndBackground(StackScrollState.ViewState state, - float realHeight, float clipHeight, float backgroundHeight) { + private void updateChildClippingAndBackground(StackViewState state, float realHeight, + float clipHeight, float backgroundHeight) { if (realHeight > clipHeight) { // Rather overlap than create a hole. state.topOverLap = (int) Math.floor((realHeight - clipHeight) / state.scale); @@ -270,7 +270,7 @@ public class StackScrollAlgorithm { int childCount = algorithmState.visibleChildren.size(); for (int i = 0; i < childCount; i++) { View child = algorithmState.visibleChildren.get(i); - StackScrollState.ViewState childViewState = resultState.getViewStateForView(child); + StackViewState childViewState = resultState.getViewStateForView(child); childViewState.dimmed = dimmed; childViewState.dark = dark; childViewState.hideSensitive = hideSensitive; @@ -297,14 +297,14 @@ public class StackScrollAlgorithm { if (!draggedViews.contains(nextChild)) { // only if the view is not dragged itself we modify its state to be fully // visible - StackScrollState.ViewState viewState = resultState.getViewStateForView( + StackViewState viewState = resultState.getViewStateForView( nextChild); // The child below the dragged one must be fully visible viewState.alpha = 1; } // Lets set the alpha to the one it currently has, as its currently being dragged - StackScrollState.ViewState viewState = resultState.getViewStateForView(draggedView); + StackViewState viewState = resultState.getViewStateForView(draggedView); // The dragged child should keep the set alpha viewState.alpha = draggedView.getAlpha(); } @@ -320,12 +320,14 @@ public class StackScrollAlgorithm { int childCount = hostView.getChildCount(); state.visibleChildren.clear(); state.visibleChildren.ensureCapacity(childCount); + int notGoneIndex = 0; for (int i = 0; i < childCount; i++) { ExpandableView v = (ExpandableView) hostView.getChildAt(i); if (v.getVisibility() != View.GONE) { - StackScrollState.ViewState viewState = resultState.getViewStateForView(v); - viewState.notGoneIndex = state.visibleChildren.size(); + StackViewState viewState = resultState.getViewStateForView(v); + viewState.notGoneIndex = notGoneIndex; state.visibleChildren.add(v); + notGoneIndex++; } } } @@ -355,8 +357,8 @@ public class StackScrollAlgorithm { int numberOfElementsCompletelyIn = (int) algorithmState.itemsInTopStack; for (int i = 0; i < childCount; i++) { ExpandableView child = algorithmState.visibleChildren.get(i); - StackScrollState.ViewState childViewState = resultState.getViewStateForView(child); - childViewState.location = StackScrollState.ViewState.LOCATION_UNKNOWN; + StackViewState childViewState = resultState.getViewStateForView(child); + childViewState.location = StackViewState.LOCATION_UNKNOWN; int childHeight = getMaxAllowedChildHeight(child); float yPositionInScrollViewAfterElement = yPositionInScrollView + childHeight @@ -413,7 +415,7 @@ public class StackScrollAlgorithm { } else { // Case 3: // We are in the regular scroll area. - childViewState.location = StackScrollState.ViewState.LOCATION_MAIN_AREA; + childViewState.location = StackViewState.LOCATION_MAIN_AREA; clampYTranslation(childViewState, childHeight); } @@ -427,9 +429,9 @@ public class StackScrollAlgorithm { bottomPeekStart - mCollapseSecondCardPadding - childViewState.yTranslation, mCollapsedSize); } - childViewState.location = StackScrollState.ViewState.LOCATION_FIRST_CARD; + childViewState.location = StackViewState.LOCATION_FIRST_CARD; } - if (childViewState.location == StackScrollState.ViewState.LOCATION_UNKNOWN) { + if (childViewState.location == StackViewState.LOCATION_UNKNOWN) { Log.wtf(LOG_TAG, "Failed to assign location for child " + i); } currentYPosition = childViewState.yTranslation + childHeight + mPaddingBetweenElements; @@ -445,7 +447,7 @@ public class StackScrollAlgorithm { * @param childViewState the view state of the child * @param childHeight the height of this child */ - private void clampYTranslation(StackScrollState.ViewState childViewState, int childHeight) { + private void clampYTranslation(StackViewState childViewState, int childHeight) { clampPositionToBottomStackStart(childViewState, childHeight); clampPositionToTopStackEnd(childViewState, childHeight); } @@ -457,7 +459,7 @@ public class StackScrollAlgorithm { * @param childViewState the view state of the child * @param childHeight the height of this child */ - private void clampPositionToBottomStackStart(StackScrollState.ViewState childViewState, + private void clampPositionToBottomStackStart(StackViewState childViewState, int childHeight) { childViewState.yTranslation = Math.min(childViewState.yTranslation, mInnerHeight - mBottomStackPeekSize - mCollapseSecondCardPadding - childHeight); @@ -470,7 +472,7 @@ public class StackScrollAlgorithm { * @param childViewState the view state of the child * @param childHeight the height of this child */ - private void clampPositionToTopStackEnd(StackScrollState.ViewState childViewState, + private void clampPositionToTopStackEnd(StackViewState childViewState, int childHeight) { childViewState.yTranslation = Math.max(childViewState.yTranslation, mCollapsedSize - childHeight); @@ -489,7 +491,7 @@ public class StackScrollAlgorithm { private void updateStateForChildTransitioningInBottom(StackScrollAlgorithmState algorithmState, float transitioningPositionStart, float bottomPeakStart, float currentYPosition, - StackScrollState.ViewState childViewState, int childHeight) { + StackViewState childViewState, int childHeight) { // This is the transitioning element on top of bottom stack, calculate how far we are in. algorithmState.partialInBottom = 1.0f - ( @@ -510,11 +512,11 @@ public class StackScrollAlgorithm { // We want at least to be at the end of the top stack when collapsing clampPositionToTopStackEnd(childViewState, newHeight); - childViewState.location = StackScrollState.ViewState.LOCATION_MAIN_AREA; + childViewState.location = StackViewState.LOCATION_MAIN_AREA; } private void updateStateForChildFullyInBottomStack(StackScrollAlgorithmState algorithmState, - float transitioningPositionStart, StackScrollState.ViewState childViewState, + float transitioningPositionStart, StackViewState childViewState, int childHeight) { float currentYPosition; @@ -524,7 +526,7 @@ public class StackScrollAlgorithm { currentYPosition = transitioningPositionStart + mBottomStackIndentationFunctor.getValue(algorithmState.itemsInBottomStack) - mPaddingBetweenElements; - childViewState.location = StackScrollState.ViewState.LOCATION_BOTTOM_STACK_PEEKING; + childViewState.location = StackViewState.LOCATION_BOTTOM_STACK_PEEKING; } else { // we are fully inside the stack if (algorithmState.itemsInBottomStack > MAX_ITEMS_IN_BOTTOM_STACK + 2) { @@ -533,7 +535,7 @@ public class StackScrollAlgorithm { > MAX_ITEMS_IN_BOTTOM_STACK + 1) { childViewState.alpha = 1.0f - algorithmState.partialInBottom; } - childViewState.location = StackScrollState.ViewState.LOCATION_BOTTOM_STACK_HIDDEN; + childViewState.location = StackViewState.LOCATION_BOTTOM_STACK_HIDDEN; currentYPosition = mInnerHeight; } childViewState.yTranslation = currentYPosition - childHeight; @@ -542,7 +544,7 @@ public class StackScrollAlgorithm { private void updateStateForTopStackChild(StackScrollAlgorithmState algorithmState, int numberOfElementsCompletelyIn, int i, int childHeight, - StackScrollState.ViewState childViewState, float scrollOffset) { + StackViewState childViewState, float scrollOffset) { // First we calculate the index relative to the current stack window of size at most @@ -574,7 +576,7 @@ public class StackScrollAlgorithm { - mTopStackIndentationFunctor.getValue(numItemsBefore); childViewState.yTranslation = currentChildEndY - childHeight; } - childViewState.location = StackScrollState.ViewState.LOCATION_TOP_STACK_PEEKING; + childViewState.location = StackViewState.LOCATION_TOP_STACK_PEEKING; } else { if (paddedIndex == -1) { childViewState.alpha = 1.0f - algorithmState.partialInTop; @@ -583,7 +585,7 @@ public class StackScrollAlgorithm { childViewState.alpha = 0.0f; } childViewState.yTranslation = mCollapsedSize - childHeight; - childViewState.location = StackScrollState.ViewState.LOCATION_TOP_STACK_HIDDEN; + childViewState.location = StackViewState.LOCATION_TOP_STACK_HIDDEN; } @@ -605,7 +607,7 @@ public class StackScrollAlgorithm { // find the number of elements in the top stack. for (int i = 0; i < childCount; i++) { ExpandableView child = algorithmState.visibleChildren.get(i); - StackScrollState.ViewState childViewState = resultState.getViewStateForView(child); + StackViewState childViewState = resultState.getViewStateForView(child); int childHeight = getMaxAllowedChildHeight(child); float yPositionInScrollViewAfterElement = yPositionInScrollView + childHeight @@ -676,7 +678,7 @@ public class StackScrollAlgorithm { int childCount = algorithmState.visibleChildren.size(); for (int i = 0; i < childCount; i++) { View child = algorithmState.visibleChildren.get(i); - StackScrollState.ViewState childViewState = resultState.getViewStateForView(child); + StackViewState childViewState = resultState.getViewStateForView(child); if (i < algorithmState.itemsInTopStack) { float stackIndex = algorithmState.itemsInTopStack - i; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java index 0b1ce8f..adfe953 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java @@ -39,13 +39,13 @@ public class StackScrollState { private static final String CHILD_NOT_FOUND_TAG = "StackScrollStateNoSuchChild"; private final ViewGroup mHostView; - private Map<ExpandableView, ViewState> mStateMap; + private Map<ExpandableView, StackViewState> mStateMap; private final Rect mClipRect = new Rect(); private final int mClearAllTopPadding; public StackScrollState(ViewGroup hostView) { mHostView = hostView; - mStateMap = new HashMap<ExpandableView, ViewState>(); + mStateMap = new HashMap<ExpandableView, StackViewState>(); mClearAllTopPadding = hostView.getContext().getResources().getDimensionPixelSize( R.dimen.clear_all_padding_top); } @@ -58,20 +58,24 @@ public class StackScrollState { int numChildren = mHostView.getChildCount(); for (int i = 0; i < numChildren; i++) { ExpandableView child = (ExpandableView) mHostView.getChildAt(i); - ViewState viewState = mStateMap.get(child); - if (viewState == null) { - viewState = new ViewState(); - mStateMap.put(child, viewState); - } - // initialize with the default values of the view - viewState.height = child.getIntrinsicHeight(); - viewState.gone = child.getVisibility() == View.GONE; - viewState.alpha = 1; - viewState.notGoneIndex = -1; + resetViewState(child); } } - public ViewState getViewStateForView(View requestedView) { + private void resetViewState(ExpandableView view) { + StackViewState viewState = mStateMap.get(view); + if (viewState == null) { + viewState = new StackViewState(); + mStateMap.put(view, viewState); + } + // initialize with the default values of the view + viewState.height = view.getIntrinsicHeight(); + viewState.gone = view.getVisibility() == View.GONE; + viewState.alpha = 1; + viewState.notGoneIndex = -1; + } + + public StackViewState getViewStateForView(View requestedView) { return mStateMap.get(requestedView); } @@ -87,102 +91,123 @@ public class StackScrollState { int numChildren = mHostView.getChildCount(); for (int i = 0; i < numChildren; i++) { ExpandableView child = (ExpandableView) mHostView.getChildAt(i); - ViewState 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"); + StackViewState state = mStateMap.get(child); + if (!applyState(child, state)) { continue; } - if (!state.gone) { - float alpha = child.getAlpha(); - float yTranslation = child.getTranslationY(); - float xTranslation = child.getTranslationX(); - float zTranslation = child.getTranslationZ(); - float scale = child.getScaleX(); - int height = child.getActualHeight(); - float newAlpha = state.alpha; - float newYTranslation = state.yTranslation; - float newZTranslation = state.zTranslation; - float newScale = state.scale; - int newHeight = state.height; - boolean becomesInvisible = newAlpha == 0.0f; - if (alpha != newAlpha && xTranslation == 0) { - // apply layer type - boolean becomesFullyVisible = newAlpha == 1.0f; - boolean newLayerTypeIsHardware = !becomesInvisible && !becomesFullyVisible; - int layerType = child.getLayerType(); - int newLayerType = newLayerTypeIsHardware - ? View.LAYER_TYPE_HARDWARE - : View.LAYER_TYPE_NONE; - if (layerType != newLayerType) { - child.setLayerType(newLayerType, null); - } - - // apply alpha - child.setAlpha(newAlpha); - } - - // apply visibility - int oldVisibility = child.getVisibility(); - int newVisibility = becomesInvisible ? View.INVISIBLE : View.VISIBLE; - if (newVisibility != oldVisibility) { - child.setVisibility(newVisibility); - } - - // apply yTranslation - if (yTranslation != newYTranslation) { - child.setTranslationY(newYTranslation); - } - - // apply zTranslation - if (zTranslation != newZTranslation) { - child.setTranslationZ(newZTranslation); - } - - // apply scale - if (scale != newScale) { - child.setScaleX(newScale); - child.setScaleY(newScale); - } - - // apply height - if (height != newHeight) { - child.setActualHeight(newHeight, false /* notifyListeners */); - } - - // apply dimming - child.setDimmed(state.dimmed, false /* animate */); - - // apply dark - child.setDark(state.dark, false /* animate */, 0 /* delay */); - - // apply hiding sensitive - child.setHideSensitive( - state.hideSensitive, false /* animated */, 0 /* delay */, 0 /* duration */); - - // apply speed bump state - child.setBelowSpeedBump(state.belowSpeedBump); - - // apply clipping - float oldClipTopAmount = child.getClipTopAmount(); - if (oldClipTopAmount != state.clipTopAmount) { - child.setClipTopAmount(state.clipTopAmount); - } - updateChildClip(child, newHeight, state.topOverLap); - - if(child instanceof SpeedBumpView) { - performSpeedBumpAnimation(i, (SpeedBumpView) child, state, 0); - } else if (child instanceof DismissView) { - DismissView dismissView = (DismissView) child; - boolean visible = state.topOverLap < mClearAllTopPadding; - dismissView.performVisibilityAnimation(visible && !dismissView.willBeGone()); - } else if (child instanceof EmptyShadeView) { - EmptyShadeView emptyShadeView = (EmptyShadeView) child; - boolean visible = state.topOverLap <= 0; - emptyShadeView.performVisibilityAnimation( - visible && !emptyShadeView.willBeGone()); - } + if(child instanceof SpeedBumpView) { + performSpeedBumpAnimation(i, (SpeedBumpView) child, state, 0); + } else if (child instanceof DismissView) { + DismissView dismissView = (DismissView) child; + boolean visible = state.topOverLap < mClearAllTopPadding; + dismissView.performVisibilityAnimation(visible && !dismissView.willBeGone()); + } else if (child instanceof EmptyShadeView) { + EmptyShadeView emptyShadeView = (EmptyShadeView) child; + boolean visible = state.topOverLap <= 0; + emptyShadeView.performVisibilityAnimation( + visible && !emptyShadeView.willBeGone()); + } + } + } + + /** + * 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 */); + } + + // apply dimming + view.setDimmed(state.dimmed, false /* animate */); + + // apply dark + view.setDark(state.dark, false /* animate */, 0 /* delay */); + + // apply hiding sensitive + view.setHideSensitive( + state.hideSensitive, false /* animated */, 0 /* delay */, 0 /* duration */); + + // apply speed bump state + view.setBelowSpeedBump(state.belowSpeedBump); + + // apply clipping + float oldClipTopAmount = view.getClipTopAmount(); + if (oldClipTopAmount != state.clipTopAmount) { + view.setClipTopAmount(state.clipTopAmount); + } + updateChildClip(view, newHeight, state.topOverLap); + 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 scale = view.getScaleX(); + float newAlpha = state.alpha; + float newYTranslation = state.yTranslation; + float newZTranslation = state.zTranslation; + float newScale = state.scale; + boolean becomesInvisible = newAlpha == 0.0f; + 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) { + view.setVisibility(newVisibility); + } + + // apply yTranslation + if (yTranslation != newYTranslation) { + view.setTranslationY(newYTranslation); + } + + // apply zTranslation + if (zTranslation != newZTranslation) { + view.setTranslationZ(newZTranslation); + } + + // apply scale + if (scale != newScale) { + view.setScaleX(newScale); + view.setScaleY(newScale); } } @@ -201,12 +226,12 @@ public class StackScrollState { child.setClipBounds(mClipRect); } - public void performSpeedBumpAnimation(int i, SpeedBumpView speedBump, ViewState state, + public void performSpeedBumpAnimation(int i, SpeedBumpView speedBump, StackViewState state, long delay) { View nextChild = getNextChildNotGone(i); if (nextChild != null) { float lineEnd = state.yTranslation + state.height / 2; - ViewState nextState = getViewStateForView(nextChild); + StackViewState nextState = getViewStateForView(nextChild); boolean startIsAboveNext = nextState.yTranslation > lineEnd; speedBump.animateDivider(startIsAboveNext, delay, null /* onFinishedRunnable */); } @@ -223,53 +248,4 @@ public class StackScrollState { return null; } - public static class 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; - /** The view isn't layouted at all. */ - public static final int LOCATION_GONE = 0x40; - - float alpha; - float yTranslation; - float zTranslation; - int height; - boolean gone; - float scale; - boolean dimmed; - boolean dark; - boolean hideSensitive; - boolean belowSpeedBump; - - /** - * The amount which the view should be clipped from the top. This is calculated to - * perceive consistent shadows. - */ - int clipTopAmount; - - /** - * How much does the child overlap with the previous view on the top? Can be used for - * a clipping optimization - */ - int topOverLap; - - /** - * The index of the view, only accounting for views not equal to GONE - */ - int notGoneIndex; - - /** - * The location this view is currently rendered at. - * - * <p>See <code>LOCATION_</code> flags.</p> - */ - int location; - } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java index b027787..215ed31 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java @@ -113,13 +113,13 @@ public class StackStateAnimator { for (int i = 0; i < childCount; i++) { final ExpandableView child = (ExpandableView) mHostLayout.getChildAt(i); - StackScrollState.ViewState viewState = finalState.getViewStateForView(child); + StackViewState viewState = finalState.getViewStateForView(child); if (viewState == null || child.getVisibility() == View.GONE) { continue; } child.setClipBounds(null); - startAnimations(child, viewState, finalState, i); + startStackAnimations(child, viewState, finalState, i, -1 /* fixedDelay */); } if (!isRunning()) { // no child has preformed any animation, lets finish @@ -134,7 +134,7 @@ public class StackStateAnimator { for (int i = childCount - 1; i >= 0; i--) { final ExpandableView child = (ExpandableView) mHostLayout.getChildAt(i); - StackScrollState.ViewState viewState = finalState.getViewStateForView(child); + StackViewState viewState = finalState.getViewStateForView(child); if (viewState == null || child.getVisibility() == View.GONE) { continue; } @@ -145,18 +145,29 @@ public class StackStateAnimator { return -1; } + /** - * Start an animation to the given viewState + * Start an animation to the given {@link StackViewState}. + * + * @param child the child to start the animation on + * @param viewState the {@link StackViewState} 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 */ - private void startAnimations(final ExpandableView child, StackScrollState.ViewState viewState, - StackScrollState finalState, int i) { - int childVisibility = child.getVisibility(); - boolean wasVisible = childVisibility == View.VISIBLE; + public void startStackAnimations(final ExpandableView child, StackViewState viewState, + StackScrollState finalState, int i, long fixedDelay) { final float alpha = viewState.alpha; - if (!wasVisible && alpha != 0 && !viewState.gone) { - child.setVisibility(View.VISIBLE); + boolean wasAdded = mNewAddChildren.contains(child); + long duration = mCurrentLength; + if (wasAdded && mAnimationFilter.hasGoToFullShadeEvent) { + child.setTranslationY(child.getTranslationY() + mGoToFullShadeAppearingTranslation); + float longerDurationFactor = viewState.notGoneIndex - mCurrentLastNotAddedIndex; + longerDurationFactor = (float) Math.pow(longerDurationFactor, 0.7f); + duration = ANIMATION_DURATION_APPEAR_DISAPPEAR + 50 + + (long) (100 * longerDurationFactor); } - boolean yTranslationChanging = child.getTranslationY() != viewState.yTranslation; boolean zTranslationChanging = child.getTranslationZ() != viewState.zTranslation; boolean scaleChanging = child.getScaleX() != viewState.scale; @@ -164,94 +175,40 @@ public class StackStateAnimator { boolean heightChanging = viewState.height != child.getActualHeight(); boolean darkChanging = viewState.dark != child.isDark(); boolean topInsetChanging = viewState.clipTopAmount != child.getClipTopAmount(); - boolean wasAdded = mNewAddChildren.contains(child); boolean hasDelays = mAnimationFilter.hasDelays; boolean isDelayRelevant = yTranslationChanging || zTranslationChanging || scaleChanging || alphaChanging || heightChanging || topInsetChanging || darkChanging; - boolean noAnimation = wasAdded; long delay = 0; - long duration = mCurrentLength; - if (hasDelays && isDelayRelevant || wasAdded) { + if (fixedDelay != -1) { + delay = fixedDelay; + } else if (hasDelays && isDelayRelevant || wasAdded) { delay = mCurrentAdditionalDelay + calculateChildAnimationDelay(viewState, finalState); } - if (wasAdded && mAnimationFilter.hasGoToFullShadeEvent) { - child.setTranslationY(child.getTranslationY() + mGoToFullShadeAppearingTranslation); - yTranslationChanging = true; - float longerDurationFactor = viewState.notGoneIndex - mCurrentLastNotAddedIndex; - longerDurationFactor = (float) Math.pow(longerDurationFactor, 0.7f); - duration = ANIMATION_DURATION_APPEAR_DISAPPEAR + 50 + - (long) (100 * longerDurationFactor); - } - - // start translationY animation - if (yTranslationChanging) { - if (noAnimation && !mAnimationFilter.hasGoToFullShadeEvent) { - child.setTranslationY(viewState.yTranslation); - } else { - startYTranslationAnimation(child, viewState, duration, delay); - } - } - - // start translationZ animation - if (zTranslationChanging) { - if (noAnimation) { - child.setTranslationZ(viewState.zTranslation); - } else { - startZTranslationAnimation(child, viewState, duration, delay); - } - } - - // start scale animation - if (scaleChanging) { - if (noAnimation) { - child.setScaleX(viewState.scale); - child.setScaleY(viewState.scale); - } else { - startScaleAnimation(child, viewState, duration); - } - } - - // start alpha animation - if (alphaChanging && child.getTranslationX() == 0) { - if (noAnimation) { - child.setAlpha(viewState.alpha); - } else { - startAlphaAnimation(child, viewState, duration, delay); - } - } + startViewAnimations(child, viewState, delay, duration); // start height animation if (heightChanging && child.getActualHeight() != 0) { - if (noAnimation) { - child.setActualHeight(viewState.height, false); - } else { - startHeightAnimation(child, viewState, duration, delay); - } + startHeightAnimation(child, viewState, duration, delay); } // start top inset animation if (topInsetChanging) { - if (noAnimation) { - child.setClipTopAmount(viewState.clipTopAmount); - } else { - startInsetAnimation(child, viewState, duration, delay); - } + startInsetAnimation(child, viewState, duration, delay); } // start dimmed animation - child.setDimmed(viewState.dimmed, mAnimationFilter.animateDimmed && !wasAdded - && !noAnimation); + child.setDimmed(viewState.dimmed, mAnimationFilter.animateDimmed); // start dark animation - child.setDark(viewState.dark, mAnimationFilter.animateDark && !noAnimation, delay); + child.setDark(viewState.dark, mAnimationFilter.animateDark, delay); // apply speed bump state child.setBelowSpeedBump(viewState.belowSpeedBump); // start hiding sensitive animation - child.setHideSensitive(viewState.hideSensitive, mAnimationFilter.animateHideSensitive && - !wasAdded && !noAnimation, delay, duration); + child.setHideSensitive(viewState.hideSensitive, mAnimationFilter.animateHideSensitive, + delay, duration); if (wasAdded) { child.performAddAnimation(delay, mCurrentLength); @@ -262,7 +219,48 @@ public class StackStateAnimator { } } - private long calculateChildAnimationDelay(StackScrollState.ViewState viewState, + /** + * 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 delay a fixed delay + * @param duration the duration of the animation + */ + public void startViewAnimations(View child, ViewState viewState, long delay, long duration) { + boolean wasVisible = child.getVisibility() == View.VISIBLE; + final float alpha = viewState.alpha; + if (!wasVisible && alpha != 0 && !viewState.gone) { + child.setVisibility(View.VISIBLE); + } + boolean yTranslationChanging = child.getTranslationY() != viewState.yTranslation; + boolean zTranslationChanging = child.getTranslationZ() != viewState.zTranslation; + boolean scaleChanging = child.getScaleX() != viewState.scale; + float childAlpha = child.getVisibility() == View.INVISIBLE ? 0.0f : child.getAlpha(); + boolean alphaChanging = viewState.alpha != childAlpha; + + // start translationY animation + if (yTranslationChanging) { + startYTranslationAnimation(child, viewState, duration, delay); + } + + // start translationZ animation + if (zTranslationChanging) { + startZTranslationAnimation(child, viewState, duration, delay); + } + + // start scale animation + if (scaleChanging) { + startScaleAnimation(child, viewState, duration); + } + + // start alpha animation + if (alphaChanging && child.getTranslationX() == 0) { + startAlphaAnimation(child, viewState, duration, delay); + } + } + + private long calculateChildAnimationDelay(StackViewState viewState, StackScrollState finalState) { if (mAnimationFilter.hasDarkEvent) { return calculateDelayDark(viewState); @@ -314,7 +312,7 @@ public class StackStateAnimator { return minDelay; } - private long calculateDelayDark(StackScrollState.ViewState viewState) { + private long calculateDelayDark(StackViewState viewState) { int referenceIndex; if (mAnimationFilter.darkAnimationOriginIndex == NotificationStackScrollLayout.AnimationEvent.DARK_ANIMATION_ORIGIN_INDEX_ABOVE) { @@ -328,14 +326,14 @@ public class StackStateAnimator { return Math.abs(referenceIndex - viewState.notGoneIndex) * ANIMATION_DELAY_PER_ELEMENT_DARK; } - private long calculateDelayGoToFullShade(StackScrollState.ViewState viewState) { + private long calculateDelayGoToFullShade(StackViewState 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 startHeightAnimation(final ExpandableView child, - StackScrollState.ViewState viewState, long duration, long delay) { + StackViewState viewState, long duration, long delay) { Integer previousStartValue = getChildTag(child, TAG_START_HEIGHT); Integer previousEndValue = getChildTag(child, TAG_END_HEIGHT); int newEndValue = viewState.height; @@ -394,7 +392,7 @@ public class StackStateAnimator { } private void startInsetAnimation(final ExpandableView child, - StackScrollState.ViewState viewState, long duration, long delay) { + StackViewState 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; @@ -451,8 +449,8 @@ public class StackStateAnimator { child.setTag(TAG_END_TOP_INSET, newEndValue); } - private void startAlphaAnimation(final ExpandableView child, - final StackScrollState.ViewState viewState, long duration, long delay) { + private void startAlphaAnimation(final View child, + final ViewState viewState, long duration, long delay) { Float previousStartValue = getChildTag(child,TAG_START_ALPHA); Float previousEndValue = getChildTag(child,TAG_END_ALPHA); final float newEndValue = viewState.alpha; @@ -525,8 +523,8 @@ public class StackStateAnimator { child.setTag(TAG_END_ALPHA, newEndValue); } - private void startZTranslationAnimation(final ExpandableView child, - final StackScrollState.ViewState viewState, long duration, long delay) { + private void startZTranslationAnimation(final View child, + final ViewState viewState, long duration, long delay) { Float previousStartValue = getChildTag(child,TAG_START_TRANSLATION_Z); Float previousEndValue = getChildTag(child,TAG_END_TRANSLATION_Z); float newEndValue = viewState.zTranslation; @@ -577,8 +575,8 @@ public class StackStateAnimator { child.setTag(TAG_END_TRANSLATION_Z, newEndValue); } - private void startYTranslationAnimation(final ExpandableView child, - StackScrollState.ViewState viewState, long duration, long delay) { + private void startYTranslationAnimation(final View child, + ViewState viewState, long duration, long delay) { Float previousStartValue = getChildTag(child,TAG_START_TRANSLATION_Y); Float previousEndValue = getChildTag(child,TAG_END_TRANSLATION_Y); float newEndValue = viewState.yTranslation; @@ -630,8 +628,8 @@ public class StackStateAnimator { child.setTag(TAG_END_TRANSLATION_Y, newEndValue); } - private void startScaleAnimation(final ExpandableView child, - StackScrollState.ViewState viewState, long duration) { + private void startScaleAnimation(final View child, + ViewState viewState, long duration) { Float previousStartValue = getChildTag(child, TAG_START_SCALE); Float previousEndValue = getChildTag(child, TAG_END_SCALE); float newEndValue = viewState.scale; @@ -765,7 +763,7 @@ public class StackStateAnimator { NotificationStackScrollLayout.AnimationEvent.ANIMATION_TYPE_ADD) { // This item is added, initialize it's properties. - StackScrollState.ViewState viewState = finalState + StackViewState viewState = finalState .getViewStateForView(changingView); if (viewState == null) { // The position for this child was never generated, let's continue. @@ -776,10 +774,7 @@ public class StackStateAnimator { finalState.removeViewStateForView(changingView); continue; } - changingView.setAlpha(viewState.alpha); - changingView.setTranslationY(viewState.yTranslation); - changingView.setTranslationZ(viewState.zTranslation); - changingView.setActualHeight(viewState.height, false); + finalState.applyState(changingView, viewState); mNewAddChildren.add(changingView); } else if (event.animationType == @@ -791,7 +786,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) - StackScrollState.ViewState viewState = finalState + StackViewState viewState = finalState .getViewStateForView(event.viewAfterChangingView); int actualHeight = changingView.getActualHeight(); // upwards by default @@ -813,7 +808,7 @@ public class StackStateAnimator { mHostLayout.getOverlay().remove(changingView); } }); - } else if (event.animationType == + } else if (event.animationType == NotificationStackScrollLayout.AnimationEvent.ANIMATION_TYPE_REMOVE_SWIPED_OUT) { // A race condition can trigger the view to be added to the overlay even though // it is swiped out. So let's remove it diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackViewState.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackViewState.java new file mode 100644 index 0000000..55ef440 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackViewState.java @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2015 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.stack; + +import android.view.View; + +import com.android.systemui.statusbar.ExpandableView; + +/** +* A state of an expandable view +*/ +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; + /** The view isn't layouted at all. */ + public static final int LOCATION_GONE = 0x40; + + public int height; + public boolean dimmed; + public boolean dark; + public boolean hideSensitive; + public boolean belowSpeedBump; + + /** + * The amount which the view should be clipped from the top. This is calculated to + * perceive consistent shadows. + */ + public int clipTopAmount; + + /** + * How much does the child overlap with the previous view on the top? Can be used for + * a clipping optimization + */ + public int topOverLap; + + /** + * The index of the view, only accounting for views not equal to GONE + */ + public int notGoneIndex; + + /** + * The location this view is currently rendered at. + * + * <p>See <code>LOCATION_</code> flags.</p> + */ + public int location; + + @Override + public void copyFrom(ViewState viewState) { + super.copyFrom(viewState); + if (viewState instanceof StackViewState) { + StackViewState svs = (StackViewState) viewState; + height = svs.height; + dimmed = svs.dimmed; + dark = svs.dark; + hideSensitive = svs.hideSensitive; + belowSpeedBump = svs.belowSpeedBump; + clipTopAmount = svs.clipTopAmount; + topOverLap = svs.topOverLap; + notGoneIndex = svs.notGoneIndex; + location = svs.location; + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/ViewState.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/ViewState.java new file mode 100644 index 0000000..3e538df --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/ViewState.java @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2015 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.stack; + +import android.view.View; + +/** + * 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 + * {@link com.android.systemui.statusbar.stack.StackStateAnimator}. +*/ +public class ViewState { + + public float alpha; + public float yTranslation; + public float zTranslation; + public boolean gone; + public float scale; + + public void copyFrom(ViewState viewState) { + alpha = viewState.alpha; + yTranslation = viewState.yTranslation; + zTranslation = viewState.zTranslation; + gone = viewState.gone; + scale = viewState.scale; + } + + public void initFrom(View view) { + alpha = view.getVisibility() == View.INVISIBLE ? 0.0f : view.getAlpha(); + yTranslation = view.getTranslationY(); + zTranslation = view.getTranslationZ(); + gone = view.getVisibility() == View.GONE; + scale = view.getScaleX(); + } +} |