1ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann/*
2ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann * Copyright (C) 2012 The Android Open Source Project
3ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann *
4ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann * Licensed under the Apache License, Version 2.0 (the "License");
5ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann * you may not use this file except in compliance with the License.
6ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann * You may obtain a copy of the License at
7ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann *
8ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann *      http://www.apache.org/licenses/LICENSE-2.0
9ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann *
10ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann * Unless required by applicable law or agreed to in writing, software
11ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann * distributed under the License is distributed on an "AS IS" BASIS,
12ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann * See the License for the specific language governing permissions and
14ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann * limitations under the License.
15ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann */
16ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann
17ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmannpackage com.android.contacts.editor;
18ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann
19ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmannimport android.animation.Animator;
20ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmannimport android.animation.Animator.AnimatorListener;
21ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmannimport android.animation.AnimatorListenerAdapter;
22ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmannimport android.animation.AnimatorSet;
23ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmannimport android.animation.ObjectAnimator;
24ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmannimport android.view.View;
25ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmannimport android.view.ViewGroup;
26ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmannimport android.view.ViewParent;
27ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmannimport android.widget.LinearLayout;
28ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann
29e0b2f1e2d01d1ac52ba207dc7ce76971d853298eChiao Chengimport com.android.contacts.util.SchedulingUtils;
30e0b2f1e2d01d1ac52ba207dc7ce76971d853298eChiao Chengimport com.google.common.collect.Lists;
31e0b2f1e2d01d1ac52ba207dc7ce76971d853298eChiao Cheng
32ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmannimport java.util.List;
33ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann
34ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann/**
35ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann * Configures animations for typical use-cases
36ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann */
37ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmannpublic class EditorAnimator {
38ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann    private static EditorAnimator sInstance = new EditorAnimator();
39ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann
40ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann    public static  EditorAnimator getInstance() {
41ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann        return sInstance;
42ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann    }
43ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann
44ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann    /** Private constructor for singleton */
45ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann    private EditorAnimator() { }
46ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann
47ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann    private AnimatorRunner mRunner = new AnimatorRunner();
48ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann
49ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann    public void removeEditorView(final View victim) {
50ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann        mRunner.endOldAnimation();
51ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann        final int offset = victim.getHeight();
52ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann
53ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann        final List<View> viewsToMove = getViewsBelowOf(victim);
54ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann        final List<Animator> animators = Lists.newArrayList();
55ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann
56ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann        // Fade out
57ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann        final ObjectAnimator fadeOutAnimator =
58ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann                ObjectAnimator.ofFloat(victim, View.ALPHA, 1.0f, 0.0f);
59ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann        fadeOutAnimator.setDuration(200);
60ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann        animators.add(fadeOutAnimator);
61ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann
62ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann        // Translations
63ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann        translateViews(animators, viewsToMove, 0.0f, -offset, 100, 200);
64ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann
65ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann        mRunner.run(animators, new AnimatorListenerAdapter() {
66ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann            @Override
67ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann            public void onAnimationEnd(Animator animation) {
68ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann                // Clean up: Remove all the translations
69ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann                for (int i = 0; i < viewsToMove.size(); i++) {
70ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann                    final View view = viewsToMove.get(i);
71ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann                    view.setTranslationY(0.0f);
72ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann                }
73ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann                // Remove our target view (if parent is null, we were run several times by quick
74ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann                // fingers. Just ignore)
75ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann                final ViewGroup victimParent = (ViewGroup) victim.getParent();
76ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann                if (victimParent != null) {
77ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann                    victimParent.removeView(victim);
78ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann                }
79ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann            }
80ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann        });
81ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann    }
82ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann
83ba48d21f2ab25c8ffb30198a752e5cd215553728Yorke Lee    /**
84ba48d21f2ab25c8ffb30198a752e5cd215553728Yorke Lee     * Slides the view into its new height, while simultaneously fading it into view.
85ba48d21f2ab25c8ffb30198a752e5cd215553728Yorke Lee     *
86ba48d21f2ab25c8ffb30198a752e5cd215553728Yorke Lee     * @param target The target view to perform the animation on.
87ba48d21f2ab25c8ffb30198a752e5cd215553728Yorke Lee     * @param previousHeight The previous height of the view before its height was changed.
88ba48d21f2ab25c8ffb30198a752e5cd215553728Yorke Lee     * Needed because the view does not store any state information about its previous height.
89ba48d21f2ab25c8ffb30198a752e5cd215553728Yorke Lee     */
90ba48d21f2ab25c8ffb30198a752e5cd215553728Yorke Lee    public void slideAndFadeIn(final ViewGroup target, final int previousHeight) {
91ba48d21f2ab25c8ffb30198a752e5cd215553728Yorke Lee        mRunner.endOldAnimation();
92ba48d21f2ab25c8ffb30198a752e5cd215553728Yorke Lee        target.setVisibility(View.VISIBLE);
93ba48d21f2ab25c8ffb30198a752e5cd215553728Yorke Lee        target.setAlpha(0.0f);
94ba48d21f2ab25c8ffb30198a752e5cd215553728Yorke Lee        target.requestFocus();
95ba48d21f2ab25c8ffb30198a752e5cd215553728Yorke Lee        SchedulingUtils.doAfterLayout(target, new Runnable() {
96ba48d21f2ab25c8ffb30198a752e5cd215553728Yorke Lee            @Override
97ba48d21f2ab25c8ffb30198a752e5cd215553728Yorke Lee            public void run() {
98ba48d21f2ab25c8ffb30198a752e5cd215553728Yorke Lee                final int offset = target.getHeight() - previousHeight;
99ba48d21f2ab25c8ffb30198a752e5cd215553728Yorke Lee                final List<Animator> animators = Lists.newArrayList();
100ba48d21f2ab25c8ffb30198a752e5cd215553728Yorke Lee
101ba48d21f2ab25c8ffb30198a752e5cd215553728Yorke Lee                // Translations
102ba48d21f2ab25c8ffb30198a752e5cd215553728Yorke Lee                final List<View> viewsToMove = getViewsBelowOf(target);
103ba48d21f2ab25c8ffb30198a752e5cd215553728Yorke Lee
104ba48d21f2ab25c8ffb30198a752e5cd215553728Yorke Lee                translateViews(animators, viewsToMove, -offset, 0.0f, 0, 200);
105ba48d21f2ab25c8ffb30198a752e5cd215553728Yorke Lee
106ba48d21f2ab25c8ffb30198a752e5cd215553728Yorke Lee                // Fade in
107ba48d21f2ab25c8ffb30198a752e5cd215553728Yorke Lee                final ObjectAnimator fadeInAnimator = ObjectAnimator.ofFloat(
108ba48d21f2ab25c8ffb30198a752e5cd215553728Yorke Lee                        target, View.ALPHA, 0.0f, 1.0f);
109ba48d21f2ab25c8ffb30198a752e5cd215553728Yorke Lee                fadeInAnimator.setDuration(200);
110ba48d21f2ab25c8ffb30198a752e5cd215553728Yorke Lee                fadeInAnimator.setStartDelay(200);
111ba48d21f2ab25c8ffb30198a752e5cd215553728Yorke Lee                animators.add(fadeInAnimator);
112ba48d21f2ab25c8ffb30198a752e5cd215553728Yorke Lee
113ba48d21f2ab25c8ffb30198a752e5cd215553728Yorke Lee                mRunner.run(animators);
114ba48d21f2ab25c8ffb30198a752e5cd215553728Yorke Lee            }
115ba48d21f2ab25c8ffb30198a752e5cd215553728Yorke Lee        });
116ba48d21f2ab25c8ffb30198a752e5cd215553728Yorke Lee    }
117ba48d21f2ab25c8ffb30198a752e5cd215553728Yorke Lee
118ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann    public void expandOrganization(final View addOrganizationButton,
119ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann            final ViewGroup organizationSectionViewContainer) {
120ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann        mRunner.endOldAnimation();
121ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann        // Make the new controls visible and do one layout pass (so that we can measure)
122ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann        organizationSectionViewContainer.setVisibility(View.VISIBLE);
123ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann        organizationSectionViewContainer.setAlpha(0.0f);
124ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann        organizationSectionViewContainer.requestFocus();
1256f5557e3dc3cd12182026bdfea17b15d4d9b7dfcJosh Gargus        SchedulingUtils.doAfterLayout(addOrganizationButton, new Runnable() {
126ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann            @Override
127ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann            public void run() {
128ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann                // How many pixels extra do we need?
129ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann                final int offset = organizationSectionViewContainer.getHeight() -
130ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann                        addOrganizationButton.getHeight();
131ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann                final List<Animator> animators = Lists.newArrayList();
132ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann
133ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann                // Fade out
134ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann                final ObjectAnimator fadeOutAnimator = ObjectAnimator.ofFloat(
135ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann                        addOrganizationButton, View.ALPHA, 1.0f, 0.0f);
136ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann                fadeOutAnimator.setDuration(200);
137ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann                animators.add(fadeOutAnimator);
138ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann
139ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann                // Translations
140ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann                final List<View> viewsToMove = getViewsBelowOf(organizationSectionViewContainer);
141ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann                translateViews(animators, viewsToMove, -offset, 0.0f, 0, 200);
142ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann                // Fade in
143ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann                final ObjectAnimator fadeInAnimator = ObjectAnimator.ofFloat(
144ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann                        organizationSectionViewContainer, View.ALPHA, 0.0f, 1.0f);
145ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann                fadeInAnimator.setDuration(200);
146ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann                fadeInAnimator.setStartDelay(200);
147ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann                animators.add(fadeInAnimator);
148ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann
149ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann                mRunner.run(animators);
150ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann            }
151ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann        });
152ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann    }
153ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann
154ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann    public void showAddFieldFooter(final View view) {
155ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann        mRunner.endOldAnimation();
156ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann        if (view.getVisibility() == View.VISIBLE) return;
157ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann        // Make the new controls visible and do one layout pass (so that we can measure)
158ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann        view.setVisibility(View.VISIBLE);
159ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann        view.setAlpha(0.0f);
1606f5557e3dc3cd12182026bdfea17b15d4d9b7dfcJosh Gargus        SchedulingUtils.doAfterLayout(view, new Runnable() {
161ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann            @Override
162ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann            public void run() {
163ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann                // How many pixels extra do we need?
164ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann                final int offset = view.getHeight();
165ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann
166ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann                final List<Animator> animators = Lists.newArrayList();
167ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann
168ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann                // Translations
169ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann                final List<View> viewsToMove = getViewsBelowOf(view);
170ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann                translateViews(animators, viewsToMove, -offset, 0.0f, 0, 200);
171ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann
172ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann                // Fade in
173ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann                final ObjectAnimator fadeInAnimator = ObjectAnimator.ofFloat(
174ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann                        view, View.ALPHA, 0.0f, 1.0f);
175ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann                fadeInAnimator.setDuration(200);
176ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann                fadeInAnimator.setStartDelay(200);
177ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann                animators.add(fadeInAnimator);
178ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann
179ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann                mRunner.run(animators);
180ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann            }
181ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann        });
182ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann    }
183ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann
184ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann    public void hideAddFieldFooter(final View victim) {
185ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann        mRunner.endOldAnimation();
186ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann        if (victim.getVisibility() == View.GONE) return;
187ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann        final int offset = victim.getHeight();
188ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann
189ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann        final List<View> viewsToMove = getViewsBelowOf(victim);
190ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann        final List<Animator> animators = Lists.newArrayList();
191ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann
192ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann        // Fade out
193ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann        final ObjectAnimator fadeOutAnimator =
194ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann                ObjectAnimator.ofFloat(victim, View.ALPHA, 1.0f, 0.0f);
195ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann        fadeOutAnimator.setDuration(200);
196ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann        animators.add(fadeOutAnimator);
197ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann
198ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann        // Translations
199ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann        translateViews(animators, viewsToMove, 0.0f, -offset, 100, 200);
200ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann
201ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann        // Combine
202ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann        mRunner.run(animators, new AnimatorListenerAdapter() {
203ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann            @Override
204ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann            public void onAnimationEnd(Animator animation) {
205ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann                // Clean up: Remove all the translations
206ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann                for (int i = 0; i < viewsToMove.size(); i++) {
207ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann                    final View view = viewsToMove.get(i);
208ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann                    view.setTranslationY(0.0f);
209ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann                }
210ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann
211ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann                // Restore alpha (for next time), but hide the view for good now
212ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann                victim.setAlpha(1.0f);
213ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann                victim.setVisibility(View.GONE);
214ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann            }
215ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann        });
216ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann    }
217ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann
218ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann    /**
219ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann     * Creates a translation-animation for the given views
220ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann     */
221ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann    private static void translateViews(List<Animator> animators, List<View> views, float fromY,
222ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann            float toY, int startDelay, int duration) {
223ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann        for (int i = 0; i < views.size(); i++) {
224ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann            final View child = views.get(i);
225ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann            final ObjectAnimator translateAnimator =
226ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann                    ObjectAnimator.ofFloat(child, View.TRANSLATION_Y, fromY, toY);
227ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann            translateAnimator.setStartDelay(startDelay);
228ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann            translateAnimator.setDuration(duration);
229ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann            animators.add(translateAnimator);
230ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann        }
231ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann    }
232ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann
233ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann    /**
234ba48d21f2ab25c8ffb30198a752e5cd215553728Yorke Lee     * Traverses up the view hierarchy and returns all views physically below this item.
2352e9ee9f15a1d928619a49ad259cdccbc8c7414dcChiao Cheng     *
2362e9ee9f15a1d928619a49ad259cdccbc8c7414dcChiao Cheng     * @return List of views that are below the given view. Empty list if parent of view is null.
237ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann     */
238ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann    private static List<View> getViewsBelowOf(View view) {
239ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann        final ViewGroup victimParent = (ViewGroup) view.getParent();
240ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann        final List<View> result = Lists.newArrayList();
2412e9ee9f15a1d928619a49ad259cdccbc8c7414dcChiao Cheng        if (victimParent != null) {
2422e9ee9f15a1d928619a49ad259cdccbc8c7414dcChiao Cheng            final int index = victimParent.indexOfChild(view);
243ba48d21f2ab25c8ffb30198a752e5cd215553728Yorke Lee            getViewsBelowOfRecursive(result, victimParent, index + 1, view);
2442e9ee9f15a1d928619a49ad259cdccbc8c7414dcChiao Cheng        }
245ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann        return result;
246ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann    }
247ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann
248ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann    private static void getViewsBelowOfRecursive(List<View> result, ViewGroup container,
249ba48d21f2ab25c8ffb30198a752e5cd215553728Yorke Lee            int index, View target) {
250ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann        for (int i = index; i < container.getChildCount(); i++) {
251ba48d21f2ab25c8ffb30198a752e5cd215553728Yorke Lee            View view = container.getChildAt(i);
252ba48d21f2ab25c8ffb30198a752e5cd215553728Yorke Lee            // consider the child view below the target view only if it is physically
253ba48d21f2ab25c8ffb30198a752e5cd215553728Yorke Lee            // below the view on-screen, using half the height of the target view as the
254ba48d21f2ab25c8ffb30198a752e5cd215553728Yorke Lee            // baseline
255ba48d21f2ab25c8ffb30198a752e5cd215553728Yorke Lee            if (view.getY() > (target.getY() + target.getHeight() / 2)) {
256ba48d21f2ab25c8ffb30198a752e5cd215553728Yorke Lee                result.add(view);
257ba48d21f2ab25c8ffb30198a752e5cd215553728Yorke Lee            }
258ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann        }
259ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann
260ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann        final ViewParent parent = container.getParent();
261ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann        if (parent instanceof LinearLayout) {
262ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann            final LinearLayout parentLayout = (LinearLayout) parent;
263ba48d21f2ab25c8ffb30198a752e5cd215553728Yorke Lee            int containerIndex = parentLayout.indexOfChild(container);
264ba48d21f2ab25c8ffb30198a752e5cd215553728Yorke Lee            getViewsBelowOfRecursive(result, parentLayout, containerIndex + 1, target);
265ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann        }
266ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann    }
267ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann
268ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann    /**
269ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann     * Keeps a reference to the last animator, so that we can end that early if the user
270ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann     * quickly pushes buttons. Removes the reference once the animation has finished
271ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann     */
272ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann    /* package */ static class AnimatorRunner extends AnimatorListenerAdapter {
273ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann        private Animator mLastAnimator;
274ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann
275ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann        @Override
276ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann        public void onAnimationEnd(Animator animation) {
277ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann            mLastAnimator = null;
278ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann        }
279ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann
280ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann        public void run(List<Animator> animators) {
281ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann            run(animators, null);
282ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann        }
283ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann
284ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann        public void run(List<Animator> animators, AnimatorListener listener) {
285ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann            final AnimatorSet set = new AnimatorSet();
286ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann            set.playTogether(animators);
287ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann            if (listener != null) set.addListener(listener);
288ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann            set.addListener(this);
289ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann            mLastAnimator = set;
290ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann            set.start();
291ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann        }
292ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann
293ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann        public void endOldAnimation() {
294ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann            if (mLastAnimator != null) {
295ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann                mLastAnimator.end();
296ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann            }
297ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann        }
298ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann    }
299ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann}
300