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}