Skip to content
Browse files

Introduce CrossFadeDrawable

This is almost a workaround for bug 6300562 "After splitting call in
manage conference screen, one contact picture may not become that
person's one but still conference's one."

It hapeens when the caller has a conference call with two destinations
and split the call by choosing the second person. At that moment the
animation transition becomes weird in some manner. It won't happen (at
this moment) if the first person is chosen there.

This change will reduce the headache by resetting the intermediate
drawable to the correct one. Wrongly made drawable is cleared at the
last step of the animation, and user will see the correct picture
eventually, while the cross-fade animation is still weird in the case
above.

As a side effect we can have a callback which is consistent with the
other part of the animation util we have so far.

Bug: 6300562
Change-Id: I418afcddb890025b3e3297747a4ff13a2959f65d
  • Loading branch information...
1 parent 5a4f9e5 commit a84a05e92fca88e677a5c9c08885d7d9e914c7d5 Daisuke Miyakawa committed Apr 12, 2012
Showing with 106 additions and 4 deletions.
  1. +2 −0 Android.mk
  2. +4 −0 proguard.flags
  3. +100 −4 src/com/android/phone/AnimationUtils.java
View
2 Android.mk
@@ -29,6 +29,8 @@ LOCAL_SRC_FILES += \
LOCAL_PACKAGE_NAME := Phone
LOCAL_CERTIFICATE := platform
+LOCAL_PROGUARD_FLAG_FILES := proguard.flags
+
include $(BUILD_PACKAGE)
# Build the test package
View
4 proguard.flags
@@ -0,0 +1,4 @@
+# Keep names that are used only by animation framework.
+-keep class ** {
+ *** *ForAnimator(...);
+}
View
104 src/com/android/phone/AnimationUtils.java
@@ -18,8 +18,10 @@
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
+import android.animation.ObjectAnimator;
+import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
-import android.graphics.drawable.TransitionDrawable;
+import android.graphics.drawable.LayerDrawable;
import android.util.Log;
import android.view.View;
import android.view.ViewPropertyAnimator;
@@ -145,21 +147,115 @@ public static boolean isFadingOut(final View view) {
}
/**
+ * Drawable achieving cross-fade, just like TransitionDrawable. We can have
+ * call-backs via animator object (see also {@link CrossFadeDrawable#getAnimator()}).
+ */
+ private static class CrossFadeDrawable extends LayerDrawable {
+ private final ObjectAnimator mAnimator;
+
+ public CrossFadeDrawable(Drawable[] layers) {
+ super(layers);
+ mAnimator = ObjectAnimator.ofInt(this, "crossFadeAlphaForAnimator", 0xff, 0);
+ }
+
+ private int mCrossFadeAlpha;
+
+ /** This will be used from ObjectAnimator. */
+ @SuppressWarnings("unused")
+ public void setCrossFadeAlphaForAnimator(int alpha) {
+ mCrossFadeAlpha = alpha;
+ invalidateSelf();
+ }
+
+ public ObjectAnimator getAnimator() {
+ return mAnimator;
+ }
+
+ @Override
+ public void draw(Canvas canvas) {
+ Drawable first = getDrawable(0);
+ Drawable second = getDrawable(1);
+
+ if (mCrossFadeAlpha > 0) {
+ first.setAlpha(mCrossFadeAlpha);
+ first.draw(canvas);
+ first.setAlpha(255);
+ }
+
+ if (mCrossFadeAlpha < 0xff) {
+ second.setAlpha(0xff - mCrossFadeAlpha);
+ second.draw(canvas);
+ second.setAlpha(0xff);
+ }
+ }
+ }
+
+ private static CrossFadeDrawable newCrossFadeDrawable(Drawable first, Drawable second) {
+ Drawable[] layers = new Drawable[2];
+ layers[0] = first;
+ layers[1] = second;
+ return new CrossFadeDrawable(layers);
+ }
+
+ /**
* Starts cross-fade animation using TransitionDrawable. Nothing will happen if "from" and "to"
* are the same.
*/
- public static void startCrossFade(ImageView imageView, Drawable from, Drawable to) {
+ public static void startCrossFade(
+ final ImageView imageView, final Drawable from, final Drawable to) {
if (!from.equals(to)) {
if (FADE_DBG) {
- log("Start transition animation for " + imageView + " (from " + from + " to " + to);
+ log("Start cross-fade animation for " + imageView
+ + "(" + Integer.toHexString(from.hashCode()) + " -> "
+ + Integer.toHexString(to.hashCode()) + ")");
}
+
+ CrossFadeDrawable crossFadeDrawable = newCrossFadeDrawable(from, to);
+ ObjectAnimator animator = crossFadeDrawable.getAnimator();
+ imageView.setImageDrawable(crossFadeDrawable);
+ animator.setDuration(ANIMATION_DURATION);
+ animator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationStart(Animator animation) {
+ if (FADE_DBG) {
+ log("cross-fade animation start ("
+ + Integer.toHexString(from.hashCode()) + " -> "
+ + Integer.toHexString(to.hashCode()) + ")");
+ }
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ if (FADE_DBG) {
+ log("cross-fade animation ended ("
+ + Integer.toHexString(from.hashCode()) + " -> "
+ + Integer.toHexString(to.hashCode()) + ")");
+ }
+ animation.removeAllListeners();
+ // Workaround for issue 6300562; this will force the drawable to the
+ // resultant one regardless of animation glitch.
+ imageView.setImageDrawable(to);
+ }
+ });
+ animator.start();
+
+ /* We could use TransitionDrawable here, but it may cause some weird animation in
+ * some corner cases. See issue 6300562
+ * TODO: decide which to be used in the long run. TransitionDrawable is old but system
+ * one. Ours uses new animation framework and thus have callback (great for testing),
+ * while no framework support for the exact class.
+
Drawable[] layers = new Drawable[2];
layers[0] = from;
layers[1] = to;
TransitionDrawable transitionDrawable = new TransitionDrawable(layers);
imageView.setImageDrawable(transitionDrawable);
- transitionDrawable.startTransition(ANIMATION_DURATION);
+ transitionDrawable.startTransition(ANIMATION_DURATION); */
imageView.setTag(to);
+ } else {
+ if (FADE_DBG) {
+ log("*Not* start cross-fade. " + imageView);
+ }
}
}

0 comments on commit a84a05e

Please sign in to comment.
Something went wrong with that request. Please try again.