use of com.android.systemui.statusbar.ExpandableNotificationRow in project platform_frameworks_base by android.
the class StackStateAnimator method startStackAnimations.
/**
* 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
*/
public void startStackAnimations(final ExpandableView child, StackViewState viewState, StackScrollState finalState, int i, long fixedDelay) {
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 alphaChanging = viewState.alpha != child.getAlpha();
boolean heightChanging = viewState.height != child.getActualHeight();
boolean shadowAlphaChanging = viewState.shadowAlpha != child.getShadowAlpha();
boolean darkChanging = viewState.dark != child.isDark();
boolean topInsetChanging = viewState.clipTopAmount != child.getClipTopAmount();
boolean hasDelays = mAnimationFilter.hasDelays;
boolean isDelayRelevant = yTranslationChanging || zTranslationChanging || alphaChanging || heightChanging || topInsetChanging || darkChanging || shadowAlphaChanging;
long delay = 0;
if (fixedDelay != -1) {
delay = fixedDelay;
} else if (hasDelays && isDelayRelevant || wasAdded) {
delay = mCurrentAdditionalDelay + calculateChildAnimationDelay(viewState, finalState);
}
startViewAnimations(child, viewState, delay, duration);
// start height animation
if (heightChanging) {
startHeightAnimation(child, viewState, duration, delay);
} else {
abortAnimation(child, TAG_ANIMATOR_HEIGHT);
}
// start shadow alpha animation
if (shadowAlphaChanging) {
startShadowAlphaAnimation(child, viewState, duration, delay);
} else {
abortAnimation(child, TAG_ANIMATOR_SHADOW_ALPHA);
}
// start top inset animation
if (topInsetChanging) {
startInsetAnimation(child, viewState, duration, delay);
} else {
abortAnimation(child, TAG_ANIMATOR_TOP_INSET);
}
// start dimmed animation
child.setDimmed(viewState.dimmed, mAnimationFilter.animateDimmed);
// apply speed bump state
child.setBelowSpeedBump(viewState.belowSpeedBump);
// start hiding sensitive animation
child.setHideSensitive(viewState.hideSensitive, mAnimationFilter.animateHideSensitive, delay, duration);
// start dark animation
child.setDark(viewState.dark, mAnimationFilter.animateDark, delay);
if (wasAdded) {
child.performAddAnimation(delay, mCurrentLength);
}
if (child instanceof ExpandableNotificationRow) {
ExpandableNotificationRow row = (ExpandableNotificationRow) child;
row.startChildAnimation(finalState, this, delay, duration);
}
}
use of com.android.systemui.statusbar.ExpandableNotificationRow in project platform_frameworks_base by android.
the class StackStateAnimator method processAnimationEvents.
/**
* Process the animationEvents for a new animation
*
* @param animationEvents the animation events for the animation to perform
* @param finalState the final state to animate to
*/
private void processAnimationEvents(ArrayList<NotificationStackScrollLayout.AnimationEvent> animationEvents, StackScrollState finalState) {
for (NotificationStackScrollLayout.AnimationEvent event : animationEvents) {
final ExpandableView changingView = (ExpandableView) event.changingView;
if (event.animationType == NotificationStackScrollLayout.AnimationEvent.ANIMATION_TYPE_ADD) {
// This item is added, initialize it's properties.
StackViewState viewState = finalState.getViewStateForView(changingView);
if (viewState == null) {
// The position for this child was never generated, let's continue.
continue;
}
finalState.applyState(changingView, viewState);
mNewAddChildren.add(changingView);
} else if (event.animationType == NotificationStackScrollLayout.AnimationEvent.ANIMATION_TYPE_REMOVE) {
if (changingView.getVisibility() == View.GONE) {
removeFromOverlay(changingView);
continue;
}
// 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.getViewStateForView(event.viewAfterChangingView);
int actualHeight = changingView.getActualHeight();
// upwards by default
float translationDirection = -1.0f;
if (viewState != null) {
// there was a view after this one, Approximate the distance the next child
// travelled
translationDirection = ((viewState.yTranslation - (changingView.getTranslationY() + actualHeight / 2.0f)) * 2 / actualHeight);
translationDirection = Math.max(Math.min(translationDirection, 1.0f), -1.0f);
}
changingView.performRemoveAnimation(ANIMATION_DURATION_APPEAR_DISAPPEAR, translationDirection, new Runnable() {
@Override
public void run() {
// remove the temporary overlay
removeFromOverlay(changingView);
}
});
} 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 was fully swiped out. So let's remove it
mHostLayout.getOverlay().remove(changingView);
if (Math.abs(changingView.getTranslation()) == changingView.getWidth() && changingView.getTransientContainer() != null) {
changingView.getTransientContainer().removeTransientView(changingView);
}
} else if (event.animationType == NotificationStackScrollLayout.AnimationEvent.ANIMATION_TYPE_GROUP_EXPANSION_CHANGED) {
ExpandableNotificationRow row = (ExpandableNotificationRow) event.changingView;
row.prepareExpansionChanged(finalState);
} else if (event.animationType == NotificationStackScrollLayout.AnimationEvent.ANIMATION_TYPE_HEADS_UP_APPEAR) {
// This item is added, initialize it's properties.
StackViewState viewState = finalState.getViewStateForView(changingView);
mTmpState.copyFrom(viewState);
if (event.headsUpFromBottom) {
mTmpState.yTranslation = mHeadsUpAppearHeightBottom;
} else {
mTmpState.yTranslation = -mTmpState.height;
}
mHeadsUpAppearChildren.add(changingView);
finalState.applyState(changingView, mTmpState);
} else if (event.animationType == NotificationStackScrollLayout.AnimationEvent.ANIMATION_TYPE_HEADS_UP_DISAPPEAR || event.animationType == NotificationStackScrollLayout.AnimationEvent.ANIMATION_TYPE_HEADS_UP_DISAPPEAR_CLICK) {
mHeadsUpDisappearChildren.add(changingView);
if (changingView.getParent() == null) {
// This notification was actually removed, so we need to add it to the overlay
mHostLayout.getOverlay().add(changingView);
mTmpState.initFrom(changingView);
mTmpState.yTranslation = -changingView.getActualHeight();
// We temporarily enable Y animations, the real filter will be combined
// afterwards anyway
mAnimationFilter.animateY = true;
startViewAnimations(changingView, mTmpState, event.animationType == NotificationStackScrollLayout.AnimationEvent.ANIMATION_TYPE_HEADS_UP_DISAPPEAR_CLICK ? ANIMATION_DELAY_HEADS_UP : 0, ANIMATION_DURATION_HEADS_UP_DISAPPEAR);
mChildrenToClearFromOverlay.add(changingView);
}
}
mNewEvents.add(event);
}
}
use of com.android.systemui.statusbar.ExpandableNotificationRow in project platform_frameworks_base by android.
the class StackStateAnimator method startHeightAnimation.
private void startHeightAnimation(final ExpandableView child, StackViewState viewState, long duration, long delay) {
Integer previousStartValue = getChildTag(child, TAG_START_HEIGHT);
Integer previousEndValue = getChildTag(child, TAG_END_HEIGHT);
int newEndValue = viewState.height;
if (previousEndValue != null && previousEndValue == newEndValue) {
return;
}
ValueAnimator previousAnimator = getChildTag(child, TAG_ANIMATOR_HEIGHT);
if (!mAnimationFilter.animateHeight) {
// just a local update was performed
if (previousAnimator != null) {
// we need to increase all animation keyframes of the previous animator by the
// relative change to the end value
PropertyValuesHolder[] values = previousAnimator.getValues();
int relativeDiff = newEndValue - previousEndValue;
int newStartValue = previousStartValue + relativeDiff;
values[0].setIntValues(newStartValue, newEndValue);
child.setTag(TAG_START_HEIGHT, newStartValue);
child.setTag(TAG_END_HEIGHT, newEndValue);
previousAnimator.setCurrentPlayTime(previousAnimator.getCurrentPlayTime());
return;
} else {
// no new animation needed, let's just apply the value
child.setActualHeight(newEndValue, false);
return;
}
}
ValueAnimator animator = ValueAnimator.ofInt(child.getActualHeight(), newEndValue);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
child.setActualHeight((int) animation.getAnimatedValue(), false);
}
});
animator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
long newDuration = cancelAnimatorAndGetNewDuration(duration, previousAnimator);
animator.setDuration(newDuration);
if (delay > 0 && (previousAnimator == null || previousAnimator.getAnimatedFraction() == 0)) {
animator.setStartDelay(delay);
}
animator.addListener(getGlobalAnimationFinishedListener());
// remove the tag when the animation is finished
animator.addListener(new AnimatorListenerAdapter() {
boolean mWasCancelled;
@Override
public void onAnimationEnd(Animator animation) {
child.setTag(TAG_ANIMATOR_HEIGHT, null);
child.setTag(TAG_START_HEIGHT, null);
child.setTag(TAG_END_HEIGHT, null);
child.setActualHeightAnimating(false);
if (!mWasCancelled && child instanceof ExpandableNotificationRow) {
((ExpandableNotificationRow) child).setGroupExpansionChanging(false);
}
}
@Override
public void onAnimationStart(Animator animation) {
mWasCancelled = false;
}
@Override
public void onAnimationCancel(Animator animation) {
mWasCancelled = true;
}
});
startAnimator(animator);
child.setTag(TAG_ANIMATOR_HEIGHT, animator);
child.setTag(TAG_START_HEIGHT, child.getActualHeight());
child.setTag(TAG_END_HEIGHT, newEndValue);
child.setActualHeightAnimating(true);
}
use of com.android.systemui.statusbar.ExpandableNotificationRow in project platform_frameworks_base by android.
the class NotificationChildrenContainer method getState.
/**
* Update the state of all its children based on a linear layout algorithm.
*
* @param resultState the state to update
* @param parentState the state of the parent
*/
public void getState(StackScrollState resultState, StackViewState parentState) {
int childCount = mChildren.size();
int yPosition = mNotificationHeaderMargin;
boolean firstChild = true;
int maxAllowedVisibleChildren = getMaxAllowedVisibleChildren();
int lastVisibleIndex = maxAllowedVisibleChildren - 1;
int firstOverflowIndex = lastVisibleIndex + 1;
float expandFactor = 0;
if (mUserLocked) {
expandFactor = getGroupExpandFraction();
firstOverflowIndex = getMaxAllowedVisibleChildren(true);
}
boolean childrenExpanded = !mNotificationParent.isGroupExpansionChanging() && mChildrenExpanded;
int parentHeight = parentState.height;
for (int i = 0; i < childCount; i++) {
ExpandableNotificationRow child = mChildren.get(i);
if (!firstChild) {
if (mUserLocked) {
yPosition += NotificationUtils.interpolate(mChildPadding, mDividerHeight, expandFactor);
} else {
yPosition += mChildrenExpanded ? mDividerHeight : mChildPadding;
}
} else {
if (mUserLocked) {
yPosition += NotificationUtils.interpolate(0, mNotificatonTopPadding + mDividerHeight, expandFactor);
} else {
yPosition += mChildrenExpanded ? mNotificatonTopPadding + mDividerHeight : 0;
}
firstChild = false;
}
StackViewState childState = resultState.getViewStateForView(child);
int intrinsicHeight = child.getIntrinsicHeight();
if (childrenExpanded) {
// adjusts its height to move into it. Children after it are hidden.
if (updateChildStateForExpandedGroup(child, parentHeight, childState, yPosition)) {
// Clipping might be deactivated if the view is transforming, however, clipping
// the child into the bottom stack should take precedent over this.
childState.isBottomClipped = true;
}
} else {
childState.hidden = false;
childState.height = intrinsicHeight;
childState.isBottomClipped = false;
}
childState.yTranslation = yPosition;
// When the group is expanded, the children cast the shadows rather than the parent
// so use the parent's elevation here.
childState.zTranslation = childrenExpanded ? mNotificationParent.getTranslationZ() : 0;
childState.dimmed = parentState.dimmed;
childState.dark = parentState.dark;
childState.hideSensitive = parentState.hideSensitive;
childState.belowSpeedBump = parentState.belowSpeedBump;
childState.clipTopAmount = 0;
childState.alpha = 0;
if (i < firstOverflowIndex) {
childState.alpha = 1;
} else if (expandFactor == 1.0f && i <= lastVisibleIndex) {
childState.alpha = (mActualHeight - childState.yTranslation) / childState.height;
childState.alpha = Math.max(0.0f, Math.min(1.0f, childState.alpha));
}
childState.location = parentState.location;
yPosition += intrinsicHeight;
}
if (mOverflowNumber != null) {
ExpandableNotificationRow overflowView = mChildren.get(Math.min(getMaxAllowedVisibleChildren(true), childCount) - 1);
mGroupOverFlowState.copyFrom(resultState.getViewStateForView(overflowView));
if (!mChildrenExpanded) {
if (mUserLocked) {
HybridNotificationView singleLineView = overflowView.getSingleLineView();
View mirrorView = singleLineView.getTextView();
if (mirrorView.getVisibility() == GONE) {
mirrorView = singleLineView.getTitleView();
}
if (mirrorView.getVisibility() == GONE) {
mirrorView = singleLineView;
}
mGroupOverFlowState.yTranslation += NotificationUtils.getRelativeYOffset(mirrorView, overflowView);
mGroupOverFlowState.alpha = mirrorView.getAlpha();
}
} else {
mGroupOverFlowState.yTranslation += mNotificationHeaderMargin;
mGroupOverFlowState.alpha = 0.0f;
}
}
if (mNotificationHeader != null) {
if (mHeaderViewState == null) {
mHeaderViewState = new ViewState();
}
mHeaderViewState.initFrom(mNotificationHeader);
mHeaderViewState.zTranslation = childrenExpanded ? mNotificationParent.getTranslationZ() : 0;
}
}
use of com.android.systemui.statusbar.ExpandableNotificationRow in project platform_frameworks_base by android.
the class NotificationChildrenContainer method setActualHeight.
public void setActualHeight(int actualHeight) {
if (!mUserLocked) {
return;
}
mActualHeight = actualHeight;
float fraction = getGroupExpandFraction();
int maxAllowedVisibleChildren = getMaxAllowedVisibleChildren(true);
int childCount = mChildren.size();
for (int i = 0; i < childCount; i++) {
ExpandableNotificationRow child = mChildren.get(i);
float childHeight = child.isExpanded(true) ? child.getMaxExpandHeight() : child.getShowingLayout().getMinHeight(true);
if (i < maxAllowedVisibleChildren) {
float singleLineHeight = child.getShowingLayout().getMinHeight(false);
child.setActualHeight((int) NotificationUtils.interpolate(singleLineHeight, childHeight, fraction), false);
} else {
child.setActualHeight((int) childHeight, false);
}
}
}
Aggregations