1572bbd42a473980c2d59af80d378f6270ba6860aSelim Cinek/* 2572bbd42a473980c2d59af80d378f6270ba6860aSelim Cinek * Copyright (C) 2014 The Android Open Source Project 3572bbd42a473980c2d59af80d378f6270ba6860aSelim Cinek * 4572bbd42a473980c2d59af80d378f6270ba6860aSelim Cinek * Licensed under the Apache License, Version 2.0 (the "License"); 5572bbd42a473980c2d59af80d378f6270ba6860aSelim Cinek * you may not use this file except in compliance with the License. 6572bbd42a473980c2d59af80d378f6270ba6860aSelim Cinek * You may obtain a copy of the License at 7572bbd42a473980c2d59af80d378f6270ba6860aSelim Cinek * 8572bbd42a473980c2d59af80d378f6270ba6860aSelim Cinek * http://www.apache.org/licenses/LICENSE-2.0 9572bbd42a473980c2d59af80d378f6270ba6860aSelim Cinek * 10572bbd42a473980c2d59af80d378f6270ba6860aSelim Cinek * Unless required by applicable law or agreed to in writing, software 11572bbd42a473980c2d59af80d378f6270ba6860aSelim Cinek * distributed under the License is distributed on an "AS IS" BASIS, 12572bbd42a473980c2d59af80d378f6270ba6860aSelim Cinek * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13572bbd42a473980c2d59af80d378f6270ba6860aSelim Cinek * See the License for the specific language governing permissions and 14572bbd42a473980c2d59af80d378f6270ba6860aSelim Cinek * limitations under the License 15572bbd42a473980c2d59af80d378f6270ba6860aSelim Cinek */ 16572bbd42a473980c2d59af80d378f6270ba6860aSelim Cinek 17572bbd42a473980c2d59af80d378f6270ba6860aSelim Cinekpackage com.android.systemui.statusbar.stack; 18572bbd42a473980c2d59af80d378f6270ba6860aSelim Cinek 19eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinekimport android.animation.Animator; 20eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinekimport android.animation.AnimatorListenerAdapter; 21eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinekimport android.animation.ObjectAnimator; 22d552d9d8e964c102e6832610be46cf2c041e8829Jorim Jaggiimport android.animation.PropertyValuesHolder; 23572bbd42a473980c2d59af80d378f6270ba6860aSelim Cinekimport android.animation.ValueAnimator; 24572bbd42a473980c2d59af80d378f6270ba6860aSelim Cinekimport android.view.View; 25a5703187a9dba418f742fab0874a8f683b0bbb0eSelim Cinekimport android.view.ViewGroup; 26572bbd42a473980c2d59af80d378f6270ba6860aSelim Cinekimport android.view.animation.Interpolator; 27eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek 28c0d7058b14c24cd07912f5629c26b39b7b4673d5Winsonimport com.android.systemui.Interpolators; 29eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinekimport com.android.systemui.R; 30b5605e58cb8080c8c887b1885336b707596c8094Selim Cinekimport com.android.systemui.statusbar.ExpandableNotificationRow; 31572bbd42a473980c2d59af80d378f6270ba6860aSelim Cinekimport com.android.systemui.statusbar.ExpandableView; 320fccc729fd3b19a62efd90ae13b207faa3d1e8bbSelim Cinekimport com.android.systemui.statusbar.policy.HeadsUpManager; 33572bbd42a473980c2d59af80d378f6270ba6860aSelim Cinek 34572bbd42a473980c2d59af80d378f6270ba6860aSelim Cinekimport java.util.ArrayList; 35eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinekimport java.util.HashSet; 36eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinekimport java.util.Stack; 37572bbd42a473980c2d59af80d378f6270ba6860aSelim Cinek 38572bbd42a473980c2d59af80d378f6270ba6860aSelim Cinek/** 39572bbd42a473980c2d59af80d378f6270ba6860aSelim Cinek * An stack state animator which handles animations to new StackScrollStates 40572bbd42a473980c2d59af80d378f6270ba6860aSelim Cinek */ 41572bbd42a473980c2d59af80d378f6270ba6860aSelim Cinekpublic class StackStateAnimator { 42572bbd42a473980c2d59af80d378f6270ba6860aSelim Cinek 435aa045cc6bca84f5c11f1a99999546ba5e5949a5Jorim Jaggi public static final int ANIMATION_DURATION_STANDARD = 360; 4460d07c597c3f996deb3f2743466fe5279ca15e8dJorim Jaggi public static final int ANIMATION_DURATION_GO_TO_FULL_SHADE = 448; 458efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinek public static final int ANIMATION_DURATION_APPEAR_DISAPPEAR = 464; 465aa045cc6bca84f5c11f1a99999546ba5e5949a5Jorim Jaggi public static final int ANIMATION_DURATION_DIMMED_ACTIVATED = 220; 47a7840af09d808ecd3f7547bbdea58d4422bd4d8fSelim Cinek public static final int ANIMATION_DURATION_HEADS_UP_APPEAR = 650; 48a59ecc3401de0c4bf1e13665158f54669f22d06cSelim Cinek public static final int ANIMATION_DURATION_HEADS_UP_DISAPPEAR = 230; 498efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinek public static final int ANIMATION_DELAY_PER_ELEMENT_INTERRUPTING = 80; 508efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinek public static final int ANIMATION_DELAY_PER_ELEMENT_MANUAL = 32; 5160d07c597c3f996deb3f2743466fe5279ca15e8dJorim Jaggi public static final int ANIMATION_DELAY_PER_ELEMENT_GO_TO_FULL_SHADE = 48; 524e857f4ef0357e05806819d0488a73a12208fe8fJorim Jaggi public static final int ANIMATION_DELAY_PER_ELEMENT_DARK = 24; 53b5605e58cb8080c8c887b1885336b707596c8094Selim Cinek public static final int DELAY_EFFECT_MAX_INDEX_DIFFERENCE = 2; 545eb67c22489f5fda22770d1fc824e7a8013ec025Jorim Jaggi public static final int ANIMATION_DELAY_HEADS_UP = 120; 555aa045cc6bca84f5c11f1a99999546ba5e5949a5Jorim Jaggi 56eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek private static final int TAG_ANIMATOR_TRANSLATION_Y = R.id.translation_y_animator_tag; 57eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek private static final int TAG_ANIMATOR_TRANSLATION_Z = R.id.translation_z_animator_tag; 58eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek private static final int TAG_ANIMATOR_ALPHA = R.id.alpha_animator_tag; 59eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek private static final int TAG_ANIMATOR_HEIGHT = R.id.height_animator_tag; 60eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek private static final int TAG_ANIMATOR_TOP_INSET = R.id.top_inset_animator_tag; 61277a8aa409def1a35eb662c974b91c0f133926aaSelim Cinek private static final int TAG_ANIMATOR_SHADOW_ALPHA = R.id.shadow_alpha_animator_tag; 62eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek private static final int TAG_END_TRANSLATION_Y = R.id.translation_y_animator_end_value_tag; 63eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek private static final int TAG_END_TRANSLATION_Z = R.id.translation_z_animator_end_value_tag; 64eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek private static final int TAG_END_ALPHA = R.id.alpha_animator_end_value_tag; 65eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek private static final int TAG_END_HEIGHT = R.id.height_animator_end_value_tag; 66eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek private static final int TAG_END_TOP_INSET = R.id.top_inset_animator_end_value_tag; 67277a8aa409def1a35eb662c974b91c0f133926aaSelim Cinek private static final int TAG_END_SHADOW_ALPHA = R.id.shadow_alpha_animator_end_value_tag; 688df56452cb696ebdee82df6fb255892eabf3febcSelim Cinek private static final int TAG_START_TRANSLATION_Y = R.id.translation_y_animator_start_value_tag; 698df56452cb696ebdee82df6fb255892eabf3febcSelim Cinek private static final int TAG_START_TRANSLATION_Z = R.id.translation_z_animator_start_value_tag; 708df56452cb696ebdee82df6fb255892eabf3febcSelim Cinek private static final int TAG_START_ALPHA = R.id.alpha_animator_start_value_tag; 718df56452cb696ebdee82df6fb255892eabf3febcSelim Cinek private static final int TAG_START_HEIGHT = R.id.height_animator_start_value_tag; 728df56452cb696ebdee82df6fb255892eabf3febcSelim Cinek private static final int TAG_START_TOP_INSET = R.id.top_inset_animator_start_value_tag; 73277a8aa409def1a35eb662c974b91c0f133926aaSelim Cinek private static final int TAG_START_SHADOW_ALPHA = R.id.shadow_alpha_animator_start_value_tag; 74572bbd42a473980c2d59af80d378f6270ba6860aSelim Cinek 75a59ecc3401de0c4bf1e13665158f54669f22d06cSelim Cinek private final Interpolator mHeadsUpAppearInterpolator; 7660d07c597c3f996deb3f2743466fe5279ca15e8dJorim Jaggi private final int mGoToFullShadeAppearingTranslation; 77684a442b812a5e95d813700ffa2fd17ca72048a7Selim Cinek private final StackViewState mTmpState = new StackViewState(); 78572bbd42a473980c2d59af80d378f6270ba6860aSelim Cinek public NotificationStackScrollLayout mHostLayout; 79eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek private ArrayList<NotificationStackScrollLayout.AnimationEvent> mNewEvents = 80eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek new ArrayList<>(); 818efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinek private ArrayList<View> mNewAddChildren = new ArrayList<>(); 82a59ecc3401de0c4bf1e13665158f54669f22d06cSelim Cinek private HashSet<View> mHeadsUpAppearChildren = new HashSet<>(); 83a59ecc3401de0c4bf1e13665158f54669f22d06cSelim Cinek private HashSet<View> mHeadsUpDisappearChildren = new HashSet<>(); 84a59ecc3401de0c4bf1e13665158f54669f22d06cSelim Cinek private HashSet<Animator> mAnimatorSet = new HashSet<>(); 8560d07c597c3f996deb3f2743466fe5279ca15e8dJorim Jaggi private Stack<AnimatorListenerAdapter> mAnimationListenerPool = new Stack<>(); 86d552d9d8e964c102e6832610be46cf2c041e8829Jorim Jaggi private AnimationFilter mAnimationFilter = new AnimationFilter(); 875aa045cc6bca84f5c11f1a99999546ba5e5949a5Jorim Jaggi private long mCurrentLength; 88dbc3dce886cb7abba23a9f18e60d0f5af5c93226Jorim Jaggi private long mCurrentAdditionalDelay; 89572bbd42a473980c2d59af80d378f6270ba6860aSelim Cinek 9060d07c597c3f996deb3f2743466fe5279ca15e8dJorim Jaggi /** The current index for the last child which was not added in this event set. */ 9160d07c597c3f996deb3f2743466fe5279ca15e8dJorim Jaggi private int mCurrentLastNotAddedIndex; 928d9ff9c2c66bc1d3b92eb6992d58599ff80ed6dcSelim Cinek private ValueAnimator mTopOverScrollAnimator; 938d9ff9c2c66bc1d3b92eb6992d58599ff80ed6dcSelim Cinek private ValueAnimator mBottomOverScrollAnimator; 94a59ecc3401de0c4bf1e13665158f54669f22d06cSelim Cinek private int mHeadsUpAppearHeightBottom; 95a59ecc3401de0c4bf1e13665158f54669f22d06cSelim Cinek private boolean mShadeExpanded; 968f93763cf0f4b3c41f6b0ecac09b621eb0ca328bSelim Cinek private ArrayList<View> mChildrenToClearFromOverlay = new ArrayList<>(); 978d9ff9c2c66bc1d3b92eb6992d58599ff80ed6dcSelim Cinek 98572bbd42a473980c2d59af80d378f6270ba6860aSelim Cinek public StackStateAnimator(NotificationStackScrollLayout hostLayout) { 99572bbd42a473980c2d59af80d378f6270ba6860aSelim Cinek mHostLayout = hostLayout; 10060d07c597c3f996deb3f2743466fe5279ca15e8dJorim Jaggi mGoToFullShadeAppearingTranslation = 10160d07c597c3f996deb3f2743466fe5279ca15e8dJorim Jaggi hostLayout.getContext().getResources().getDimensionPixelSize( 10260d07c597c3f996deb3f2743466fe5279ca15e8dJorim Jaggi R.dimen.go_to_full_shade_appearing_translation); 103684a442b812a5e95d813700ffa2fd17ca72048a7Selim Cinek mHeadsUpAppearInterpolator = new HeadsUpAppearInterpolator(); 104572bbd42a473980c2d59af80d378f6270ba6860aSelim Cinek } 105572bbd42a473980c2d59af80d378f6270ba6860aSelim Cinek 106572bbd42a473980c2d59af80d378f6270ba6860aSelim Cinek public boolean isRunning() { 107eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek return !mAnimatorSet.isEmpty(); 108572bbd42a473980c2d59af80d378f6270ba6860aSelim Cinek } 109572bbd42a473980c2d59af80d378f6270ba6860aSelim Cinek 110572bbd42a473980c2d59af80d378f6270ba6860aSelim Cinek public void startAnimationForEvents( 1110dd6881ea481c855976214807c17595b34a2920aJorim Jaggi ArrayList<NotificationStackScrollLayout.AnimationEvent> mAnimationEvents, 112dbc3dce886cb7abba23a9f18e60d0f5af5c93226Jorim Jaggi StackScrollState finalState, long additionalDelay) { 113eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek 114eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek processAnimationEvents(mAnimationEvents, finalState); 115eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek 116572bbd42a473980c2d59af80d378f6270ba6860aSelim Cinek int childCount = mHostLayout.getChildCount(); 117d552d9d8e964c102e6832610be46cf2c041e8829Jorim Jaggi mAnimationFilter.applyCombination(mNewEvents); 118dbc3dce886cb7abba23a9f18e60d0f5af5c93226Jorim Jaggi mCurrentAdditionalDelay = additionalDelay; 1195aa045cc6bca84f5c11f1a99999546ba5e5949a5Jorim Jaggi mCurrentLength = NotificationStackScrollLayout.AnimationEvent.combineLength(mNewEvents); 12060d07c597c3f996deb3f2743466fe5279ca15e8dJorim Jaggi mCurrentLastNotAddedIndex = findLastNotAddedIndex(finalState); 121572bbd42a473980c2d59af80d378f6270ba6860aSelim Cinek for (int i = 0; i < childCount; i++) { 122572bbd42a473980c2d59af80d378f6270ba6860aSelim Cinek final ExpandableView child = (ExpandableView) mHostLayout.getChildAt(i); 1238efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinek 124b036ca4de8e93d83bcdc093fbf8f096dc18a810dSelim Cinek StackViewState viewState = finalState.getViewStateForView(child); 125a59ecc3401de0c4bf1e13665158f54669f22d06cSelim Cinek if (viewState == null || child.getVisibility() == View.GONE 126a59ecc3401de0c4bf1e13665158f54669f22d06cSelim Cinek || applyWithoutAnimation(child, viewState, finalState)) { 127572bbd42a473980c2d59af80d378f6270ba6860aSelim Cinek continue; 128572bbd42a473980c2d59af80d378f6270ba6860aSelim Cinek } 129572bbd42a473980c2d59af80d378f6270ba6860aSelim Cinek 130b036ca4de8e93d83bcdc093fbf8f096dc18a810dSelim Cinek startStackAnimations(child, viewState, finalState, i, -1 /* fixedDelay */); 131572bbd42a473980c2d59af80d378f6270ba6860aSelim Cinek } 132eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek if (!isRunning()) { 133eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek // no child has preformed any animation, lets finish 134eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek onAnimationFinished(); 135eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek } 136a59ecc3401de0c4bf1e13665158f54669f22d06cSelim Cinek mHeadsUpAppearChildren.clear(); 137a59ecc3401de0c4bf1e13665158f54669f22d06cSelim Cinek mHeadsUpDisappearChildren.clear(); 1388efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinek mNewEvents.clear(); 1398efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinek mNewAddChildren.clear(); 140572bbd42a473980c2d59af80d378f6270ba6860aSelim Cinek } 141572bbd42a473980c2d59af80d378f6270ba6860aSelim Cinek 142a59ecc3401de0c4bf1e13665158f54669f22d06cSelim Cinek /** 143a59ecc3401de0c4bf1e13665158f54669f22d06cSelim Cinek * Determines if a view should not perform an animation and applies it directly. 144a59ecc3401de0c4bf1e13665158f54669f22d06cSelim Cinek * 145a59ecc3401de0c4bf1e13665158f54669f22d06cSelim Cinek * @return true if no animation should be performed 146a59ecc3401de0c4bf1e13665158f54669f22d06cSelim Cinek */ 147a59ecc3401de0c4bf1e13665158f54669f22d06cSelim Cinek private boolean applyWithoutAnimation(ExpandableView child, StackViewState viewState, 148a59ecc3401de0c4bf1e13665158f54669f22d06cSelim Cinek StackScrollState finalState) { 149a59ecc3401de0c4bf1e13665158f54669f22d06cSelim Cinek if (mShadeExpanded) { 150a59ecc3401de0c4bf1e13665158f54669f22d06cSelim Cinek return false; 151a59ecc3401de0c4bf1e13665158f54669f22d06cSelim Cinek } 152a59ecc3401de0c4bf1e13665158f54669f22d06cSelim Cinek if (getChildTag(child, TAG_ANIMATOR_TRANSLATION_Y) != null) { 153a59ecc3401de0c4bf1e13665158f54669f22d06cSelim Cinek // A Y translation animation is running 154a59ecc3401de0c4bf1e13665158f54669f22d06cSelim Cinek return false; 155a59ecc3401de0c4bf1e13665158f54669f22d06cSelim Cinek } 156a59ecc3401de0c4bf1e13665158f54669f22d06cSelim Cinek if (mHeadsUpDisappearChildren.contains(child) || mHeadsUpAppearChildren.contains(child)) { 157a59ecc3401de0c4bf1e13665158f54669f22d06cSelim Cinek // This is a heads up animation 158a59ecc3401de0c4bf1e13665158f54669f22d06cSelim Cinek return false; 159a59ecc3401de0c4bf1e13665158f54669f22d06cSelim Cinek } 160131c1e2960fa5bdf54bfb6fcd5ac98c9f728f796Selim Cinek if (NotificationStackScrollLayout.isPinnedHeadsUp(child)) { 1611f3f544f21cab3728f749ab66cd6859e9dfcf389Selim Cinek // This is another headsUp which might move. Let's animate! 1621f3f544f21cab3728f749ab66cd6859e9dfcf389Selim Cinek return false; 1631f3f544f21cab3728f749ab66cd6859e9dfcf389Selim Cinek } 164a59ecc3401de0c4bf1e13665158f54669f22d06cSelim Cinek finalState.applyState(child, viewState); 165a59ecc3401de0c4bf1e13665158f54669f22d06cSelim Cinek return true; 166a59ecc3401de0c4bf1e13665158f54669f22d06cSelim Cinek } 167a59ecc3401de0c4bf1e13665158f54669f22d06cSelim Cinek 16860d07c597c3f996deb3f2743466fe5279ca15e8dJorim Jaggi private int findLastNotAddedIndex(StackScrollState finalState) { 16960d07c597c3f996deb3f2743466fe5279ca15e8dJorim Jaggi int childCount = mHostLayout.getChildCount(); 17060d07c597c3f996deb3f2743466fe5279ca15e8dJorim Jaggi for (int i = childCount - 1; i >= 0; i--) { 17160d07c597c3f996deb3f2743466fe5279ca15e8dJorim Jaggi final ExpandableView child = (ExpandableView) mHostLayout.getChildAt(i); 17260d07c597c3f996deb3f2743466fe5279ca15e8dJorim Jaggi 173b036ca4de8e93d83bcdc093fbf8f096dc18a810dSelim Cinek StackViewState viewState = finalState.getViewStateForView(child); 17460d07c597c3f996deb3f2743466fe5279ca15e8dJorim Jaggi if (viewState == null || child.getVisibility() == View.GONE) { 17560d07c597c3f996deb3f2743466fe5279ca15e8dJorim Jaggi continue; 17660d07c597c3f996deb3f2743466fe5279ca15e8dJorim Jaggi } 17760d07c597c3f996deb3f2743466fe5279ca15e8dJorim Jaggi if (!mNewAddChildren.contains(child)) { 17860d07c597c3f996deb3f2743466fe5279ca15e8dJorim Jaggi return viewState.notGoneIndex; 17960d07c597c3f996deb3f2743466fe5279ca15e8dJorim Jaggi } 18060d07c597c3f996deb3f2743466fe5279ca15e8dJorim Jaggi } 18160d07c597c3f996deb3f2743466fe5279ca15e8dJorim Jaggi return -1; 18260d07c597c3f996deb3f2743466fe5279ca15e8dJorim Jaggi } 18360d07c597c3f996deb3f2743466fe5279ca15e8dJorim Jaggi 184b036ca4de8e93d83bcdc093fbf8f096dc18a810dSelim Cinek 185eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek /** 186b036ca4de8e93d83bcdc093fbf8f096dc18a810dSelim Cinek * Start an animation to the given {@link StackViewState}. 187b036ca4de8e93d83bcdc093fbf8f096dc18a810dSelim Cinek * 188b036ca4de8e93d83bcdc093fbf8f096dc18a810dSelim Cinek * @param child the child to start the animation on 189b036ca4de8e93d83bcdc093fbf8f096dc18a810dSelim Cinek * @param viewState the {@link StackViewState} of the view to animate to 190b036ca4de8e93d83bcdc093fbf8f096dc18a810dSelim Cinek * @param finalState the final state after the animation 191b036ca4de8e93d83bcdc093fbf8f096dc18a810dSelim Cinek * @param i the index of the view; only relevant if the view is the speed bump and is 192b036ca4de8e93d83bcdc093fbf8f096dc18a810dSelim Cinek * ignored otherwise 193b036ca4de8e93d83bcdc093fbf8f096dc18a810dSelim Cinek * @param fixedDelay a fixed delay if desired or -1 if the delay should be calculated 194eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek */ 195b036ca4de8e93d83bcdc093fbf8f096dc18a810dSelim Cinek public void startStackAnimations(final ExpandableView child, StackViewState viewState, 196b036ca4de8e93d83bcdc093fbf8f096dc18a810dSelim Cinek StackScrollState finalState, int i, long fixedDelay) { 197b036ca4de8e93d83bcdc093fbf8f096dc18a810dSelim Cinek boolean wasAdded = mNewAddChildren.contains(child); 198b036ca4de8e93d83bcdc093fbf8f096dc18a810dSelim Cinek long duration = mCurrentLength; 199b036ca4de8e93d83bcdc093fbf8f096dc18a810dSelim Cinek if (wasAdded && mAnimationFilter.hasGoToFullShadeEvent) { 200b036ca4de8e93d83bcdc093fbf8f096dc18a810dSelim Cinek child.setTranslationY(child.getTranslationY() + mGoToFullShadeAppearingTranslation); 201b036ca4de8e93d83bcdc093fbf8f096dc18a810dSelim Cinek float longerDurationFactor = viewState.notGoneIndex - mCurrentLastNotAddedIndex; 202b036ca4de8e93d83bcdc093fbf8f096dc18a810dSelim Cinek longerDurationFactor = (float) Math.pow(longerDurationFactor, 0.7f); 203b036ca4de8e93d83bcdc093fbf8f096dc18a810dSelim Cinek duration = ANIMATION_DURATION_APPEAR_DISAPPEAR + 50 + 204b036ca4de8e93d83bcdc093fbf8f096dc18a810dSelim Cinek (long) (100 * longerDurationFactor); 205eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek } 2068efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinek boolean yTranslationChanging = child.getTranslationY() != viewState.yTranslation; 2078efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinek boolean zTranslationChanging = child.getTranslationZ() != viewState.zTranslation; 208277a8aa409def1a35eb662c974b91c0f133926aaSelim Cinek boolean alphaChanging = viewState.alpha != child.getAlpha(); 2098efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinek boolean heightChanging = viewState.height != child.getActualHeight(); 210277a8aa409def1a35eb662c974b91c0f133926aaSelim Cinek boolean shadowAlphaChanging = viewState.shadowAlpha != child.getShadowAlpha(); 2114e857f4ef0357e05806819d0488a73a12208fe8fJorim Jaggi boolean darkChanging = viewState.dark != child.isDark(); 212708a6c120da6750d281195ef15a240a5627efed4Selim Cinek boolean topInsetChanging = viewState.clipTopAmount != child.getClipTopAmount(); 2138efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinek boolean hasDelays = mAnimationFilter.hasDelays; 214587cbf30a7be07b502ab78b21c9f4e24370f8fceSelim Cinek boolean isDelayRelevant = yTranslationChanging || zTranslationChanging || alphaChanging 215277a8aa409def1a35eb662c974b91c0f133926aaSelim Cinek || heightChanging || topInsetChanging || darkChanging || shadowAlphaChanging; 2168efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinek long delay = 0; 217b036ca4de8e93d83bcdc093fbf8f096dc18a810dSelim Cinek if (fixedDelay != -1) { 218b036ca4de8e93d83bcdc093fbf8f096dc18a810dSelim Cinek delay = fixedDelay; 219b036ca4de8e93d83bcdc093fbf8f096dc18a810dSelim Cinek } else if (hasDelays && isDelayRelevant || wasAdded) { 220dbc3dce886cb7abba23a9f18e60d0f5af5c93226Jorim Jaggi delay = mCurrentAdditionalDelay + calculateChildAnimationDelay(viewState, finalState); 2218efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinek } 2228efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinek 223b036ca4de8e93d83bcdc093fbf8f096dc18a810dSelim Cinek startViewAnimations(child, viewState, delay, duration); 2248efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinek 225eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek // start height animation 226b0a824687f56b6950338aad169d8d837f8ed657bMady Mellor if (heightChanging) { 227b036ca4de8e93d83bcdc093fbf8f096dc18a810dSelim Cinek startHeightAnimation(child, viewState, duration, delay); 228843f54173743abe8cd4aa83b87d38e6b8b4e0ab3Selim Cinek } else { 229843f54173743abe8cd4aa83b87d38e6b8b4e0ab3Selim Cinek abortAnimation(child, TAG_ANIMATOR_HEIGHT); 23059b5a356b828fe60ea2874b0680a1bf7c84809a1Jorim Jaggi } 2318efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinek 232277a8aa409def1a35eb662c974b91c0f133926aaSelim Cinek // start shadow alpha animation 233277a8aa409def1a35eb662c974b91c0f133926aaSelim Cinek if (shadowAlphaChanging) { 234277a8aa409def1a35eb662c974b91c0f133926aaSelim Cinek startShadowAlphaAnimation(child, viewState, duration, delay); 235843f54173743abe8cd4aa83b87d38e6b8b4e0ab3Selim Cinek } else { 236843f54173743abe8cd4aa83b87d38e6b8b4e0ab3Selim Cinek abortAnimation(child, TAG_ANIMATOR_SHADOW_ALPHA); 237277a8aa409def1a35eb662c974b91c0f133926aaSelim Cinek } 238277a8aa409def1a35eb662c974b91c0f133926aaSelim Cinek 239708a6c120da6750d281195ef15a240a5627efed4Selim Cinek // start top inset animation 240708a6c120da6750d281195ef15a240a5627efed4Selim Cinek if (topInsetChanging) { 241b036ca4de8e93d83bcdc093fbf8f096dc18a810dSelim Cinek startInsetAnimation(child, viewState, duration, delay); 242843f54173743abe8cd4aa83b87d38e6b8b4e0ab3Selim Cinek } else { 243843f54173743abe8cd4aa83b87d38e6b8b4e0ab3Selim Cinek abortAnimation(child, TAG_ANIMATOR_TOP_INSET); 244708a6c120da6750d281195ef15a240a5627efed4Selim Cinek } 245708a6c120da6750d281195ef15a240a5627efed4Selim Cinek 246d552d9d8e964c102e6832610be46cf2c041e8829Jorim Jaggi // start dimmed animation 247b036ca4de8e93d83bcdc093fbf8f096dc18a810dSelim Cinek child.setDimmed(viewState.dimmed, mAnimationFilter.animateDimmed); 2488efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinek 2493d2b94bf8e32640e57573ebb17911b1db9440231Selim Cinek // apply speed bump state 2503d2b94bf8e32640e57573ebb17911b1db9440231Selim Cinek child.setBelowSpeedBump(viewState.belowSpeedBump); 2513d2b94bf8e32640e57573ebb17911b1db9440231Selim Cinek 252ae44128776410abd11bd06ae700db9cc4606a773Jorim Jaggi // start hiding sensitive animation 253b036ca4de8e93d83bcdc093fbf8f096dc18a810dSelim Cinek child.setHideSensitive(viewState.hideSensitive, mAnimationFilter.animateHideSensitive, 254b036ca4de8e93d83bcdc093fbf8f096dc18a810dSelim Cinek delay, duration); 255ae44128776410abd11bd06ae700db9cc4606a773Jorim Jaggi 256021eee53e52c880a529ece28a3a9edb3cd0776b7Jorim Jaggi // start dark animation 257021eee53e52c880a529ece28a3a9edb3cd0776b7Jorim Jaggi child.setDark(viewState.dark, mAnimationFilter.animateDark, delay); 258021eee53e52c880a529ece28a3a9edb3cd0776b7Jorim Jaggi 2598efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinek if (wasAdded) { 26060d07c597c3f996deb3f2743466fe5279ca15e8dJorim Jaggi child.performAddAnimation(delay, mCurrentLength); 2618efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinek } 2624fd5dfc1c3c356c62db329b2c1ccc00e3e75dabcSelim Cinek if (child instanceof ExpandableNotificationRow) { 263b5605e58cb8080c8c887b1885336b707596c8094Selim Cinek ExpandableNotificationRow row = (ExpandableNotificationRow) child; 2649969559da02f54fcbd7832de9810507a581d98d8Selim Cinek row.startChildAnimation(finalState, this, delay, duration); 2658b73006a36b3000a9847534dcb01a2e7066e9d93Jorim Jaggi } 2668efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinek } 2678efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinek 268b036ca4de8e93d83bcdc093fbf8f096dc18a810dSelim Cinek /** 269b036ca4de8e93d83bcdc093fbf8f096dc18a810dSelim Cinek * Start an animation to a new {@link ViewState}. 270b036ca4de8e93d83bcdc093fbf8f096dc18a810dSelim Cinek * 271b036ca4de8e93d83bcdc093fbf8f096dc18a810dSelim Cinek * @param child the child to start the animation on 272b036ca4de8e93d83bcdc093fbf8f096dc18a810dSelim Cinek * @param viewState the {@link StackViewState} of the view to animate to 273b036ca4de8e93d83bcdc093fbf8f096dc18a810dSelim Cinek * @param delay a fixed delay 274b036ca4de8e93d83bcdc093fbf8f096dc18a810dSelim Cinek * @param duration the duration of the animation 275b036ca4de8e93d83bcdc093fbf8f096dc18a810dSelim Cinek */ 276b036ca4de8e93d83bcdc093fbf8f096dc18a810dSelim Cinek public void startViewAnimations(View child, ViewState viewState, long delay, long duration) { 277b036ca4de8e93d83bcdc093fbf8f096dc18a810dSelim Cinek boolean wasVisible = child.getVisibility() == View.VISIBLE; 278b036ca4de8e93d83bcdc093fbf8f096dc18a810dSelim Cinek final float alpha = viewState.alpha; 279b0a824687f56b6950338aad169d8d837f8ed657bMady Mellor if (!wasVisible && (alpha != 0 || child.getAlpha() != 0) 280b0a824687f56b6950338aad169d8d837f8ed657bMady Mellor && !viewState.gone && !viewState.hidden) { 281b036ca4de8e93d83bcdc093fbf8f096dc18a810dSelim Cinek child.setVisibility(View.VISIBLE); 282b036ca4de8e93d83bcdc093fbf8f096dc18a810dSelim Cinek } 283b036ca4de8e93d83bcdc093fbf8f096dc18a810dSelim Cinek boolean yTranslationChanging = child.getTranslationY() != viewState.yTranslation; 284b036ca4de8e93d83bcdc093fbf8f096dc18a810dSelim Cinek boolean zTranslationChanging = child.getTranslationZ() != viewState.zTranslation; 285277a8aa409def1a35eb662c974b91c0f133926aaSelim Cinek float childAlpha = child.getAlpha(); 286b036ca4de8e93d83bcdc093fbf8f096dc18a810dSelim Cinek boolean alphaChanging = viewState.alpha != childAlpha; 2872cd45dfba6a9105a305ea20b110ba5ac078a9dc6Selim Cinek if (child instanceof ExpandableView) { 2882cd45dfba6a9105a305ea20b110ba5ac078a9dc6Selim Cinek // We don't want views to change visibility when they are animating to GONE 2892cd45dfba6a9105a305ea20b110ba5ac078a9dc6Selim Cinek alphaChanging &= !((ExpandableView) child).willBeGone(); 2902cd45dfba6a9105a305ea20b110ba5ac078a9dc6Selim Cinek } 291b036ca4de8e93d83bcdc093fbf8f096dc18a810dSelim Cinek 292b036ca4de8e93d83bcdc093fbf8f096dc18a810dSelim Cinek // start translationY animation 293b036ca4de8e93d83bcdc093fbf8f096dc18a810dSelim Cinek if (yTranslationChanging) { 294b036ca4de8e93d83bcdc093fbf8f096dc18a810dSelim Cinek startYTranslationAnimation(child, viewState, duration, delay); 295843f54173743abe8cd4aa83b87d38e6b8b4e0ab3Selim Cinek } else { 296843f54173743abe8cd4aa83b87d38e6b8b4e0ab3Selim Cinek abortAnimation(child, TAG_ANIMATOR_TRANSLATION_Y); 297b036ca4de8e93d83bcdc093fbf8f096dc18a810dSelim Cinek } 298b036ca4de8e93d83bcdc093fbf8f096dc18a810dSelim Cinek 299b036ca4de8e93d83bcdc093fbf8f096dc18a810dSelim Cinek // start translationZ animation 300b036ca4de8e93d83bcdc093fbf8f096dc18a810dSelim Cinek if (zTranslationChanging) { 301b036ca4de8e93d83bcdc093fbf8f096dc18a810dSelim Cinek startZTranslationAnimation(child, viewState, duration, delay); 302843f54173743abe8cd4aa83b87d38e6b8b4e0ab3Selim Cinek } else { 303843f54173743abe8cd4aa83b87d38e6b8b4e0ab3Selim Cinek abortAnimation(child, TAG_ANIMATOR_TRANSLATION_Z); 304b036ca4de8e93d83bcdc093fbf8f096dc18a810dSelim Cinek } 305b036ca4de8e93d83bcdc093fbf8f096dc18a810dSelim Cinek 306b036ca4de8e93d83bcdc093fbf8f096dc18a810dSelim Cinek // start alpha animation 307b036ca4de8e93d83bcdc093fbf8f096dc18a810dSelim Cinek if (alphaChanging && child.getTranslationX() == 0) { 308b036ca4de8e93d83bcdc093fbf8f096dc18a810dSelim Cinek startAlphaAnimation(child, viewState, duration, delay); 309843f54173743abe8cd4aa83b87d38e6b8b4e0ab3Selim Cinek } else { 310843f54173743abe8cd4aa83b87d38e6b8b4e0ab3Selim Cinek abortAnimation(child, TAG_ANIMATOR_ALPHA); 311843f54173743abe8cd4aa83b87d38e6b8b4e0ab3Selim Cinek } 312843f54173743abe8cd4aa83b87d38e6b8b4e0ab3Selim Cinek } 313843f54173743abe8cd4aa83b87d38e6b8b4e0ab3Selim Cinek 314843f54173743abe8cd4aa83b87d38e6b8b4e0ab3Selim Cinek private void abortAnimation(View child, int animatorTag) { 315843f54173743abe8cd4aa83b87d38e6b8b4e0ab3Selim Cinek Animator previousAnimator = getChildTag(child, animatorTag); 316843f54173743abe8cd4aa83b87d38e6b8b4e0ab3Selim Cinek if (previousAnimator != null) { 317843f54173743abe8cd4aa83b87d38e6b8b4e0ab3Selim Cinek previousAnimator.cancel(); 318b036ca4de8e93d83bcdc093fbf8f096dc18a810dSelim Cinek } 319b036ca4de8e93d83bcdc093fbf8f096dc18a810dSelim Cinek } 320b036ca4de8e93d83bcdc093fbf8f096dc18a810dSelim Cinek 321b036ca4de8e93d83bcdc093fbf8f096dc18a810dSelim Cinek private long calculateChildAnimationDelay(StackViewState viewState, 3228efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinek StackScrollState finalState) { 3234e857f4ef0357e05806819d0488a73a12208fe8fJorim Jaggi if (mAnimationFilter.hasDarkEvent) { 3244e857f4ef0357e05806819d0488a73a12208fe8fJorim Jaggi return calculateDelayDark(viewState); 3254e857f4ef0357e05806819d0488a73a12208fe8fJorim Jaggi } 32660d07c597c3f996deb3f2743466fe5279ca15e8dJorim Jaggi if (mAnimationFilter.hasGoToFullShadeEvent) { 32760d07c597c3f996deb3f2743466fe5279ca15e8dJorim Jaggi return calculateDelayGoToFullShade(viewState); 32860d07c597c3f996deb3f2743466fe5279ca15e8dJorim Jaggi } 3295eb67c22489f5fda22770d1fc824e7a8013ec025Jorim Jaggi if (mAnimationFilter.hasHeadsUpDisappearClickEvent) { 3305eb67c22489f5fda22770d1fc824e7a8013ec025Jorim Jaggi return ANIMATION_DELAY_HEADS_UP; 3315eb67c22489f5fda22770d1fc824e7a8013ec025Jorim Jaggi } 3328efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinek long minDelay = 0; 3338efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinek for (NotificationStackScrollLayout.AnimationEvent event : mNewEvents) { 3348efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinek long delayPerElement = ANIMATION_DELAY_PER_ELEMENT_INTERRUPTING; 3358efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinek switch (event.animationType) { 3368efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinek case NotificationStackScrollLayout.AnimationEvent.ANIMATION_TYPE_ADD: { 3378efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinek int ownIndex = viewState.notGoneIndex; 3388efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinek int changingIndex = finalState 3398efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinek .getViewStateForView(event.changingView).notGoneIndex; 3408efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinek int difference = Math.abs(ownIndex - changingIndex); 3418efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinek difference = Math.max(0, Math.min(DELAY_EFFECT_MAX_INDEX_DIFFERENCE, 3428efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinek difference - 1)); 3438efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinek long delay = (DELAY_EFFECT_MAX_INDEX_DIFFERENCE - difference) * delayPerElement; 3448efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinek minDelay = Math.max(delay, minDelay); 3458efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinek break; 3468efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinek } 3478efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinek case NotificationStackScrollLayout.AnimationEvent.ANIMATION_TYPE_REMOVE_SWIPED_OUT: 3488efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinek delayPerElement = ANIMATION_DELAY_PER_ELEMENT_MANUAL; 3498efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinek case NotificationStackScrollLayout.AnimationEvent.ANIMATION_TYPE_REMOVE: { 3508efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinek int ownIndex = viewState.notGoneIndex; 3518efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinek boolean noNextView = event.viewAfterChangingView == null; 3528efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinek View viewAfterChangingView = noNextView 3538efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinek ? mHostLayout.getLastChildNotGone() 3548efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinek : event.viewAfterChangingView; 3558efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinek 3568efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinek int nextIndex = finalState 3578efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinek .getViewStateForView(viewAfterChangingView).notGoneIndex; 3588efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinek if (ownIndex >= nextIndex) { 3598efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinek // we only have the view afterwards 3608efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinek ownIndex++; 3618efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinek } 3628efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinek int difference = Math.abs(ownIndex - nextIndex); 3638efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinek difference = Math.max(0, Math.min(DELAY_EFFECT_MAX_INDEX_DIFFERENCE, 3648efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinek difference - 1)); 3658efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinek long delay = difference * delayPerElement; 3668efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinek minDelay = Math.max(delay, minDelay); 3678efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinek break; 3688efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinek } 3698efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinek default: 3708efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinek break; 3718efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinek } 3728efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinek } 3738efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinek return minDelay; 374572bbd42a473980c2d59af80d378f6270ba6860aSelim Cinek } 375572bbd42a473980c2d59af80d378f6270ba6860aSelim Cinek 376b036ca4de8e93d83bcdc093fbf8f096dc18a810dSelim Cinek private long calculateDelayDark(StackViewState viewState) { 3772a5e452f4f70d2dd717946dd50486cc66ea4cc43Jorim Jaggi int referenceIndex; 3782a5e452f4f70d2dd717946dd50486cc66ea4cc43Jorim Jaggi if (mAnimationFilter.darkAnimationOriginIndex == 3792a5e452f4f70d2dd717946dd50486cc66ea4cc43Jorim Jaggi NotificationStackScrollLayout.AnimationEvent.DARK_ANIMATION_ORIGIN_INDEX_ABOVE) { 3802a5e452f4f70d2dd717946dd50486cc66ea4cc43Jorim Jaggi referenceIndex = 0; 3812a5e452f4f70d2dd717946dd50486cc66ea4cc43Jorim Jaggi } else if (mAnimationFilter.darkAnimationOriginIndex == 3822a5e452f4f70d2dd717946dd50486cc66ea4cc43Jorim Jaggi NotificationStackScrollLayout.AnimationEvent.DARK_ANIMATION_ORIGIN_INDEX_BELOW) { 3832a5e452f4f70d2dd717946dd50486cc66ea4cc43Jorim Jaggi referenceIndex = mHostLayout.getNotGoneChildCount() - 1; 3842a5e452f4f70d2dd717946dd50486cc66ea4cc43Jorim Jaggi } else { 3852a5e452f4f70d2dd717946dd50486cc66ea4cc43Jorim Jaggi referenceIndex = mAnimationFilter.darkAnimationOriginIndex; 3862a5e452f4f70d2dd717946dd50486cc66ea4cc43Jorim Jaggi } 3872a5e452f4f70d2dd717946dd50486cc66ea4cc43Jorim Jaggi return Math.abs(referenceIndex - viewState.notGoneIndex) * ANIMATION_DELAY_PER_ELEMENT_DARK; 3884e857f4ef0357e05806819d0488a73a12208fe8fJorim Jaggi } 3894e857f4ef0357e05806819d0488a73a12208fe8fJorim Jaggi 390b036ca4de8e93d83bcdc093fbf8f096dc18a810dSelim Cinek private long calculateDelayGoToFullShade(StackViewState viewState) { 39160d07c597c3f996deb3f2743466fe5279ca15e8dJorim Jaggi float index = viewState.notGoneIndex; 39260d07c597c3f996deb3f2743466fe5279ca15e8dJorim Jaggi index = (float) Math.pow(index, 0.7f); 39360d07c597c3f996deb3f2743466fe5279ca15e8dJorim Jaggi return (long) (index * ANIMATION_DELAY_PER_ELEMENT_GO_TO_FULL_SHADE); 39460d07c597c3f996deb3f2743466fe5279ca15e8dJorim Jaggi } 39560d07c597c3f996deb3f2743466fe5279ca15e8dJorim Jaggi 396277a8aa409def1a35eb662c974b91c0f133926aaSelim Cinek private void startShadowAlphaAnimation(final ExpandableView child, 397277a8aa409def1a35eb662c974b91c0f133926aaSelim Cinek StackViewState viewState, long duration, long delay) { 398277a8aa409def1a35eb662c974b91c0f133926aaSelim Cinek Float previousStartValue = getChildTag(child, TAG_START_SHADOW_ALPHA); 399277a8aa409def1a35eb662c974b91c0f133926aaSelim Cinek Float previousEndValue = getChildTag(child, TAG_END_SHADOW_ALPHA); 400277a8aa409def1a35eb662c974b91c0f133926aaSelim Cinek float newEndValue = viewState.shadowAlpha; 401277a8aa409def1a35eb662c974b91c0f133926aaSelim Cinek if (previousEndValue != null && previousEndValue == newEndValue) { 402277a8aa409def1a35eb662c974b91c0f133926aaSelim Cinek return; 403277a8aa409def1a35eb662c974b91c0f133926aaSelim Cinek } 404277a8aa409def1a35eb662c974b91c0f133926aaSelim Cinek ValueAnimator previousAnimator = getChildTag(child, TAG_ANIMATOR_SHADOW_ALPHA); 405277a8aa409def1a35eb662c974b91c0f133926aaSelim Cinek if (!mAnimationFilter.animateShadowAlpha) { 406277a8aa409def1a35eb662c974b91c0f133926aaSelim Cinek // just a local update was performed 407277a8aa409def1a35eb662c974b91c0f133926aaSelim Cinek if (previousAnimator != null) { 408277a8aa409def1a35eb662c974b91c0f133926aaSelim Cinek // we need to increase all animation keyframes of the previous animator by the 409277a8aa409def1a35eb662c974b91c0f133926aaSelim Cinek // relative change to the end value 410277a8aa409def1a35eb662c974b91c0f133926aaSelim Cinek PropertyValuesHolder[] values = previousAnimator.getValues(); 411277a8aa409def1a35eb662c974b91c0f133926aaSelim Cinek float relativeDiff = newEndValue - previousEndValue; 412277a8aa409def1a35eb662c974b91c0f133926aaSelim Cinek float newStartValue = previousStartValue + relativeDiff; 413277a8aa409def1a35eb662c974b91c0f133926aaSelim Cinek values[0].setFloatValues(newStartValue, newEndValue); 414277a8aa409def1a35eb662c974b91c0f133926aaSelim Cinek child.setTag(TAG_START_SHADOW_ALPHA, newStartValue); 415277a8aa409def1a35eb662c974b91c0f133926aaSelim Cinek child.setTag(TAG_END_SHADOW_ALPHA, newEndValue); 416277a8aa409def1a35eb662c974b91c0f133926aaSelim Cinek previousAnimator.setCurrentPlayTime(previousAnimator.getCurrentPlayTime()); 417277a8aa409def1a35eb662c974b91c0f133926aaSelim Cinek return; 418277a8aa409def1a35eb662c974b91c0f133926aaSelim Cinek } else { 419277a8aa409def1a35eb662c974b91c0f133926aaSelim Cinek // no new animation needed, let's just apply the value 420277a8aa409def1a35eb662c974b91c0f133926aaSelim Cinek child.setShadowAlpha(newEndValue); 421277a8aa409def1a35eb662c974b91c0f133926aaSelim Cinek return; 422277a8aa409def1a35eb662c974b91c0f133926aaSelim Cinek } 423277a8aa409def1a35eb662c974b91c0f133926aaSelim Cinek } 424277a8aa409def1a35eb662c974b91c0f133926aaSelim Cinek 425277a8aa409def1a35eb662c974b91c0f133926aaSelim Cinek ValueAnimator animator = ValueAnimator.ofFloat(child.getShadowAlpha(), newEndValue); 426277a8aa409def1a35eb662c974b91c0f133926aaSelim Cinek animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { 427277a8aa409def1a35eb662c974b91c0f133926aaSelim Cinek @Override 428277a8aa409def1a35eb662c974b91c0f133926aaSelim Cinek public void onAnimationUpdate(ValueAnimator animation) { 429277a8aa409def1a35eb662c974b91c0f133926aaSelim Cinek child.setShadowAlpha((float) animation.getAnimatedValue()); 430277a8aa409def1a35eb662c974b91c0f133926aaSelim Cinek } 431277a8aa409def1a35eb662c974b91c0f133926aaSelim Cinek }); 432277a8aa409def1a35eb662c974b91c0f133926aaSelim Cinek animator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN); 433277a8aa409def1a35eb662c974b91c0f133926aaSelim Cinek long newDuration = cancelAnimatorAndGetNewDuration(duration, previousAnimator); 434277a8aa409def1a35eb662c974b91c0f133926aaSelim Cinek animator.setDuration(newDuration); 435843f54173743abe8cd4aa83b87d38e6b8b4e0ab3Selim Cinek if (delay > 0 && (previousAnimator == null 436843f54173743abe8cd4aa83b87d38e6b8b4e0ab3Selim Cinek || previousAnimator.getAnimatedFraction() == 0)) { 437277a8aa409def1a35eb662c974b91c0f133926aaSelim Cinek animator.setStartDelay(delay); 438277a8aa409def1a35eb662c974b91c0f133926aaSelim Cinek } 439277a8aa409def1a35eb662c974b91c0f133926aaSelim Cinek animator.addListener(getGlobalAnimationFinishedListener()); 440277a8aa409def1a35eb662c974b91c0f133926aaSelim Cinek // remove the tag when the animation is finished 441277a8aa409def1a35eb662c974b91c0f133926aaSelim Cinek animator.addListener(new AnimatorListenerAdapter() { 442277a8aa409def1a35eb662c974b91c0f133926aaSelim Cinek @Override 443277a8aa409def1a35eb662c974b91c0f133926aaSelim Cinek public void onAnimationEnd(Animator animation) { 444277a8aa409def1a35eb662c974b91c0f133926aaSelim Cinek child.setTag(TAG_ANIMATOR_SHADOW_ALPHA, null); 445277a8aa409def1a35eb662c974b91c0f133926aaSelim Cinek child.setTag(TAG_START_SHADOW_ALPHA, null); 446277a8aa409def1a35eb662c974b91c0f133926aaSelim Cinek child.setTag(TAG_END_SHADOW_ALPHA, null); 447277a8aa409def1a35eb662c974b91c0f133926aaSelim Cinek } 448277a8aa409def1a35eb662c974b91c0f133926aaSelim Cinek }); 449277a8aa409def1a35eb662c974b91c0f133926aaSelim Cinek startAnimator(animator); 450277a8aa409def1a35eb662c974b91c0f133926aaSelim Cinek child.setTag(TAG_ANIMATOR_SHADOW_ALPHA, animator); 451277a8aa409def1a35eb662c974b91c0f133926aaSelim Cinek child.setTag(TAG_START_SHADOW_ALPHA, child.getShadowAlpha()); 452277a8aa409def1a35eb662c974b91c0f133926aaSelim Cinek child.setTag(TAG_END_SHADOW_ALPHA, newEndValue); 453277a8aa409def1a35eb662c974b91c0f133926aaSelim Cinek } 454277a8aa409def1a35eb662c974b91c0f133926aaSelim Cinek 455eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek private void startHeightAnimation(final ExpandableView child, 456b036ca4de8e93d83bcdc093fbf8f096dc18a810dSelim Cinek StackViewState viewState, long duration, long delay) { 4578df56452cb696ebdee82df6fb255892eabf3febcSelim Cinek Integer previousStartValue = getChildTag(child, TAG_START_HEIGHT); 458d552d9d8e964c102e6832610be46cf2c041e8829Jorim Jaggi Integer previousEndValue = getChildTag(child, TAG_END_HEIGHT); 4598df56452cb696ebdee82df6fb255892eabf3febcSelim Cinek int newEndValue = viewState.height; 4608df56452cb696ebdee82df6fb255892eabf3febcSelim Cinek if (previousEndValue != null && previousEndValue == newEndValue) { 461eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek return; 462eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek } 463eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek ValueAnimator previousAnimator = getChildTag(child, TAG_ANIMATOR_HEIGHT); 4648df56452cb696ebdee82df6fb255892eabf3febcSelim Cinek if (!mAnimationFilter.animateHeight) { 4658df56452cb696ebdee82df6fb255892eabf3febcSelim Cinek // just a local update was performed 4668df56452cb696ebdee82df6fb255892eabf3febcSelim Cinek if (previousAnimator != null) { 4678df56452cb696ebdee82df6fb255892eabf3febcSelim Cinek // we need to increase all animation keyframes of the previous animator by the 4688df56452cb696ebdee82df6fb255892eabf3febcSelim Cinek // relative change to the end value 4698df56452cb696ebdee82df6fb255892eabf3febcSelim Cinek PropertyValuesHolder[] values = previousAnimator.getValues(); 4708df56452cb696ebdee82df6fb255892eabf3febcSelim Cinek int relativeDiff = newEndValue - previousEndValue; 4718df56452cb696ebdee82df6fb255892eabf3febcSelim Cinek int newStartValue = previousStartValue + relativeDiff; 4728df56452cb696ebdee82df6fb255892eabf3febcSelim Cinek values[0].setIntValues(newStartValue, newEndValue); 4738df56452cb696ebdee82df6fb255892eabf3febcSelim Cinek child.setTag(TAG_START_HEIGHT, newStartValue); 4748df56452cb696ebdee82df6fb255892eabf3febcSelim Cinek child.setTag(TAG_END_HEIGHT, newEndValue); 4758df56452cb696ebdee82df6fb255892eabf3febcSelim Cinek previousAnimator.setCurrentPlayTime(previousAnimator.getCurrentPlayTime()); 4768df56452cb696ebdee82df6fb255892eabf3febcSelim Cinek return; 4778df56452cb696ebdee82df6fb255892eabf3febcSelim Cinek } else { 4788df56452cb696ebdee82df6fb255892eabf3febcSelim Cinek // no new animation needed, let's just apply the value 4798df56452cb696ebdee82df6fb255892eabf3febcSelim Cinek child.setActualHeight(newEndValue, false); 4808df56452cb696ebdee82df6fb255892eabf3febcSelim Cinek return; 481eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek } 482eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek } 483eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek 4848df56452cb696ebdee82df6fb255892eabf3febcSelim Cinek ValueAnimator animator = ValueAnimator.ofInt(child.getActualHeight(), newEndValue); 485eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { 486572bbd42a473980c2d59af80d378f6270ba6860aSelim Cinek @Override 487572bbd42a473980c2d59af80d378f6270ba6860aSelim Cinek public void onAnimationUpdate(ValueAnimator animation) { 488d552d9d8e964c102e6832610be46cf2c041e8829Jorim Jaggi child.setActualHeight((int) animation.getAnimatedValue(), 489d552d9d8e964c102e6832610be46cf2c041e8829Jorim Jaggi false /* notifyListeners */); 490572bbd42a473980c2d59af80d378f6270ba6860aSelim Cinek } 491572bbd42a473980c2d59af80d378f6270ba6860aSelim Cinek }); 492c18010f6720f606003cde3cd376ddacaca30f6e5Selim Cinek animator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN); 49360d07c597c3f996deb3f2743466fe5279ca15e8dJorim Jaggi long newDuration = cancelAnimatorAndGetNewDuration(duration, previousAnimator); 494eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek animator.setDuration(newDuration); 495843f54173743abe8cd4aa83b87d38e6b8b4e0ab3Selim Cinek if (delay > 0 && (previousAnimator == null 496843f54173743abe8cd4aa83b87d38e6b8b4e0ab3Selim Cinek || previousAnimator.getAnimatedFraction() == 0)) { 4978efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinek animator.setStartDelay(delay); 4988efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinek } 499eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek animator.addListener(getGlobalAnimationFinishedListener()); 500eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek // remove the tag when the animation is finished 501eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek animator.addListener(new AnimatorListenerAdapter() { 502b0a824687f56b6950338aad169d8d837f8ed657bMady Mellor boolean mWasCancelled; 503b0a824687f56b6950338aad169d8d837f8ed657bMady Mellor 504eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek @Override 505eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek public void onAnimationEnd(Animator animation) { 506eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek child.setTag(TAG_ANIMATOR_HEIGHT, null); 5078df56452cb696ebdee82df6fb255892eabf3febcSelim Cinek child.setTag(TAG_START_HEIGHT, null); 508eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek child.setTag(TAG_END_HEIGHT, null); 509599be34e6e3274e97512f3970a0d6edddedb8eb4Adrian Roos child.setActualHeightAnimating(false); 510b0a824687f56b6950338aad169d8d837f8ed657bMady Mellor if (!mWasCancelled && child instanceof ExpandableNotificationRow) { 511b0a824687f56b6950338aad169d8d837f8ed657bMady Mellor ((ExpandableNotificationRow) child).setGroupExpansionChanging( 512b0a824687f56b6950338aad169d8d837f8ed657bMady Mellor false /* isExpansionChanging */); 513b0a824687f56b6950338aad169d8d837f8ed657bMady Mellor } 514b0a824687f56b6950338aad169d8d837f8ed657bMady Mellor } 515b0a824687f56b6950338aad169d8d837f8ed657bMady Mellor 516b0a824687f56b6950338aad169d8d837f8ed657bMady Mellor @Override 517b0a824687f56b6950338aad169d8d837f8ed657bMady Mellor public void onAnimationStart(Animator animation) { 518b0a824687f56b6950338aad169d8d837f8ed657bMady Mellor mWasCancelled = false; 519b0a824687f56b6950338aad169d8d837f8ed657bMady Mellor } 520b0a824687f56b6950338aad169d8d837f8ed657bMady Mellor 521b0a824687f56b6950338aad169d8d837f8ed657bMady Mellor @Override 522b0a824687f56b6950338aad169d8d837f8ed657bMady Mellor public void onAnimationCancel(Animator animation) { 523b0a824687f56b6950338aad169d8d837f8ed657bMady Mellor mWasCancelled = true; 524eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek } 525eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek }); 5268efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinek startAnimator(animator); 527eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek child.setTag(TAG_ANIMATOR_HEIGHT, animator); 5288df56452cb696ebdee82df6fb255892eabf3febcSelim Cinek child.setTag(TAG_START_HEIGHT, child.getActualHeight()); 5298df56452cb696ebdee82df6fb255892eabf3febcSelim Cinek child.setTag(TAG_END_HEIGHT, newEndValue); 530599be34e6e3274e97512f3970a0d6edddedb8eb4Adrian Roos child.setActualHeightAnimating(true); 531eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek } 532eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek 533708a6c120da6750d281195ef15a240a5627efed4Selim Cinek private void startInsetAnimation(final ExpandableView child, 534b036ca4de8e93d83bcdc093fbf8f096dc18a810dSelim Cinek StackViewState viewState, long duration, long delay) { 535708a6c120da6750d281195ef15a240a5627efed4Selim Cinek Integer previousStartValue = getChildTag(child, TAG_START_TOP_INSET); 536708a6c120da6750d281195ef15a240a5627efed4Selim Cinek Integer previousEndValue = getChildTag(child, TAG_END_TOP_INSET); 537708a6c120da6750d281195ef15a240a5627efed4Selim Cinek int newEndValue = viewState.clipTopAmount; 538708a6c120da6750d281195ef15a240a5627efed4Selim Cinek if (previousEndValue != null && previousEndValue == newEndValue) { 539708a6c120da6750d281195ef15a240a5627efed4Selim Cinek return; 540708a6c120da6750d281195ef15a240a5627efed4Selim Cinek } 541708a6c120da6750d281195ef15a240a5627efed4Selim Cinek ValueAnimator previousAnimator = getChildTag(child, TAG_ANIMATOR_TOP_INSET); 542708a6c120da6750d281195ef15a240a5627efed4Selim Cinek if (!mAnimationFilter.animateTopInset) { 543708a6c120da6750d281195ef15a240a5627efed4Selim Cinek // just a local update was performed 544708a6c120da6750d281195ef15a240a5627efed4Selim Cinek if (previousAnimator != null) { 545708a6c120da6750d281195ef15a240a5627efed4Selim Cinek // we need to increase all animation keyframes of the previous animator by the 546708a6c120da6750d281195ef15a240a5627efed4Selim Cinek // relative change to the end value 547708a6c120da6750d281195ef15a240a5627efed4Selim Cinek PropertyValuesHolder[] values = previousAnimator.getValues(); 548708a6c120da6750d281195ef15a240a5627efed4Selim Cinek int relativeDiff = newEndValue - previousEndValue; 549708a6c120da6750d281195ef15a240a5627efed4Selim Cinek int newStartValue = previousStartValue + relativeDiff; 550708a6c120da6750d281195ef15a240a5627efed4Selim Cinek values[0].setIntValues(newStartValue, newEndValue); 551708a6c120da6750d281195ef15a240a5627efed4Selim Cinek child.setTag(TAG_START_TOP_INSET, newStartValue); 552708a6c120da6750d281195ef15a240a5627efed4Selim Cinek child.setTag(TAG_END_TOP_INSET, newEndValue); 553708a6c120da6750d281195ef15a240a5627efed4Selim Cinek previousAnimator.setCurrentPlayTime(previousAnimator.getCurrentPlayTime()); 554708a6c120da6750d281195ef15a240a5627efed4Selim Cinek return; 555708a6c120da6750d281195ef15a240a5627efed4Selim Cinek } else { 556708a6c120da6750d281195ef15a240a5627efed4Selim Cinek // no new animation needed, let's just apply the value 557708a6c120da6750d281195ef15a240a5627efed4Selim Cinek child.setClipTopAmount(newEndValue); 558708a6c120da6750d281195ef15a240a5627efed4Selim Cinek return; 559708a6c120da6750d281195ef15a240a5627efed4Selim Cinek } 560708a6c120da6750d281195ef15a240a5627efed4Selim Cinek } 561708a6c120da6750d281195ef15a240a5627efed4Selim Cinek 562708a6c120da6750d281195ef15a240a5627efed4Selim Cinek ValueAnimator animator = ValueAnimator.ofInt(child.getClipTopAmount(), newEndValue); 563708a6c120da6750d281195ef15a240a5627efed4Selim Cinek animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { 564708a6c120da6750d281195ef15a240a5627efed4Selim Cinek @Override 565708a6c120da6750d281195ef15a240a5627efed4Selim Cinek public void onAnimationUpdate(ValueAnimator animation) { 566708a6c120da6750d281195ef15a240a5627efed4Selim Cinek child.setClipTopAmount((int) animation.getAnimatedValue()); 567708a6c120da6750d281195ef15a240a5627efed4Selim Cinek } 568708a6c120da6750d281195ef15a240a5627efed4Selim Cinek }); 569c18010f6720f606003cde3cd376ddacaca30f6e5Selim Cinek animator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN); 57060d07c597c3f996deb3f2743466fe5279ca15e8dJorim Jaggi long newDuration = cancelAnimatorAndGetNewDuration(duration, previousAnimator); 571708a6c120da6750d281195ef15a240a5627efed4Selim Cinek animator.setDuration(newDuration); 572843f54173743abe8cd4aa83b87d38e6b8b4e0ab3Selim Cinek if (delay > 0 && (previousAnimator == null 573843f54173743abe8cd4aa83b87d38e6b8b4e0ab3Selim Cinek || previousAnimator.getAnimatedFraction() == 0)) { 574708a6c120da6750d281195ef15a240a5627efed4Selim Cinek animator.setStartDelay(delay); 575708a6c120da6750d281195ef15a240a5627efed4Selim Cinek } 576708a6c120da6750d281195ef15a240a5627efed4Selim Cinek animator.addListener(getGlobalAnimationFinishedListener()); 577708a6c120da6750d281195ef15a240a5627efed4Selim Cinek // remove the tag when the animation is finished 578708a6c120da6750d281195ef15a240a5627efed4Selim Cinek animator.addListener(new AnimatorListenerAdapter() { 579708a6c120da6750d281195ef15a240a5627efed4Selim Cinek @Override 580708a6c120da6750d281195ef15a240a5627efed4Selim Cinek public void onAnimationEnd(Animator animation) { 581708a6c120da6750d281195ef15a240a5627efed4Selim Cinek child.setTag(TAG_ANIMATOR_TOP_INSET, null); 582708a6c120da6750d281195ef15a240a5627efed4Selim Cinek child.setTag(TAG_START_TOP_INSET, null); 583708a6c120da6750d281195ef15a240a5627efed4Selim Cinek child.setTag(TAG_END_TOP_INSET, null); 584708a6c120da6750d281195ef15a240a5627efed4Selim Cinek } 585708a6c120da6750d281195ef15a240a5627efed4Selim Cinek }); 586708a6c120da6750d281195ef15a240a5627efed4Selim Cinek startAnimator(animator); 587708a6c120da6750d281195ef15a240a5627efed4Selim Cinek child.setTag(TAG_ANIMATOR_TOP_INSET, animator); 588708a6c120da6750d281195ef15a240a5627efed4Selim Cinek child.setTag(TAG_START_TOP_INSET, child.getClipTopAmount()); 589708a6c120da6750d281195ef15a240a5627efed4Selim Cinek child.setTag(TAG_END_TOP_INSET, newEndValue); 590708a6c120da6750d281195ef15a240a5627efed4Selim Cinek } 591708a6c120da6750d281195ef15a240a5627efed4Selim Cinek 592b036ca4de8e93d83bcdc093fbf8f096dc18a810dSelim Cinek private void startAlphaAnimation(final View child, 593b036ca4de8e93d83bcdc093fbf8f096dc18a810dSelim Cinek final ViewState viewState, long duration, long delay) { 5948df56452cb696ebdee82df6fb255892eabf3febcSelim Cinek Float previousStartValue = getChildTag(child,TAG_START_ALPHA); 595eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek Float previousEndValue = getChildTag(child,TAG_END_ALPHA); 5968df56452cb696ebdee82df6fb255892eabf3febcSelim Cinek final float newEndValue = viewState.alpha; 5978df56452cb696ebdee82df6fb255892eabf3febcSelim Cinek if (previousEndValue != null && previousEndValue == newEndValue) { 598eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek return; 599eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek } 600eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek ObjectAnimator previousAnimator = getChildTag(child, TAG_ANIMATOR_ALPHA); 6018df56452cb696ebdee82df6fb255892eabf3febcSelim Cinek if (!mAnimationFilter.animateAlpha) { 6028df56452cb696ebdee82df6fb255892eabf3febcSelim Cinek // just a local update was performed 6038df56452cb696ebdee82df6fb255892eabf3febcSelim Cinek if (previousAnimator != null) { 6048df56452cb696ebdee82df6fb255892eabf3febcSelim Cinek // we need to increase all animation keyframes of the previous animator by the 6058df56452cb696ebdee82df6fb255892eabf3febcSelim Cinek // relative change to the end value 6068df56452cb696ebdee82df6fb255892eabf3febcSelim Cinek PropertyValuesHolder[] values = previousAnimator.getValues(); 6078df56452cb696ebdee82df6fb255892eabf3febcSelim Cinek float relativeDiff = newEndValue - previousEndValue; 6088df56452cb696ebdee82df6fb255892eabf3febcSelim Cinek float newStartValue = previousStartValue + relativeDiff; 6098df56452cb696ebdee82df6fb255892eabf3febcSelim Cinek values[0].setFloatValues(newStartValue, newEndValue); 6108df56452cb696ebdee82df6fb255892eabf3febcSelim Cinek child.setTag(TAG_START_ALPHA, newStartValue); 6118df56452cb696ebdee82df6fb255892eabf3febcSelim Cinek child.setTag(TAG_END_ALPHA, newEndValue); 6128df56452cb696ebdee82df6fb255892eabf3febcSelim Cinek previousAnimator.setCurrentPlayTime(previousAnimator.getCurrentPlayTime()); 6138df56452cb696ebdee82df6fb255892eabf3febcSelim Cinek return; 6148df56452cb696ebdee82df6fb255892eabf3febcSelim Cinek } else { 6158df56452cb696ebdee82df6fb255892eabf3febcSelim Cinek // no new animation needed, let's just apply the value 6168df56452cb696ebdee82df6fb255892eabf3febcSelim Cinek child.setAlpha(newEndValue); 6178df56452cb696ebdee82df6fb255892eabf3febcSelim Cinek if (newEndValue == 0) { 6188df56452cb696ebdee82df6fb255892eabf3febcSelim Cinek child.setVisibility(View.INVISIBLE); 6198df56452cb696ebdee82df6fb255892eabf3febcSelim Cinek } 620eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek } 621eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek } 622eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek 623eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek ObjectAnimator animator = ObjectAnimator.ofFloat(child, View.ALPHA, 6248df56452cb696ebdee82df6fb255892eabf3febcSelim Cinek child.getAlpha(), newEndValue); 625c18010f6720f606003cde3cd376ddacaca30f6e5Selim Cinek animator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN); 626eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek // Handle layer type 627eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek child.setLayerType(View.LAYER_TYPE_HARDWARE, null); 628eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek animator.addListener(new AnimatorListenerAdapter() { 629eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek public boolean mWasCancelled; 630eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek 631eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek @Override 632eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek public void onAnimationEnd(Animator animation) { 6331efb240c1a0aeca9492cf8891794712adfdb1fa7Selim Cinek child.setLayerType(View.LAYER_TYPE_NONE, null); 6348df56452cb696ebdee82df6fb255892eabf3febcSelim Cinek if (newEndValue == 0 && !mWasCancelled) { 635eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek child.setVisibility(View.INVISIBLE); 636eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek } 637c5baa3eb0893cb764e7810f8c68e89b04653df86Selim Cinek // remove the tag when the animation is finished 638eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek child.setTag(TAG_ANIMATOR_ALPHA, null); 6398df56452cb696ebdee82df6fb255892eabf3febcSelim Cinek child.setTag(TAG_START_ALPHA, null); 640eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek child.setTag(TAG_END_ALPHA, null); 641eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek } 642eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek 643eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek @Override 644eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek public void onAnimationCancel(Animator animation) { 645eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek mWasCancelled = true; 646eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek } 647eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek 648eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek @Override 649eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek public void onAnimationStart(Animator animation) { 650eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek mWasCancelled = false; 651eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek } 652eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek }); 65360d07c597c3f996deb3f2743466fe5279ca15e8dJorim Jaggi long newDuration = cancelAnimatorAndGetNewDuration(duration, previousAnimator); 6543af00cf10660c7fdc0582dc12361c13673d0c9bbSelim Cinek animator.setDuration(newDuration); 655843f54173743abe8cd4aa83b87d38e6b8b4e0ab3Selim Cinek if (delay > 0 && (previousAnimator == null 656843f54173743abe8cd4aa83b87d38e6b8b4e0ab3Selim Cinek || previousAnimator.getAnimatedFraction() == 0)) { 6578efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinek animator.setStartDelay(delay); 6588efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinek } 659eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek animator.addListener(getGlobalAnimationFinishedListener()); 660eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek 6618efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinek startAnimator(animator); 662eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek child.setTag(TAG_ANIMATOR_ALPHA, animator); 6638df56452cb696ebdee82df6fb255892eabf3febcSelim Cinek child.setTag(TAG_START_ALPHA, child.getAlpha()); 6648df56452cb696ebdee82df6fb255892eabf3febcSelim Cinek child.setTag(TAG_END_ALPHA, newEndValue); 665572bbd42a473980c2d59af80d378f6270ba6860aSelim Cinek } 666572bbd42a473980c2d59af80d378f6270ba6860aSelim Cinek 667b036ca4de8e93d83bcdc093fbf8f096dc18a810dSelim Cinek private void startZTranslationAnimation(final View child, 668b036ca4de8e93d83bcdc093fbf8f096dc18a810dSelim Cinek final ViewState viewState, long duration, long delay) { 6698df56452cb696ebdee82df6fb255892eabf3febcSelim Cinek Float previousStartValue = getChildTag(child,TAG_START_TRANSLATION_Z); 670eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek Float previousEndValue = getChildTag(child,TAG_END_TRANSLATION_Z); 6718df56452cb696ebdee82df6fb255892eabf3febcSelim Cinek float newEndValue = viewState.zTranslation; 6728df56452cb696ebdee82df6fb255892eabf3febcSelim Cinek if (previousEndValue != null && previousEndValue == newEndValue) { 673eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek return; 674eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek } 675eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek ObjectAnimator previousAnimator = getChildTag(child, TAG_ANIMATOR_TRANSLATION_Z); 6768df56452cb696ebdee82df6fb255892eabf3febcSelim Cinek if (!mAnimationFilter.animateZ) { 6778df56452cb696ebdee82df6fb255892eabf3febcSelim Cinek // just a local update was performed 6788df56452cb696ebdee82df6fb255892eabf3febcSelim Cinek if (previousAnimator != null) { 6798df56452cb696ebdee82df6fb255892eabf3febcSelim Cinek // we need to increase all animation keyframes of the previous animator by the 6808df56452cb696ebdee82df6fb255892eabf3febcSelim Cinek // relative change to the end value 6818df56452cb696ebdee82df6fb255892eabf3febcSelim Cinek PropertyValuesHolder[] values = previousAnimator.getValues(); 6828df56452cb696ebdee82df6fb255892eabf3febcSelim Cinek float relativeDiff = newEndValue - previousEndValue; 6838df56452cb696ebdee82df6fb255892eabf3febcSelim Cinek float newStartValue = previousStartValue + relativeDiff; 6848df56452cb696ebdee82df6fb255892eabf3febcSelim Cinek values[0].setFloatValues(newStartValue, newEndValue); 6858df56452cb696ebdee82df6fb255892eabf3febcSelim Cinek child.setTag(TAG_START_TRANSLATION_Z, newStartValue); 6868df56452cb696ebdee82df6fb255892eabf3febcSelim Cinek child.setTag(TAG_END_TRANSLATION_Z, newEndValue); 6878df56452cb696ebdee82df6fb255892eabf3febcSelim Cinek previousAnimator.setCurrentPlayTime(previousAnimator.getCurrentPlayTime()); 6888df56452cb696ebdee82df6fb255892eabf3febcSelim Cinek return; 6898df56452cb696ebdee82df6fb255892eabf3febcSelim Cinek } else { 6908df56452cb696ebdee82df6fb255892eabf3febcSelim Cinek // no new animation needed, let's just apply the value 6918df56452cb696ebdee82df6fb255892eabf3febcSelim Cinek child.setTranslationZ(newEndValue); 692eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek } 693eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek } 694eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek 695eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek ObjectAnimator animator = ObjectAnimator.ofFloat(child, View.TRANSLATION_Z, 6968df56452cb696ebdee82df6fb255892eabf3febcSelim Cinek child.getTranslationZ(), newEndValue); 697c18010f6720f606003cde3cd376ddacaca30f6e5Selim Cinek animator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN); 69860d07c597c3f996deb3f2743466fe5279ca15e8dJorim Jaggi long newDuration = cancelAnimatorAndGetNewDuration(duration, previousAnimator); 6993af00cf10660c7fdc0582dc12361c13673d0c9bbSelim Cinek animator.setDuration(newDuration); 700843f54173743abe8cd4aa83b87d38e6b8b4e0ab3Selim Cinek if (delay > 0 && (previousAnimator == null 701843f54173743abe8cd4aa83b87d38e6b8b4e0ab3Selim Cinek || previousAnimator.getAnimatedFraction() == 0)) { 7028efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinek animator.setStartDelay(delay); 7038efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinek } 704eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek animator.addListener(getGlobalAnimationFinishedListener()); 705eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek // remove the tag when the animation is finished 706eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek animator.addListener(new AnimatorListenerAdapter() { 707eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek @Override 708eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek public void onAnimationEnd(Animator animation) { 709eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek child.setTag(TAG_ANIMATOR_TRANSLATION_Z, null); 7108df56452cb696ebdee82df6fb255892eabf3febcSelim Cinek child.setTag(TAG_START_TRANSLATION_Z, null); 711eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek child.setTag(TAG_END_TRANSLATION_Z, null); 712eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek } 713eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek }); 7148efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinek startAnimator(animator); 715eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek child.setTag(TAG_ANIMATOR_TRANSLATION_Z, animator); 7168df56452cb696ebdee82df6fb255892eabf3febcSelim Cinek child.setTag(TAG_START_TRANSLATION_Z, child.getTranslationZ()); 7178df56452cb696ebdee82df6fb255892eabf3febcSelim Cinek child.setTag(TAG_END_TRANSLATION_Z, newEndValue); 718eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek } 719eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek 720b036ca4de8e93d83bcdc093fbf8f096dc18a810dSelim Cinek private void startYTranslationAnimation(final View child, 721b036ca4de8e93d83bcdc093fbf8f096dc18a810dSelim Cinek ViewState viewState, long duration, long delay) { 7228df56452cb696ebdee82df6fb255892eabf3febcSelim Cinek Float previousStartValue = getChildTag(child,TAG_START_TRANSLATION_Y); 723eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek Float previousEndValue = getChildTag(child,TAG_END_TRANSLATION_Y); 7248df56452cb696ebdee82df6fb255892eabf3febcSelim Cinek float newEndValue = viewState.yTranslation; 7258df56452cb696ebdee82df6fb255892eabf3febcSelim Cinek if (previousEndValue != null && previousEndValue == newEndValue) { 726eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek return; 727eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek } 728eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek ObjectAnimator previousAnimator = getChildTag(child, TAG_ANIMATOR_TRANSLATION_Y); 7298df56452cb696ebdee82df6fb255892eabf3febcSelim Cinek if (!mAnimationFilter.animateY) { 7308df56452cb696ebdee82df6fb255892eabf3febcSelim Cinek // just a local update was performed 7318df56452cb696ebdee82df6fb255892eabf3febcSelim Cinek if (previousAnimator != null) { 7328df56452cb696ebdee82df6fb255892eabf3febcSelim Cinek // we need to increase all animation keyframes of the previous animator by the 7338df56452cb696ebdee82df6fb255892eabf3febcSelim Cinek // relative change to the end value 7348df56452cb696ebdee82df6fb255892eabf3febcSelim Cinek PropertyValuesHolder[] values = previousAnimator.getValues(); 7358df56452cb696ebdee82df6fb255892eabf3febcSelim Cinek float relativeDiff = newEndValue - previousEndValue; 7368df56452cb696ebdee82df6fb255892eabf3febcSelim Cinek float newStartValue = previousStartValue + relativeDiff; 7378df56452cb696ebdee82df6fb255892eabf3febcSelim Cinek values[0].setFloatValues(newStartValue, newEndValue); 7388df56452cb696ebdee82df6fb255892eabf3febcSelim Cinek child.setTag(TAG_START_TRANSLATION_Y, newStartValue); 7398df56452cb696ebdee82df6fb255892eabf3febcSelim Cinek child.setTag(TAG_END_TRANSLATION_Y, newEndValue); 7408df56452cb696ebdee82df6fb255892eabf3febcSelim Cinek previousAnimator.setCurrentPlayTime(previousAnimator.getCurrentPlayTime()); 7418df56452cb696ebdee82df6fb255892eabf3febcSelim Cinek return; 7428df56452cb696ebdee82df6fb255892eabf3febcSelim Cinek } else { 7438df56452cb696ebdee82df6fb255892eabf3febcSelim Cinek // no new animation needed, let's just apply the value 7448df56452cb696ebdee82df6fb255892eabf3febcSelim Cinek child.setTranslationY(newEndValue); 7458df56452cb696ebdee82df6fb255892eabf3febcSelim Cinek return; 746eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek } 747eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek } 748eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek 749eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek ObjectAnimator animator = ObjectAnimator.ofFloat(child, View.TRANSLATION_Y, 7508df56452cb696ebdee82df6fb255892eabf3febcSelim Cinek child.getTranslationY(), newEndValue); 751a59ecc3401de0c4bf1e13665158f54669f22d06cSelim Cinek Interpolator interpolator = mHeadsUpAppearChildren.contains(child) ? 752c18010f6720f606003cde3cd376ddacaca30f6e5Selim Cinek mHeadsUpAppearInterpolator :Interpolators.FAST_OUT_SLOW_IN; 753a59ecc3401de0c4bf1e13665158f54669f22d06cSelim Cinek animator.setInterpolator(interpolator); 75460d07c597c3f996deb3f2743466fe5279ca15e8dJorim Jaggi long newDuration = cancelAnimatorAndGetNewDuration(duration, previousAnimator); 7553af00cf10660c7fdc0582dc12361c13673d0c9bbSelim Cinek animator.setDuration(newDuration); 756843f54173743abe8cd4aa83b87d38e6b8b4e0ab3Selim Cinek if (delay > 0 && (previousAnimator == null 757843f54173743abe8cd4aa83b87d38e6b8b4e0ab3Selim Cinek || previousAnimator.getAnimatedFraction() == 0)) { 7588efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinek animator.setStartDelay(delay); 7598efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinek } 760eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek animator.addListener(getGlobalAnimationFinishedListener()); 76173cf02a0783e3857cae21fece9c292abcc9e1409Selim Cinek final boolean isHeadsUpDisappear = mHeadsUpDisappearChildren.contains(child); 762eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek // remove the tag when the animation is finished 763eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek animator.addListener(new AnimatorListenerAdapter() { 764eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek @Override 765eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek public void onAnimationEnd(Animator animation) { 7660fccc729fd3b19a62efd90ae13b207faa3d1e8bbSelim Cinek HeadsUpManager.setIsClickedNotification(child, false); 767eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek child.setTag(TAG_ANIMATOR_TRANSLATION_Y, null); 7688df56452cb696ebdee82df6fb255892eabf3febcSelim Cinek child.setTag(TAG_START_TRANSLATION_Y, null); 769eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek child.setTag(TAG_END_TRANSLATION_Y, null); 77073cf02a0783e3857cae21fece9c292abcc9e1409Selim Cinek if (isHeadsUpDisappear) { 77173cf02a0783e3857cae21fece9c292abcc9e1409Selim Cinek ((ExpandableNotificationRow) child).setHeadsupDisappearRunning(false); 77273cf02a0783e3857cae21fece9c292abcc9e1409Selim Cinek } 773eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek } 774eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek }); 7758efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinek startAnimator(animator); 776eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek child.setTag(TAG_ANIMATOR_TRANSLATION_Y, animator); 7778df56452cb696ebdee82df6fb255892eabf3febcSelim Cinek child.setTag(TAG_START_TRANSLATION_Y, child.getTranslationY()); 7788df56452cb696ebdee82df6fb255892eabf3febcSelim Cinek child.setTag(TAG_END_TRANSLATION_Y, newEndValue); 779eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek } 780eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek 7818efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinek private void startAnimator(ValueAnimator animator) { 7828efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinek mAnimatorSet.add(animator); 7833af00cf10660c7fdc0582dc12361c13673d0c9bbSelim Cinek animator.start(); 7843af00cf10660c7fdc0582dc12361c13673d0c9bbSelim Cinek } 7853af00cf10660c7fdc0582dc12361c13673d0c9bbSelim Cinek 7863af00cf10660c7fdc0582dc12361c13673d0c9bbSelim Cinek /** 7873af00cf10660c7fdc0582dc12361c13673d0c9bbSelim Cinek * @return an adapter which ensures that onAnimationFinished is called once no animation is 7883af00cf10660c7fdc0582dc12361c13673d0c9bbSelim Cinek * running anymore 7893af00cf10660c7fdc0582dc12361c13673d0c9bbSelim Cinek */ 7903af00cf10660c7fdc0582dc12361c13673d0c9bbSelim Cinek private AnimatorListenerAdapter getGlobalAnimationFinishedListener() { 7913af00cf10660c7fdc0582dc12361c13673d0c9bbSelim Cinek if (!mAnimationListenerPool.empty()) { 7923af00cf10660c7fdc0582dc12361c13673d0c9bbSelim Cinek return mAnimationListenerPool.pop(); 7933af00cf10660c7fdc0582dc12361c13673d0c9bbSelim Cinek } 7943af00cf10660c7fdc0582dc12361c13673d0c9bbSelim Cinek 7953af00cf10660c7fdc0582dc12361c13673d0c9bbSelim Cinek // We need to create a new one, no reusable ones found 7963af00cf10660c7fdc0582dc12361c13673d0c9bbSelim Cinek return new AnimatorListenerAdapter() { 7973af00cf10660c7fdc0582dc12361c13673d0c9bbSelim Cinek private boolean mWasCancelled; 7983af00cf10660c7fdc0582dc12361c13673d0c9bbSelim Cinek 7993af00cf10660c7fdc0582dc12361c13673d0c9bbSelim Cinek @Override 8003af00cf10660c7fdc0582dc12361c13673d0c9bbSelim Cinek public void onAnimationEnd(Animator animation) { 8013af00cf10660c7fdc0582dc12361c13673d0c9bbSelim Cinek mAnimatorSet.remove(animation); 8023af00cf10660c7fdc0582dc12361c13673d0c9bbSelim Cinek if (mAnimatorSet.isEmpty() && !mWasCancelled) { 8033af00cf10660c7fdc0582dc12361c13673d0c9bbSelim Cinek onAnimationFinished(); 8043af00cf10660c7fdc0582dc12361c13673d0c9bbSelim Cinek } 8053af00cf10660c7fdc0582dc12361c13673d0c9bbSelim Cinek mAnimationListenerPool.push(this); 8063af00cf10660c7fdc0582dc12361c13673d0c9bbSelim Cinek } 8073af00cf10660c7fdc0582dc12361c13673d0c9bbSelim Cinek 8083af00cf10660c7fdc0582dc12361c13673d0c9bbSelim Cinek @Override 8093af00cf10660c7fdc0582dc12361c13673d0c9bbSelim Cinek public void onAnimationCancel(Animator animation) { 8103af00cf10660c7fdc0582dc12361c13673d0c9bbSelim Cinek mWasCancelled = true; 8113af00cf10660c7fdc0582dc12361c13673d0c9bbSelim Cinek } 8123af00cf10660c7fdc0582dc12361c13673d0c9bbSelim Cinek 8133af00cf10660c7fdc0582dc12361c13673d0c9bbSelim Cinek @Override 8143af00cf10660c7fdc0582dc12361c13673d0c9bbSelim Cinek public void onAnimationStart(Animator animation) { 8153af00cf10660c7fdc0582dc12361c13673d0c9bbSelim Cinek mWasCancelled = false; 8163af00cf10660c7fdc0582dc12361c13673d0c9bbSelim Cinek } 8173af00cf10660c7fdc0582dc12361c13673d0c9bbSelim Cinek }; 8183af00cf10660c7fdc0582dc12361c13673d0c9bbSelim Cinek } 8193af00cf10660c7fdc0582dc12361c13673d0c9bbSelim Cinek 820aac932591d7aa05bae61d2b47ed7647f35da0001Selim Cinek public static <T> T getChildTag(View child, int tag) { 821eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek return (T) child.getTag(tag); 822eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek } 823eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek 824eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek /** 825eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek * Cancel the previous animator and get the duration of the new animation. 82639610545f0c2714a3526bc935effe57b421542d1Selim Cinek * 82760d07c597c3f996deb3f2743466fe5279ca15e8dJorim Jaggi * @param duration the new duration 828eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek * @param previousAnimator the animator which was running before 829eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek * @return the new duration 830eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek */ 83160d07c597c3f996deb3f2743466fe5279ca15e8dJorim Jaggi private long cancelAnimatorAndGetNewDuration(long duration, ValueAnimator previousAnimator) { 83260d07c597c3f996deb3f2743466fe5279ca15e8dJorim Jaggi long newDuration = duration; 833eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek if (previousAnimator != null) { 8348df56452cb696ebdee82df6fb255892eabf3febcSelim Cinek // We take either the desired length of the new animation or the remaining time of 8358df56452cb696ebdee82df6fb255892eabf3febcSelim Cinek // the previous animator, whichever is longer. 8368df56452cb696ebdee82df6fb255892eabf3febcSelim Cinek newDuration = Math.max(previousAnimator.getDuration() 8378df56452cb696ebdee82df6fb255892eabf3febcSelim Cinek - previousAnimator.getCurrentPlayTime(), newDuration); 8383af00cf10660c7fdc0582dc12361c13673d0c9bbSelim Cinek previousAnimator.cancel(); 839eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek } 8403af00cf10660c7fdc0582dc12361c13673d0c9bbSelim Cinek return newDuration; 841eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek } 842eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek 843eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek private void onAnimationFinished() { 844eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek mHostLayout.onChildAnimationFinished(); 8458f93763cf0f4b3c41f6b0ecac09b621eb0ca328bSelim Cinek for (View v : mChildrenToClearFromOverlay) { 846a5703187a9dba418f742fab0874a8f683b0bbb0eSelim Cinek removeFromOverlay(v); 8478f93763cf0f4b3c41f6b0ecac09b621eb0ca328bSelim Cinek } 8488f93763cf0f4b3c41f6b0ecac09b621eb0ca328bSelim Cinek mChildrenToClearFromOverlay.clear(); 849eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek } 850eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek 851eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek /** 852eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek * Process the animationEvents for a new animation 853eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek * 854eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek * @param animationEvents the animation events for the animation to perform 85539610545f0c2714a3526bc935effe57b421542d1Selim Cinek * @param finalState the final state to animate to 85639610545f0c2714a3526bc935effe57b421542d1Selim Cinek */ 857eb973565f3efc6417ca35363e4d6c642947775d8Selim Cinek private void processAnimationEvents( 8580dd6881ea481c855976214807c17595b34a2920aJorim Jaggi ArrayList<NotificationStackScrollLayout.AnimationEvent> animationEvents, 859572bbd42a473980c2d59af80d378f6270ba6860aSelim Cinek StackScrollState finalState) { 8608d9ff9c2c66bc1d3b92eb6992d58599ff80ed6dcSelim Cinek for (NotificationStackScrollLayout.AnimationEvent event : animationEvents) { 8618efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinek final ExpandableView changingView = (ExpandableView) event.changingView; 8628efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinek if (event.animationType == 8638efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinek NotificationStackScrollLayout.AnimationEvent.ANIMATION_TYPE_ADD) { 8648efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinek 8658efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinek // This item is added, initialize it's properties. 866b036ca4de8e93d83bcdc093fbf8f096dc18a810dSelim Cinek StackViewState viewState = finalState 8678efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinek .getViewStateForView(changingView); 8688efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinek if (viewState == null) { 8698efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinek // The position for this child was never generated, let's continue. 8708efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinek continue; 8718efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinek } 872b036ca4de8e93d83bcdc093fbf8f096dc18a810dSelim Cinek finalState.applyState(changingView, viewState); 8738efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinek mNewAddChildren.add(changingView); 8748efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinek 8758efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinek } else if (event.animationType == 8768efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinek NotificationStackScrollLayout.AnimationEvent.ANIMATION_TYPE_REMOVE) { 8778efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinek if (changingView.getVisibility() == View.GONE) { 878a5703187a9dba418f742fab0874a8f683b0bbb0eSelim Cinek removeFromOverlay(changingView); 8798efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinek continue; 8808efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinek } 8818efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinek 8828efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinek // Find the amount to translate up. This is needed in order to understand the 8838efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinek // direction of the remove animation (either downwards or upwards) 884b036ca4de8e93d83bcdc093fbf8f096dc18a810dSelim Cinek StackViewState viewState = finalState 8858efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinek .getViewStateForView(event.viewAfterChangingView); 8868efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinek int actualHeight = changingView.getActualHeight(); 8878efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinek // upwards by default 8888efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinek float translationDirection = -1.0f; 8898efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinek if (viewState != null) { 8908efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinek // there was a view after this one, Approximate the distance the next child 8918efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinek // travelled 8928efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinek translationDirection = ((viewState.yTranslation 8938efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinek - (changingView.getTranslationY() + actualHeight / 2.0f)) * 2 / 8948efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinek actualHeight); 8958efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinek translationDirection = Math.max(Math.min(translationDirection, 1.0f),-1.0f); 8968efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinek 8978efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinek } 89860d07c597c3f996deb3f2743466fe5279ca15e8dJorim Jaggi changingView.performRemoveAnimation(ANIMATION_DURATION_APPEAR_DISAPPEAR, 89960d07c597c3f996deb3f2743466fe5279ca15e8dJorim Jaggi translationDirection, new Runnable() { 9008efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinek @Override 9018efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinek public void run() { 9028efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinek // remove the temporary overlay 903a5703187a9dba418f742fab0874a8f683b0bbb0eSelim Cinek removeFromOverlay(changingView); 9048efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinek } 9058efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinek }); 906b036ca4de8e93d83bcdc093fbf8f096dc18a810dSelim Cinek } else if (event.animationType == 907f336f4c13ad3be15e2b44266cd786685975425f2Selim Cinek NotificationStackScrollLayout.AnimationEvent.ANIMATION_TYPE_REMOVE_SWIPED_OUT) { 908f336f4c13ad3be15e2b44266cd786685975425f2Selim Cinek // A race condition can trigger the view to be added to the overlay even though 909d13956475e97da9de83f6519eab514770118e7afSelim Cinek // it was fully swiped out. So let's remove it 910f336f4c13ad3be15e2b44266cd786685975425f2Selim Cinek mHostLayout.getOverlay().remove(changingView); 911d13956475e97da9de83f6519eab514770118e7afSelim Cinek if (Math.abs(changingView.getTranslation()) == changingView.getWidth() 912d13956475e97da9de83f6519eab514770118e7afSelim Cinek && changingView.getTransientContainer() != null) { 913d13956475e97da9de83f6519eab514770118e7afSelim Cinek changingView.getTransientContainer().removeTransientView(changingView); 914d13956475e97da9de83f6519eab514770118e7afSelim Cinek } 915b5605e58cb8080c8c887b1885336b707596c8094Selim Cinek } else if (event.animationType == NotificationStackScrollLayout 916b5605e58cb8080c8c887b1885336b707596c8094Selim Cinek .AnimationEvent.ANIMATION_TYPE_GROUP_EXPANSION_CHANGED) { 917b5605e58cb8080c8c887b1885336b707596c8094Selim Cinek ExpandableNotificationRow row = (ExpandableNotificationRow) event.changingView; 918b5605e58cb8080c8c887b1885336b707596c8094Selim Cinek row.prepareExpansionChanged(finalState); 919b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek } else if (event.animationType == NotificationStackScrollLayout 920b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek .AnimationEvent.ANIMATION_TYPE_HEADS_UP_APPEAR) { 921b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek // This item is added, initialize it's properties. 922b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek StackViewState viewState = finalState.getViewStateForView(changingView); 923b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek mTmpState.copyFrom(viewState); 924a59ecc3401de0c4bf1e13665158f54669f22d06cSelim Cinek if (event.headsUpFromBottom) { 925a59ecc3401de0c4bf1e13665158f54669f22d06cSelim Cinek mTmpState.yTranslation = mHeadsUpAppearHeightBottom; 926a59ecc3401de0c4bf1e13665158f54669f22d06cSelim Cinek } else { 927a59ecc3401de0c4bf1e13665158f54669f22d06cSelim Cinek mTmpState.yTranslation = -mTmpState.height; 928a59ecc3401de0c4bf1e13665158f54669f22d06cSelim Cinek } 929a59ecc3401de0c4bf1e13665158f54669f22d06cSelim Cinek mHeadsUpAppearChildren.add(changingView); 930b8f09cf5533d458868a335ce334e4880b2b0788dSelim Cinek finalState.applyState(changingView, mTmpState); 931a59ecc3401de0c4bf1e13665158f54669f22d06cSelim Cinek } else if (event.animationType == NotificationStackScrollLayout 9325eb67c22489f5fda22770d1fc824e7a8013ec025Jorim Jaggi .AnimationEvent.ANIMATION_TYPE_HEADS_UP_DISAPPEAR || 9335eb67c22489f5fda22770d1fc824e7a8013ec025Jorim Jaggi event.animationType == NotificationStackScrollLayout 9345eb67c22489f5fda22770d1fc824e7a8013ec025Jorim Jaggi .AnimationEvent.ANIMATION_TYPE_HEADS_UP_DISAPPEAR_CLICK) { 935a59ecc3401de0c4bf1e13665158f54669f22d06cSelim Cinek mHeadsUpDisappearChildren.add(changingView); 936ef5127ea5f34f7a4c961021f6b691174bcb81d2eSelim Cinek if (changingView.getParent() == null) { 9378f93763cf0f4b3c41f6b0ecac09b621eb0ca328bSelim Cinek // This notification was actually removed, so we need to add it to the overlay 9388f93763cf0f4b3c41f6b0ecac09b621eb0ca328bSelim Cinek mHostLayout.getOverlay().add(changingView); 939eaee9c01902ecfc253be98d68e5d7b586ed54463Selim Cinek mTmpState.initFrom(changingView); 940eaee9c01902ecfc253be98d68e5d7b586ed54463Selim Cinek mTmpState.yTranslation = -changingView.getActualHeight(); 9418f93763cf0f4b3c41f6b0ecac09b621eb0ca328bSelim Cinek // We temporarily enable Y animations, the real filter will be combined 9428f93763cf0f4b3c41f6b0ecac09b621eb0ca328bSelim Cinek // afterwards anyway 9438f93763cf0f4b3c41f6b0ecac09b621eb0ca328bSelim Cinek mAnimationFilter.animateY = true; 9445eb67c22489f5fda22770d1fc824e7a8013ec025Jorim Jaggi startViewAnimations(changingView, mTmpState, 9455eb67c22489f5fda22770d1fc824e7a8013ec025Jorim Jaggi event.animationType == NotificationStackScrollLayout 9465eb67c22489f5fda22770d1fc824e7a8013ec025Jorim Jaggi .AnimationEvent.ANIMATION_TYPE_HEADS_UP_DISAPPEAR_CLICK 9475eb67c22489f5fda22770d1fc824e7a8013ec025Jorim Jaggi ? ANIMATION_DELAY_HEADS_UP 9485eb67c22489f5fda22770d1fc824e7a8013ec025Jorim Jaggi : 0, 9498f93763cf0f4b3c41f6b0ecac09b621eb0ca328bSelim Cinek ANIMATION_DURATION_HEADS_UP_DISAPPEAR); 9508f93763cf0f4b3c41f6b0ecac09b621eb0ca328bSelim Cinek mChildrenToClearFromOverlay.add(changingView); 9518f93763cf0f4b3c41f6b0ecac09b621eb0ca328bSelim Cinek } 952572bbd42a473980c2d59af80d378f6270ba6860aSelim Cinek } 9538efa6dde2b4f2cdbf046b87b7366404c3cc46219Selim Cinek mNewEvents.add(event); 954572bbd42a473980c2d59af80d378f6270ba6860aSelim Cinek } 955572bbd42a473980c2d59af80d378f6270ba6860aSelim Cinek } 9568d9ff9c2c66bc1d3b92eb6992d58599ff80ed6dcSelim Cinek 957a5703187a9dba418f742fab0874a8f683b0bbb0eSelim Cinek public static void removeFromOverlay(View changingView) { 958a5703187a9dba418f742fab0874a8f683b0bbb0eSelim Cinek ViewGroup parent = (ViewGroup) changingView.getParent(); 959a5703187a9dba418f742fab0874a8f683b0bbb0eSelim Cinek if (parent != null) { 960a5703187a9dba418f742fab0874a8f683b0bbb0eSelim Cinek parent.removeView(changingView); 961a5703187a9dba418f742fab0874a8f683b0bbb0eSelim Cinek } 962a5703187a9dba418f742fab0874a8f683b0bbb0eSelim Cinek } 963a5703187a9dba418f742fab0874a8f683b0bbb0eSelim Cinek 964475b21dfe517ec04f435f6b02f4a53083d040db4Jorim Jaggi public void animateOverScrollToAmount(float targetAmount, final boolean onTop, 965475b21dfe517ec04f435f6b02f4a53083d040db4Jorim Jaggi final boolean isRubberbanded) { 9668d9ff9c2c66bc1d3b92eb6992d58599ff80ed6dcSelim Cinek final float startOverScrollAmount = mHostLayout.getCurrentOverScrollAmount(onTop); 9679012958742c7a66b37ba5f2196f9086bb1980e6bJorim Jaggi if (targetAmount == startOverScrollAmount) { 9689012958742c7a66b37ba5f2196f9086bb1980e6bJorim Jaggi return; 9699012958742c7a66b37ba5f2196f9086bb1980e6bJorim Jaggi } 9708d9ff9c2c66bc1d3b92eb6992d58599ff80ed6dcSelim Cinek cancelOverScrollAnimators(onTop); 9718d9ff9c2c66bc1d3b92eb6992d58599ff80ed6dcSelim Cinek ValueAnimator overScrollAnimator = ValueAnimator.ofFloat(startOverScrollAmount, 9728d9ff9c2c66bc1d3b92eb6992d58599ff80ed6dcSelim Cinek targetAmount); 9738d9ff9c2c66bc1d3b92eb6992d58599ff80ed6dcSelim Cinek overScrollAnimator.setDuration(ANIMATION_DURATION_STANDARD); 9748d9ff9c2c66bc1d3b92eb6992d58599ff80ed6dcSelim Cinek overScrollAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { 9758d9ff9c2c66bc1d3b92eb6992d58599ff80ed6dcSelim Cinek @Override 9768d9ff9c2c66bc1d3b92eb6992d58599ff80ed6dcSelim Cinek public void onAnimationUpdate(ValueAnimator animation) { 9778d9ff9c2c66bc1d3b92eb6992d58599ff80ed6dcSelim Cinek float currentOverScroll = (float) animation.getAnimatedValue(); 97847c85a3525dcd0bbd3168632830e8ab491d18462Jorim Jaggi mHostLayout.setOverScrollAmount( 979475b21dfe517ec04f435f6b02f4a53083d040db4Jorim Jaggi currentOverScroll, onTop, false /* animate */, false /* cancelAnimators */, 980475b21dfe517ec04f435f6b02f4a53083d040db4Jorim Jaggi isRubberbanded); 9818d9ff9c2c66bc1d3b92eb6992d58599ff80ed6dcSelim Cinek } 9828d9ff9c2c66bc1d3b92eb6992d58599ff80ed6dcSelim Cinek }); 983c18010f6720f606003cde3cd376ddacaca30f6e5Selim Cinek overScrollAnimator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN); 98447c85a3525dcd0bbd3168632830e8ab491d18462Jorim Jaggi overScrollAnimator.addListener(new AnimatorListenerAdapter() { 98547c85a3525dcd0bbd3168632830e8ab491d18462Jorim Jaggi @Override 98647c85a3525dcd0bbd3168632830e8ab491d18462Jorim Jaggi public void onAnimationEnd(Animator animation) { 98747c85a3525dcd0bbd3168632830e8ab491d18462Jorim Jaggi if (onTop) { 98847c85a3525dcd0bbd3168632830e8ab491d18462Jorim Jaggi mTopOverScrollAnimator = null; 98947c85a3525dcd0bbd3168632830e8ab491d18462Jorim Jaggi } else { 99047c85a3525dcd0bbd3168632830e8ab491d18462Jorim Jaggi mBottomOverScrollAnimator = null; 99147c85a3525dcd0bbd3168632830e8ab491d18462Jorim Jaggi } 99247c85a3525dcd0bbd3168632830e8ab491d18462Jorim Jaggi } 99347c85a3525dcd0bbd3168632830e8ab491d18462Jorim Jaggi }); 9948d9ff9c2c66bc1d3b92eb6992d58599ff80ed6dcSelim Cinek overScrollAnimator.start(); 9958d9ff9c2c66bc1d3b92eb6992d58599ff80ed6dcSelim Cinek if (onTop) { 9968d9ff9c2c66bc1d3b92eb6992d58599ff80ed6dcSelim Cinek mTopOverScrollAnimator = overScrollAnimator; 9978d9ff9c2c66bc1d3b92eb6992d58599ff80ed6dcSelim Cinek } else { 9988d9ff9c2c66bc1d3b92eb6992d58599ff80ed6dcSelim Cinek mBottomOverScrollAnimator = overScrollAnimator; 9998d9ff9c2c66bc1d3b92eb6992d58599ff80ed6dcSelim Cinek } 10008d9ff9c2c66bc1d3b92eb6992d58599ff80ed6dcSelim Cinek } 10018d9ff9c2c66bc1d3b92eb6992d58599ff80ed6dcSelim Cinek 10028d9ff9c2c66bc1d3b92eb6992d58599ff80ed6dcSelim Cinek public void cancelOverScrollAnimators(boolean onTop) { 10038d9ff9c2c66bc1d3b92eb6992d58599ff80ed6dcSelim Cinek ValueAnimator currentAnimator = onTop ? mTopOverScrollAnimator : mBottomOverScrollAnimator; 10048d9ff9c2c66bc1d3b92eb6992d58599ff80ed6dcSelim Cinek if (currentAnimator != null) { 10058d9ff9c2c66bc1d3b92eb6992d58599ff80ed6dcSelim Cinek currentAnimator.cancel(); 10068d9ff9c2c66bc1d3b92eb6992d58599ff80ed6dcSelim Cinek } 10078d9ff9c2c66bc1d3b92eb6992d58599ff80ed6dcSelim Cinek } 100802af41efe54eb2cc8fde7311e4cf5f0e5ff2373cSelim Cinek 100902af41efe54eb2cc8fde7311e4cf5f0e5ff2373cSelim Cinek /** 101002af41efe54eb2cc8fde7311e4cf5f0e5ff2373cSelim Cinek * Get the end value of the height animation running on a view or the actualHeight 101102af41efe54eb2cc8fde7311e4cf5f0e5ff2373cSelim Cinek * if no animation is running. 101202af41efe54eb2cc8fde7311e4cf5f0e5ff2373cSelim Cinek */ 101302af41efe54eb2cc8fde7311e4cf5f0e5ff2373cSelim Cinek public static int getFinalActualHeight(ExpandableView view) { 101402af41efe54eb2cc8fde7311e4cf5f0e5ff2373cSelim Cinek if (view == null) { 101502af41efe54eb2cc8fde7311e4cf5f0e5ff2373cSelim Cinek return 0; 101602af41efe54eb2cc8fde7311e4cf5f0e5ff2373cSelim Cinek } 101702af41efe54eb2cc8fde7311e4cf5f0e5ff2373cSelim Cinek ValueAnimator heightAnimator = getChildTag(view, TAG_ANIMATOR_HEIGHT); 101802af41efe54eb2cc8fde7311e4cf5f0e5ff2373cSelim Cinek if (heightAnimator == null) { 101902af41efe54eb2cc8fde7311e4cf5f0e5ff2373cSelim Cinek return view.getActualHeight(); 102002af41efe54eb2cc8fde7311e4cf5f0e5ff2373cSelim Cinek } else { 102102af41efe54eb2cc8fde7311e4cf5f0e5ff2373cSelim Cinek return getChildTag(view, TAG_END_HEIGHT); 102202af41efe54eb2cc8fde7311e4cf5f0e5ff2373cSelim Cinek } 102302af41efe54eb2cc8fde7311e4cf5f0e5ff2373cSelim Cinek } 1024a59ecc3401de0c4bf1e13665158f54669f22d06cSelim Cinek 10256811d728fb988a32cbfc836b768a261a7f60c98aSelim Cinek /** 1026c897bd3e91ed442b0f32c3a5b9918e9e580b62b1Selim Cinek * Get the end value of the yTranslation animation running on a view or the yTranslation 10276811d728fb988a32cbfc836b768a261a7f60c98aSelim Cinek * if no animation is running. 10286811d728fb988a32cbfc836b768a261a7f60c98aSelim Cinek */ 1029c897bd3e91ed442b0f32c3a5b9918e9e580b62b1Selim Cinek public static float getFinalTranslationY(View view) { 10306811d728fb988a32cbfc836b768a261a7f60c98aSelim Cinek if (view == null) { 10316811d728fb988a32cbfc836b768a261a7f60c98aSelim Cinek return 0; 10326811d728fb988a32cbfc836b768a261a7f60c98aSelim Cinek } 10336811d728fb988a32cbfc836b768a261a7f60c98aSelim Cinek ValueAnimator yAnimator = getChildTag(view, TAG_ANIMATOR_TRANSLATION_Y); 10346811d728fb988a32cbfc836b768a261a7f60c98aSelim Cinek if (yAnimator == null) { 10356811d728fb988a32cbfc836b768a261a7f60c98aSelim Cinek return view.getTranslationY(); 10366811d728fb988a32cbfc836b768a261a7f60c98aSelim Cinek } else { 10376811d728fb988a32cbfc836b768a261a7f60c98aSelim Cinek return getChildTag(view, TAG_END_TRANSLATION_Y); 10386811d728fb988a32cbfc836b768a261a7f60c98aSelim Cinek } 10396811d728fb988a32cbfc836b768a261a7f60c98aSelim Cinek } 10406811d728fb988a32cbfc836b768a261a7f60c98aSelim Cinek 1041a59ecc3401de0c4bf1e13665158f54669f22d06cSelim Cinek public void setHeadsUpAppearHeightBottom(int headsUpAppearHeightBottom) { 1042a59ecc3401de0c4bf1e13665158f54669f22d06cSelim Cinek mHeadsUpAppearHeightBottom = headsUpAppearHeightBottom; 1043a59ecc3401de0c4bf1e13665158f54669f22d06cSelim Cinek } 1044a59ecc3401de0c4bf1e13665158f54669f22d06cSelim Cinek 1045a59ecc3401de0c4bf1e13665158f54669f22d06cSelim Cinek public void setShadeExpanded(boolean shadeExpanded) { 1046a59ecc3401de0c4bf1e13665158f54669f22d06cSelim Cinek mShadeExpanded = shadeExpanded; 1047a59ecc3401de0c4bf1e13665158f54669f22d06cSelim Cinek } 1048572bbd42a473980c2d59af80d378f6270ba6860aSelim Cinek} 1049