1988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee/*
2988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee * Copyright (C) 2012 The Android Open Source Project
3988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee *
4988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee * Licensed under the Apache License, Version 2.0 (the "License");
5988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee * you may not use this file except in compliance with the License.
6988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee * You may obtain a copy of the License at
7988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee *
8988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee *      http://www.apache.org/licenses/LICENSE-2.0
9988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee *
10988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee * Unless required by applicable law or agreed to in writing, software
11988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee * distributed under the License is distributed on an "AS IS" BASIS,
12988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee * See the License for the specific language governing permissions and
14988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee * limitations under the License.
15988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee */
16988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee
17988d06b64b99a13f4f060dc82594edcb738d9113Yorke Leepackage com.android.incallui;
18988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee
19988d06b64b99a13f4f060dc82594edcb738d9113Yorke Leeimport android.animation.Animator;
20988d06b64b99a13f4f060dc82594edcb738d9113Yorke Leeimport android.animation.AnimatorListenerAdapter;
21988d06b64b99a13f4f060dc82594edcb738d9113Yorke Leeimport android.animation.ObjectAnimator;
22988d06b64b99a13f4f060dc82594edcb738d9113Yorke Leeimport android.graphics.Canvas;
23988d06b64b99a13f4f060dc82594edcb738d9113Yorke Leeimport android.graphics.drawable.BitmapDrawable;
24988d06b64b99a13f4f060dc82594edcb738d9113Yorke Leeimport android.graphics.drawable.Drawable;
25988d06b64b99a13f4f060dc82594edcb738d9113Yorke Leeimport android.graphics.drawable.LayerDrawable;
26988d06b64b99a13f4f060dc82594edcb738d9113Yorke Leeimport android.view.ViewPropertyAnimator;
27988d06b64b99a13f4f060dc82594edcb738d9113Yorke Leeimport android.widget.ImageView;
28988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee
29988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee/**
30988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee * Utilities for Animation.
31988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee */
32382b39d1b21c878fdeda387571ad6d9e784c9a73Andrew Leepublic class InCallAnimationUtils {
33382b39d1b21c878fdeda387571ad6d9e784c9a73Andrew Lee    private static final String LOG_TAG = InCallAnimationUtils.class.getSimpleName();
34988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee    /**
35988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee     * Turn on when you're interested in fading animation. Intentionally untied from other debug
36988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee     * settings.
37988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee     */
38988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee    private static final boolean FADE_DBG = false;
39988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee
40988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee    /**
41988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee     * Duration for animations in msec, which can be used with
42988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee     * {@link ViewPropertyAnimator#setDuration(long)} for example.
43988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee     */
44988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee    public static final int ANIMATION_DURATION = 250;
45988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee
46382b39d1b21c878fdeda387571ad6d9e784c9a73Andrew Lee    private InCallAnimationUtils() {
47988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee    }
48988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee
49988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee    /**
50988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee     * Drawable achieving cross-fade, just like TransitionDrawable. We can have
51988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee     * call-backs via animator object (see also {@link CrossFadeDrawable#getAnimator()}).
52988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee     */
53988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee    private static class CrossFadeDrawable extends LayerDrawable {
54988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee        private final ObjectAnimator mAnimator;
55988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee
56988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee        public CrossFadeDrawable(Drawable[] layers) {
57988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee            super(layers);
58988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee            mAnimator = ObjectAnimator.ofInt(this, "crossFadeAlpha", 0xff, 0);
59988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee        }
60988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee
61988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee        private int mCrossFadeAlpha;
62988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee
63988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee        /**
64988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee         * This will be used from ObjectAnimator.
65988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee         * Note: this method is protected by proguard.flags so that it won't be removed
66988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee         * automatically.
67988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee         */
68988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee        @SuppressWarnings("unused")
69988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee        public void setCrossFadeAlpha(int alpha) {
70988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee            mCrossFadeAlpha = alpha;
71988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee            invalidateSelf();
72988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee        }
73988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee
74988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee        public ObjectAnimator getAnimator() {
75988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee            return mAnimator;
76988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee        }
77988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee
78988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee        @Override
79988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee        public void draw(Canvas canvas) {
80988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee            Drawable first = getDrawable(0);
81988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee            Drawable second = getDrawable(1);
82988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee
83988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee            if (mCrossFadeAlpha > 0) {
84988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee                first.setAlpha(mCrossFadeAlpha);
85988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee                first.draw(canvas);
86988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee                first.setAlpha(255);
87988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee            }
88988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee
89988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee            if (mCrossFadeAlpha < 0xff) {
90988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee                second.setAlpha(0xff - mCrossFadeAlpha);
91988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee                second.draw(canvas);
92988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee                second.setAlpha(0xff);
93988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee            }
94988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee        }
95988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee    }
96988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee
97988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee    private static CrossFadeDrawable newCrossFadeDrawable(Drawable first, Drawable second) {
98988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee        Drawable[] layers = new Drawable[2];
99988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee        layers[0] = first;
100988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee        layers[1] = second;
101988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee        return new CrossFadeDrawable(layers);
102988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee    }
103988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee
104988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee    /**
105988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee     * Starts cross-fade animation using TransitionDrawable. Nothing will happen if "from" and "to"
106988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee     * are the same.
107988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee     */
108988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee    public static void startCrossFade(
109988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee            final ImageView imageView, final Drawable from, final Drawable to) {
110988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee        // We skip the cross-fade when those two Drawables are equal, or they are BitmapDrawables
111988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee        // pointing to the same Bitmap.
11245ce12981f1282368735ea600c71991512ff5d3fChristine Chen        final boolean drawableIsEqual = (from != null && to != null && from.equals(to));
11345ce12981f1282368735ea600c71991512ff5d3fChristine Chen        final boolean hasFromImage = ((from instanceof BitmapDrawable) &&
11445ce12981f1282368735ea600c71991512ff5d3fChristine Chen                ((BitmapDrawable) from).getBitmap() != null);
11545ce12981f1282368735ea600c71991512ff5d3fChristine Chen        final boolean hasToImage = ((to instanceof BitmapDrawable) &&
11645ce12981f1282368735ea600c71991512ff5d3fChristine Chen                ((BitmapDrawable) to).getBitmap() != null);
11745ce12981f1282368735ea600c71991512ff5d3fChristine Chen        final boolean areSameImage = drawableIsEqual || (hasFromImage && hasToImage &&
11845ce12981f1282368735ea600c71991512ff5d3fChristine Chen                ((BitmapDrawable) from).getBitmap().equals(((BitmapDrawable) to).getBitmap()));
11945ce12981f1282368735ea600c71991512ff5d3fChristine Chen
120988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee        if (!areSameImage) {
121988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee            if (FADE_DBG) {
122988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee                log("Start cross-fade animation for " + imageView
123988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee                        + "(" + Integer.toHexString(from.hashCode()) + " -> "
124988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee                        + Integer.toHexString(to.hashCode()) + ")");
125988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee            }
126988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee
127988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee            CrossFadeDrawable crossFadeDrawable = newCrossFadeDrawable(from, to);
128988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee            ObjectAnimator animator = crossFadeDrawable.getAnimator();
129988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee            imageView.setImageDrawable(crossFadeDrawable);
130988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee            animator.setDuration(ANIMATION_DURATION);
131988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee            animator.addListener(new AnimatorListenerAdapter() {
132988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee                @Override
133988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee                public void onAnimationStart(Animator animation) {
134988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee                    if (FADE_DBG) {
135988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee                        log("cross-fade animation start ("
136988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee                                + Integer.toHexString(from.hashCode()) + " -> "
137988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee                                + Integer.toHexString(to.hashCode()) + ")");
138988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee                    }
139988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee                }
140988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee
141988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee                @Override
142988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee                public void onAnimationEnd(Animator animation) {
143988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee                    if (FADE_DBG) {
144988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee                        log("cross-fade animation ended ("
145988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee                                + Integer.toHexString(from.hashCode()) + " -> "
146988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee                                + Integer.toHexString(to.hashCode()) + ")");
147988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee                    }
148988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee                    animation.removeAllListeners();
149988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee                    // Workaround for issue 6300562; this will force the drawable to the
150988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee                    // resultant one regardless of animation glitch.
151988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee                    imageView.setImageDrawable(to);
152988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee                }
153988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee            });
154988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee            animator.start();
155988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee
156988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee            /* We could use TransitionDrawable here, but it may cause some weird animation in
157988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee             * some corner cases. See issue 6300562
158988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee             * TODO: decide which to be used in the long run. TransitionDrawable is old but system
159988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee             * one. Ours uses new animation framework and thus have callback (great for testing),
160988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee             * while no framework support for the exact class.
161988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee
162988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee            Drawable[] layers = new Drawable[2];
163988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee            layers[0] = from;
164988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee            layers[1] = to;
165988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee            TransitionDrawable transitionDrawable = new TransitionDrawable(layers);
166988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee            imageView.setImageDrawable(transitionDrawable);
167988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee            transitionDrawable.startTransition(ANIMATION_DURATION); */
168988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee            imageView.setTag(to);
16945ce12981f1282368735ea600c71991512ff5d3fChristine Chen        } else if (!hasFromImage && hasToImage) {
17045ce12981f1282368735ea600c71991512ff5d3fChristine Chen            imageView.setImageDrawable(to);
17145ce12981f1282368735ea600c71991512ff5d3fChristine Chen            imageView.setTag(to);
172988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee        } else {
173988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee            if (FADE_DBG) {
174988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee                log("*Not* start cross-fade. " + imageView);
175988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee            }
176988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee        }
177988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee    }
178988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee
179988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee    // Debugging / testing code
180988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee
181988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee    private static void log(String msg) {
182988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee        Log.d(LOG_TAG, msg);
183988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee    }
184988d06b64b99a13f4f060dc82594edcb738d9113Yorke Lee}