Merge "De-jank quick contact animation" into jb-dev
diff --git a/proguard.flags b/proguard.flags
index 79378e6..39784b1 100644
--- a/proguard.flags
+++ b/proguard.flags
@@ -9,10 +9,12 @@
   public void *(android.view.MenuItem);
 }
 
-# Any class or method annotated with NeededForTesting.
+# Any class or method annotated with NeededForTesting or NeededForReflection.
 -keep @com.android.contacts.test.NeededForTesting class *
+-keep @com.android.contacts.test.NeededForReflection class *
 -keepclassmembers class * {
 @com.android.contacts.test.NeededForTesting *;
+@com.android.contacts.test.NeededForReflection *;
 }
 
 -verbose
diff --git a/src/com/android/contacts/quickcontact/FloatingChildLayout.java b/src/com/android/contacts/quickcontact/FloatingChildLayout.java
index dca738c..20a3c1e 100644
--- a/src/com/android/contacts/quickcontact/FloatingChildLayout.java
+++ b/src/com/android/contacts/quickcontact/FloatingChildLayout.java
@@ -17,15 +17,17 @@
 package com.android.contacts.quickcontact;
 
 import com.android.contacts.R;
+import com.android.contacts.test.NeededForReflection;
+import com.android.contacts.util.SchedulingUtils;
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
+import android.animation.ObjectAnimator;
 import android.content.Context;
 import android.content.res.Resources;
 import android.graphics.Rect;
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
-import android.graphics.drawable.TransitionDrawable;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.view.MotionEvent;
@@ -53,11 +55,13 @@
     private View mChild;
     private Rect mTargetScreen = new Rect();
     private final int mAnimationDuration;
-    private final TransitionDrawable mBackground;
 
     /** The phase of the background dim. This is one of the values of {@link BackgroundPhase}  */
     private int mBackgroundPhase = BackgroundPhase.BEFORE;
 
+    private ObjectAnimator mBackgroundAnimator = ObjectAnimator.ofInt(this,
+            "backgroundColorAlpha", 0, DIM_BACKGROUND_ALPHA);
+
     private interface BackgroundPhase {
         public static final int BEFORE = 0;
         public static final int APPEARING_OR_VISIBLE = 1;
@@ -76,7 +80,7 @@
     }
 
     // Black, 50% alpha as per the system default.
-    private static final int DIM_BACKGROUND_COLOR = 0x7F000000;
+    private static final int DIM_BACKGROUND_ALPHA = 0x7F;
 
     public FloatingChildLayout(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -85,10 +89,7 @@
                 resources.getDimensionPixelOffset(R.dimen.quick_contact_top_position);
         mAnimationDuration = resources.getInteger(android.R.integer.config_shortAnimTime);
 
-        final ColorDrawable[] drawables =
-            { new ColorDrawable(0), new ColorDrawable(DIM_BACKGROUND_COLOR) };
-        mBackground = new TransitionDrawable(drawables);
-        super.setBackground(mBackground);
+        super.setBackground(new ColorDrawable(0));
     }
 
     @Override
@@ -178,17 +179,35 @@
         child.layout(left, top, left + child.getMeasuredWidth(), top + child.getMeasuredHeight());
     }
 
+    @NeededForReflection
+    public void setBackgroundColorAlpha(int alpha) {
+        setBackgroundColor(alpha << 24);
+    }
+
     public void fadeInBackground() {
         if (mBackgroundPhase == BackgroundPhase.BEFORE) {
             mBackgroundPhase = BackgroundPhase.APPEARING_OR_VISIBLE;
-            mBackground.startTransition(mAnimationDuration);
+
+            createChildLayer();
+
+            SchedulingUtils.doAfterDraw(this, new Runnable() {
+                @Override
+                public void run() {
+                    mBackgroundAnimator.setDuration(mAnimationDuration).start();
+                }
+            });
         }
     }
 
     public void fadeOutBackground() {
         if (mBackgroundPhase == BackgroundPhase.APPEARING_OR_VISIBLE) {
             mBackgroundPhase = BackgroundPhase.DISAPPEARING_OR_GONE;
-            mBackground.reverseTransition(mAnimationDuration);
+            if (mBackgroundAnimator.isRunning()) {
+                mBackgroundAnimator.reverse();
+            } else {
+                ObjectAnimator.ofInt(this, "backgroundColorAlpha", DIM_BACKGROUND_ALPHA, 0).
+                        setDuration(mAnimationDuration).start();
+            }
         }
     }
 
@@ -212,6 +231,9 @@
         if (mForegroundPhase == ForegroundPhase.APPEARING ||
                 mForegroundPhase == ForegroundPhase.IDLE) {
             mForegroundPhase = ForegroundPhase.DISAPPEARING;
+
+            createChildLayer();
+
             animateScale(true, onAnimationEndRunnable);
             return true;
         } else {
@@ -219,6 +241,12 @@
         }
     }
 
+    private void createChildLayer() {
+        mChild.invalidate();
+        mChild.setLayerType(LAYER_TYPE_HARDWARE, null);
+        mChild.buildLayer();
+    }
+
     /** Creates the open/close animation */
     private void animateScale(
             final boolean isExitAnimation,
@@ -231,7 +259,7 @@
                 : android.R.interpolator.decelerate_quint;
         final float scaleTarget = isExitAnimation ? 0.5f : 1.0f;
 
-        mChild.animate().withLayer()
+        mChild.animate()
                 .setDuration(mAnimationDuration)
                 .setInterpolator(AnimationUtils.loadInterpolator(getContext(), scaleInterpolator))
                 .scaleX(scaleTarget)
@@ -240,6 +268,7 @@
                 .setListener(new AnimatorListenerAdapter() {
                     @Override
                     public void onAnimationEnd(Animator animation) {
+                        mChild.setLayerType(LAYER_TYPE_NONE, null);
                         if (isExitAnimation) {
                             if (mForegroundPhase == ForegroundPhase.DISAPPEARING) {
                                 mForegroundPhase = ForegroundPhase.AFTER;
diff --git a/src/com/android/contacts/quickcontact/QuickContactActivity.java b/src/com/android/contacts/quickcontact/QuickContactActivity.java
index 3c91716..cbddf90 100644
--- a/src/com/android/contacts/quickcontact/QuickContactActivity.java
+++ b/src/com/android/contacts/quickcontact/QuickContactActivity.java
@@ -220,7 +220,12 @@
         mContactLoader = (ContactLoader) getLoaderManager().initLoader(
                 LOADER_ID, null, mLoaderCallbacks);
 
-        mFloatingLayout.fadeInBackground();
+        SchedulingUtils.doAfterLayout(mFloatingLayout, new Runnable() {
+            @Override
+            public void run() {
+                mFloatingLayout.fadeInBackground();
+            }
+        });
     }
 
     private void handleOutsideTouch() {
diff --git a/src/com/android/contacts/test/NeededForReflection.java b/src/com/android/contacts/test/NeededForReflection.java
new file mode 100644
index 0000000..feacca5
--- /dev/null
+++ b/src/com/android/contacts/test/NeededForReflection.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.contacts.test;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Denotes that the class, constructor, method or field is used by tests and therefore cannot be
+ * removed by tools like ProGuard.
+ */
+@Retention(RetentionPolicy.CLASS)
+@Target({ElementType.TYPE, ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.FIELD})
+public @interface NeededForReflection{}