Improve frame-rate of quick-contact opening animation.

Fix consists of putting the quick-contact into a hardware layer for
the duration of the animation.

Rename AnimationUtils to SchedulingUtils to avoid conflict with
framework class of the same name.

Bug: 6000249
Change-Id: Ie627ddb947582b7860f5bd0de30484c1d1d4f428
diff --git a/src/com/android/contacts/activities/PhotoSelectionActivity.java b/src/com/android/contacts/activities/PhotoSelectionActivity.java
index 1ac107b..4a6b187 100644
--- a/src/com/android/contacts/activities/PhotoSelectionActivity.java
+++ b/src/com/android/contacts/activities/PhotoSelectionActivity.java
@@ -21,7 +21,7 @@
 import com.android.contacts.detail.PhotoSelectionHandler;
 import com.android.contacts.editor.PhotoActionPopup;
 import com.android.contacts.model.EntityDeltaList;
-import com.android.contacts.util.AnimationUtils;
+import com.android.contacts.util.SchedulingUtils;
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
@@ -37,7 +37,7 @@
 import android.os.Parcelable;
 import android.view.View;
 import android.view.ViewGroup.MarginLayoutParams;
-import android.view.ViewTreeObserver.OnGlobalLayoutListener;
+
 import android.widget.FrameLayout.LayoutParams;
 import android.widget.ImageView;
 
@@ -176,7 +176,7 @@
         });
 
         // Wait until the layout pass to show the photo, so that the source bounds will match up.
