Use predraw height for expand animation

Since TextViews can wrap multiple lines, their measurements
can change after layout() is called on them. Therefore,
it isn't sufficent to perform a manual measurement call on
mEntriesViewGroup. We need a predraw listener.

Bug: 15021154
Change-Id: I01daa89cb25cd381425c3994eda67f8769a40c13
diff --git a/src/com/android/contacts/quickcontact/ExpandingEntryCardView.java b/src/com/android/contacts/quickcontact/ExpandingEntryCardView.java
index dc78d5b..0309030 100644
--- a/src/com/android/contacts/quickcontact/ExpandingEntryCardView.java
+++ b/src/com/android/contacts/quickcontact/ExpandingEntryCardView.java
@@ -36,6 +36,8 @@
 import android.view.View;
 import android.view.View.OnClickListener;
 import android.view.ViewGroup;
+import android.view.ViewTreeObserver;
+import android.view.ViewTreeObserver.OnPreDrawListener;
 import android.view.animation.AccelerateDecelerateInterpolator;
 import android.widget.FrameLayout;
 import android.widget.ImageView;
@@ -282,8 +284,7 @@
 
     private List<View> createEntryViews(LayoutInflater layoutInflater, List<Entry> entries) {
         ArrayList<View> views = new ArrayList<View>(entries.size());
-        for (int i = 0; i < entries.size(); ++i) {
-            Entry entry = entries.get(i);
+        for (Entry entry : entries) {
             views.add(createEntryView(layoutInflater, entry));
         }
         return views;
@@ -362,33 +363,38 @@
         insertEntriesIntoViewGroup();
         updateExpandCollapseButton(getCollapseButtonText());
 
-        createExpandAnimator(startingHeight, measureContentAreaHeight()).start();
+        // When expanding, all the TextViews haven't been laid out yet. Therefore,
+        // calling measure() would return an incorrect result. Therefore, we need a pre draw
+        // listener.
+        final ViewTreeObserver observer = mEntriesViewGroup.getViewTreeObserver();
+        observer.addOnPreDrawListener(new OnPreDrawListener() {
+            @Override
+            public boolean onPreDraw() {
+                if (observer.isAlive()) {
+                    mEntriesViewGroup.getViewTreeObserver().removeOnPreDrawListener(this);
+                }
+                createExpandAnimator(startingHeight, mEntriesViewGroup.getHeight()).start();
+                // Do not draw the final frame of the animation immediately.
+                return false;
+            }
+        });
     }
 
     private void collapse() {
         int startingHeight = mEntriesViewGroup.getHeight();
-
-        // Figure out the height the view will be after the animation is finished.
-        mIsExpanded = false;
-        insertEntriesIntoViewGroup();
-        int finishHeight = measureContentAreaHeight();
-
-        // During the animation, mEntriesViewGroup should contain the same views as it did before
-        // the animation. Otherwise, the animation will look very silly.
-        mIsExpanded = true;
-        insertEntriesIntoViewGroup();
+        int finishHeight = measureCollapsedViewGroupHeight();
 
         mIsExpanded = false;
         updateExpandCollapseButton(getExpandButtonText());
         createExpandAnimator(startingHeight, finishHeight).start();
     }
 
-    private int measureContentAreaHeight() {
-        // Measure the LinearLayout, assuming no constraints from the parent.
-        final int widthSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
-        final int heightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
-        mEntriesViewGroup.measure(widthSpec, heightSpec);
-        return mEntriesViewGroup.getMeasuredHeight();
+    private int measureCollapsedViewGroupHeight() {
+        if (mCollapsedEntriesCount == 0) {
+            return 0;
+        }
+        final View bottomCollapsedView = mEntryViews.get(mCollapsedEntriesCount - 1);
+        return bottomCollapsedView.getTop() + bottomCollapsedView.getHeight();
     }
 
     /**
@@ -399,7 +405,6 @@
      */
     private ValueAnimator createExpandAnimator(int start, int end) {
         ValueAnimator animator = ValueAnimator.ofInt(start, end);
-        animator.setInterpolator(new AccelerateDecelerateInterpolator());
         animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
             @Override
             public void onAnimationUpdate(ValueAnimator valueAnimator) {
@@ -413,6 +418,10 @@
             @Override
             public void onAnimationEnd(Animator animation) {
                 insertEntriesIntoViewGroup();
+                // Now that the animation is done, stop using a fixed height.
+                ViewGroup.LayoutParams layoutParams = mEntriesViewGroup.getLayoutParams();
+                layoutParams.height = ViewGroup.LayoutParams.MATCH_PARENT;
+                mEntriesViewGroup.setLayoutParams(layoutParams);
             }
         });
         return animator;
diff --git a/src/com/android/contacts/quickcontact/QuickContactActivity.java b/src/com/android/contacts/quickcontact/QuickContactActivity.java
index 63dc9fd..286026e 100644
--- a/src/com/android/contacts/quickcontact/QuickContactActivity.java
+++ b/src/com/android/contacts/quickcontact/QuickContactActivity.java
@@ -451,7 +451,7 @@
                 entries.addAll(actionsToEntries(mActions.get(mimeType)));
             }
         }
-        mCommunicationCard.initialize(entries, /* numInitialVisibleEntries = */ 1,
+        mCommunicationCard.initialize(entries, /* numInitialVisibleEntries = */ 2,
                 /* isExpanded = */ false, /* themeColor = */ 0);
 
         final boolean hasData = !mSortedActionMimeTypes.isEmpty();