-        AnimationUtils.doAfterLayout(mBackdrop, new Runnable() {
+        SchedulingUtils.doAfterLayout(mBackdrop, new Runnable() {
             @Override
             public void run() {
                 displayPhoto();
@@ -433,7 +433,7 @@
         } else {
             // Setting the photo in displayPhoto() resulted in a relayout
             // request... to avoid jank, wait until this layout has happened.
-            AnimationUtils.doAfterLayout(mBackdrop, new Runnable() {
+            SchedulingUtils.doAfterLayout(mBackdrop, new Runnable() {
                 @Override
                 public void run() {
                     animatePhotoOpen();
@@ -450,8 +450,10 @@
         }
 
         private final class PhotoListener extends PhotoActionListener {
-            private final Context mContext;
+            @SuppressWarnings("hiding")
             private final boolean mIsProfile;
+            private final Context mContext;
+
             private PhotoListener(Context context, boolean isProfile) {
                 mContext = context;
                 mIsProfile = isProfile;
diff --git a/src/com/android/contacts/editor/EditorAnimator.java b/src/com/android/contacts/editor/EditorAnimator.java
index 879b162..33ee5b8 100644
--- a/src/com/android/contacts/editor/EditorAnimator.java
+++ b/src/com/android/contacts/editor/EditorAnimator.java
@@ -16,7 +16,7 @@
 
 package com.android.contacts.editor;
 
-import com.android.contacts.util.AnimationUtils;
+import com.android.contacts.util.SchedulingUtils;
 
 import com.google.common.collect.Lists;
 
@@ -28,7 +28,6 @@
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.ViewParent;
-import android.view.ViewTreeObserver.OnGlobalLayoutListener;
 import android.widget.LinearLayout;
 
 import java.util.List;
@@ -89,7 +88,7 @@
         organizationSectionViewContainer.setVisibility(View.VISIBLE);
         organizationSectionViewContainer.setAlpha(0.0f);
         organizationSectionViewContainer.requestFocus();
-        AnimationUtils.doAfterLayout(addOrganizationButton, new Runnable() {
+        SchedulingUtils.doAfterLayout(addOrganizationButton, new Runnable() {
             @Override
             public void run() {
                 // How many pixels extra do we need?
@@ -126,7 +125,7 @@
         // Make the new controls visible and do one layout pass (so that we can measure)
         view.setVisibility(View.VISIBLE);
         view.setAlpha(0.0f);
-        AnimationUtils.doAfterLayout(view, new Runnable() {
+        SchedulingUtils.doAfterLayout(view, new Runnable() {
             @Override
             public void run() {
                 // How many pixels extra do we need?
diff --git a/src/com/android/contacts/quickcontact/FloatingChildLayout.java b/src/com/android/contacts/quickcontact/FloatingChildLayout.java
index f1a0fe1..75141ae 100644
--- a/src/com/android/contacts/quickcontact/FloatingChildLayout.java
+++ b/src/com/android/contacts/quickcontact/FloatingChildLayout.java
@@ -19,7 +19,7 @@
 import com.android.contacts.R;
 
 import android.animation.Animator;
-import android.animation.Animator.AnimatorListener;
+import android.animation.AnimatorListenerAdapter;
 import android.content.Context;
 import android.content.res.Resources;
 import android.graphics.Rect;
@@ -153,33 +153,24 @@
     private void animateScale(boolean isExitAnimation, final Runnable onAnimationEndRunnable) {
         mChild.setPivotX(mTargetScreen.centerX() - mChild.getLeft());
         mChild.setPivotY(mTargetScreen.centerY() - mChild.getTop());
-        ViewPropertyAnimator animator = mChild.animate();
-        animator.setDuration(mAnimationDuration);
-        final int scaleInterpolator = isExitAnimation ? android.R.interpolator.accelerate_quint
+
+        final int scaleInterpolator = isExitAnimation
+                ? android.R.interpolator.accelerate_quint
                 : android.R.interpolator.decelerate_quint;
-        animator.setInterpolator(AnimationUtils.loadInterpolator(getContext(), scaleInterpolator));
         final float scaleTarget = isExitAnimation ? 0.5f : 1.0f;
-        animator.scaleX(scaleTarget);
-        animator.scaleY(scaleTarget);
-        animator.alpha(isExitAnimation ? 0.0f : 1.0f);
 
-        if (onAnimationEndRunnable != null) {
-            animator.setListener(new AnimatorListener() {
-                @Override
-                public void onAnimationStart(Animator animation) {}
-
-                @Override
-                public void onAnimationRepeat(Animator animation) {}
-
-                @Override
-                public void onAnimationCancel(Animator animation) {}
-
-                @Override
-                public void onAnimationEnd(Animator animation) {
-                    onAnimationEndRunnable.run();
-                }
-            });
-        }
+        ViewPropertyAnimator animator = mChild.animate().withLayer()
+                .setDuration(mAnimationDuration)
+                .setInterpolator(AnimationUtils.loadInterpolator(getContext(), scaleInterpolator))
+                .scaleX(scaleTarget)
+                .scaleY(scaleTarget)
+                .alpha(isExitAnimation ? 0.0f : 1.0f)
+                .setListener(new AnimatorListenerAdapter() {
+                    @Override
+                    public void onAnimationEnd(Animator animation) {
+                        if (onAnimationEndRunnable != null) onAnimationEndRunnable.run();
+                    }
+                });
     }
 
     private View.OnTouchListener mOutsideTouchListener;
diff --git a/src/com/android/contacts/quickcontact/QuickContactActivity.java b/src/com/android/contacts/quickcontact/QuickContactActivity.java
index 04afb89..92e68d4 100644
--- a/src/com/android/contacts/quickcontact/QuickContactActivity.java
+++ b/src/com/android/contacts/quickcontact/QuickContactActivity.java
@@ -24,6 +24,7 @@
 import com.android.contacts.model.DataKind;
 import com.android.contacts.util.DataStatus;
 import com.android.contacts.util.ImageViewDrawableSetter;
+import com.android.contacts.util.SchedulingUtils;
 import com.google.common.base.Preconditions;
 import com.google.common.collect.Lists;
 
@@ -479,7 +480,7 @@
 
             // Data bound and ready, pull curtain to show. Put this on the Handler to ensure
             // that the layout passes are completed
-            new Handler().post(new Runnable() {
+            SchedulingUtils.doAfterLayout(mFloatingLayout, new Runnable() {
                 @Override
                 public void run() {
                     mFloatingLayout.showChild(new Runnable() {
diff --git a/src/com/android/contacts/util/AnimationUtils.java b/src/com/android/contacts/util/SchedulingUtils.java
similarity index 91%
rename from src/com/android/contacts/util/AnimationUtils.java
rename to src/com/android/contacts/util/SchedulingUtils.java
index 31f0a0d..71fad05 100644
--- a/src/com/android/contacts/util/AnimationUtils.java
+++ b/src/com/android/contacts/util/SchedulingUtils.java
@@ -19,8 +19,8 @@
 import android.view.View;
 import android.view.ViewTreeObserver.OnGlobalLayoutListener;
 
-/** Static methods that are useful for animations. */
-public class AnimationUtils {
+/** Static methods that are useful for scheduling actions to occur at a later time. */
+public class SchedulingUtils {
 
     /** Runs a piece of code after the next layout run */
     public static void doAfterLayout(final View view, final Runnable runnable) {