Merge "Add white touch feedback drawable to Dialer" into lmp-dev
diff --git a/res/layout-land/quickcontact_activity.xml b/res/layout-land/quickcontact_activity.xml
index 9a07698..b22b5ef 100644
--- a/res/layout-land/quickcontact_activity.xml
+++ b/res/layout-land/quickcontact_activity.xml
@@ -23,19 +23,39 @@
     android:focusableInTouchMode="true"
     android:descendantFocusability="afterDescendants" >
 
-    <View
-        android:layout_width="match_parent"
-        android:layout_height="@dimen/quickcontact_starting_empty_height"
-        android:contentDescription="@string/quickcontact_transparent_view_description"
-        android:id="@+id/transparent_view" />
-
     <LinearLayout
         android:layout_width="match_parent"
-        android:layout_height="match_parent">
+        android:layout_height="match_parent"
+        android:orientation="vertical">
 
-        <include layout="@layout/quickcontact_header" />
+        <View
+            android:layout_width="match_parent"
+            android:layout_height="@dimen/quickcontact_starting_empty_height"
+            android:contentDescription="@string/quickcontact_transparent_view_description"
+            android:id="@+id/transparent_view" />
 
-        <include layout="@layout/quickcontact_content" />
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:orientation="horizontal">
+
+            <!-- Needs a non null background for elevation to work on this View. This will
+                 *not* cause an additional draw since the background is transparent. -->
+            <FrameLayout
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
+                android:background="#00000000"
+                android:id="@+id/toolbar_parent">
+
+                <include layout="@layout/quickcontact_header" />
+
+                <include layout="@layout/quickcontact_title" />
+
+            </FrameLayout>
+
+            <include layout="@layout/quickcontact_content" />
+
+        </LinearLayout>
 
     </LinearLayout>
 
diff --git a/res/layout/quickcontact_activity.xml b/res/layout/quickcontact_activity.xml
index 008062b..577a451 100644
--- a/res/layout/quickcontact_activity.xml
+++ b/res/layout/quickcontact_activity.xml
@@ -24,14 +24,34 @@
     android:focusableInTouchMode="true"
     android:descendantFocusability="afterDescendants" >
 
-    <View
+    <LinearLayout
         android:layout_width="match_parent"
-        android:layout_height="@dimen/quickcontact_starting_empty_height"
-        android:contentDescription="@string/quickcontact_transparent_view_description"
-        android:id="@+id/transparent_view" />
+        android:layout_height="match_parent"
+        android:orientation="vertical">
 
-    <include layout="@layout/quickcontact_header" />
+        <View
+            android:layout_width="match_parent"
+            android:layout_height="@dimen/quickcontact_starting_empty_height"
+            android:contentDescription="@string/quickcontact_transparent_view_description"
+            android:id="@+id/transparent_view" />
 
-    <include layout="@layout/quickcontact_content" />
+        <!-- Needs a non null background for elevation to work on this View. This will *not*
+             cause an additional draw since the background is transparent. -->
+        <FrameLayout
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:background="#00000000"
+            android:id="@+id/toolbar_parent">
+            <include layout="@layout/quickcontact_header" />
+        </FrameLayout>
+
+        <include layout="@layout/quickcontact_content" />
+
+    </LinearLayout>
+
+    <!-- This title's maximum height must be less than the minimum size of its
+         parent ViewGroup because of an oddity in the way View#setScaleY() works. As a result,
+         this title can not be inside @style/quickcontact_header. -->
+    <include layout="@layout/quickcontact_title" />
 
 </com.android.contacts.widget.MultiShrinkScroller>
\ No newline at end of file
diff --git a/res/layout/quickcontact_header.xml b/res/layout/quickcontact_header.xml
index 1f73215..bb89dda 100644
--- a/res/layout/quickcontact_header.xml
+++ b/res/layout/quickcontact_header.xml
@@ -14,15 +14,7 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-
-<!-- Needs a non null background in for elevation to work on this View. This will *not* cause an
-     additional draw since the background is transparent. -->
-<FrameLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:background="#00000000"
-    android:id="@+id/toolbar_parent">
+<merge xmlns:android="http://schemas.android.com/apk/res/android">
 
     <com.android.contacts.widget.QuickContactImageView
         android:id="@+id/photo"
@@ -61,17 +53,4 @@
         android:background="#00000000"
         android:id="@+id/toolbar"/>
 
-    <TextView
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:textColor="@color/actionbar_text_color"
-        android:maxLines="@integer/quickcontact_title_lines"
-        android:ellipsize="end"
-        android:layout_gravity="bottom|start"
-        android:textSize="@dimen/quickcontact_maximum_title_size"
-        android:layout_marginStart="@dimen/quickcontact_title_initial_margin"
-        android:layout_marginEnd="@dimen/quickcontact_title_initial_margin"
-        android:layout_marginBottom="@dimen/quickcontact_title_initial_margin"
-        android:id="@+id/large_title"/>
-
-</FrameLayout>
+</merge>
diff --git a/res/layout/quickcontact_title.xml b/res/layout/quickcontact_title.xml
new file mode 100644
index 0000000..9b23a86
--- /dev/null
+++ b/res/layout/quickcontact_title.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2014 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.
+-->
+<TextView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:layout_marginStart="@dimen/quickcontact_title_initial_margin"
+    android:layout_marginEnd="@dimen/quickcontact_title_initial_margin"
+    android:layout_marginBottom="@dimen/quickcontact_title_initial_margin"
+    android:layout_gravity="top|start"
+    android:textColor="@color/actionbar_text_color"
+    android:maxLines="@integer/quickcontact_title_lines"
+    android:textSize="@dimen/quickcontact_maximum_title_size"
+    android:ellipsize="end"
+    android:id="@+id/large_title"/>
\ No newline at end of file
diff --git a/res/values-sw720dp/dimens.xml b/res/values-sw720dp/dimens.xml
index 495526d..827c71b 100644
--- a/res/values-sw720dp/dimens.xml
+++ b/res/values-sw720dp/dimens.xml
@@ -21,4 +21,9 @@
     <dimen name="quick_contact_photo_container_height">360dip</dimen>
     <dimen name="contact_picker_contact_list_min_height">650dip</dimen>
     <dimen name="list_visible_scrollbar_padding">48dip</dimen>
+
+    <!-- When QC is uncollapsed, the title has this much margin on its left, right and bottom -->
+    <dimen name="quickcontact_title_initial_margin">32dp</dimen>
+    <!-- Initial size of QuickContact's title size -->
+    <dimen name="quickcontact_maximum_title_size">64dp</dimen>
 </resources>
diff --git a/src/com/android/contacts/widget/MultiShrinkScroller.java b/src/com/android/contacts/widget/MultiShrinkScroller.java
index 370c3ae..632bb28 100644
--- a/src/com/android/contacts/widget/MultiShrinkScroller.java
+++ b/src/com/android/contacts/widget/MultiShrinkScroller.java
@@ -24,6 +24,7 @@
 import android.util.TypedValue;
 import android.view.Display;
 import android.view.DisplayInfo;
+import android.view.Gravity;
 import android.view.MotionEvent;
 import android.view.VelocityTracker;
 import android.view.View;
@@ -31,6 +32,7 @@
 import android.view.ViewConfiguration;
 import android.view.animation.AnimationUtils;
 import android.view.animation.Interpolator;
+import android.view.animation.PathInterpolator;
 import android.widget.EdgeEffect;
 import android.widget.FrameLayout;
 import android.widget.LinearLayout;
@@ -51,7 +53,7 @@
  * features are missing. For example: handling of KEYCODES, OverScroll bounce and saving
  * scroll state in savedInstanceState bundles.
  */
-public class MultiShrinkScroller extends LinearLayout {
+public class MultiShrinkScroller extends FrameLayout {
 
     /**
      * 1000 pixels per millisecond. Ie, 1 pixel per second.
@@ -147,6 +149,9 @@
             0, 0, 0, 1, 0
     };
 
+    private final PathInterpolator mTextSizePathInterpolator
+            = new PathInterpolator(0.16f, 0.4f, 0.2f, 1);
+
     private final int[] mGradientColors = new int[] {0,0xAA000000};
     private GradientDrawable mTitleGradientDrawable = new GradientDrawable(
             GradientDrawable.Orientation.TOP_BOTTOM, mGradientColors);
@@ -287,18 +292,28 @@
                     mMaximumHeaderHeight = getHeight();
                     mMinimumHeaderHeight = mMaximumHeaderHeight;
                     mIntermediateHeaderHeight = mMaximumHeaderHeight;
+
+                    // Permanently set photo width and height.
                     final TypedValue photoRatio = new TypedValue();
                     getResources().getValue(R.vals.quickcontact_photo_ratio, photoRatio,
                             /* resolveRefs = */ true);
-                    final LayoutParams layoutParams
-                            = (LayoutParams) mPhotoViewContainer.getLayoutParams();
-                    layoutParams.height = mMaximumHeaderHeight;
-                    layoutParams.width = (int) (mMaximumHeaderHeight * photoRatio.getFloat());
-                    mPhotoViewContainer.setLayoutParams(layoutParams);
+                    final ViewGroup.LayoutParams photoLayoutParams
+                            = mPhotoViewContainer.getLayoutParams();
+                    photoLayoutParams.height = mMaximumHeaderHeight;
+                    photoLayoutParams.width = (int) (mMaximumHeaderHeight * photoRatio.getFloat());
+                    mPhotoViewContainer.setLayoutParams(photoLayoutParams);
+
+                    // Permanently set title width and margin.
+                    final FrameLayout.LayoutParams largeTextLayoutParams
+                            = (FrameLayout.LayoutParams) mLargeTextView.getLayoutParams();
+                    largeTextLayoutParams.width = photoLayoutParams.width -
+                            largeTextLayoutParams.leftMargin - largeTextLayoutParams.rightMargin;
+                    largeTextLayoutParams.gravity = Gravity.BOTTOM | Gravity.START;
+                    mLargeTextView.setLayoutParams(largeTextLayoutParams);
                 }
 
                 calculateCollapsedLargeTitlePadding();
-                updateHeaderTextSize();
+                updateHeaderTextSizeAndMargin();
                 configureGradientViewHeights();
             }
         });
@@ -578,7 +593,7 @@
             scrollDown(delta);
         }
         updatePhotoTintAndDropShadow();
-        updateHeaderTextSize();
+        updateHeaderTextSizeAndMargin();
         final boolean isFullscreen = getScrollNeededToBeFullScreen() <= 0;
         mHasEverTouchedTheTop |= isFullscreen;
         if (mListener != null) {
@@ -596,13 +611,13 @@
      */
     @NeededForReflection
     public void setToolbarHeight(int delta) {
-        final LinearLayout.LayoutParams toolbarLayoutParams
-                = (LayoutParams) mToolbar.getLayoutParams();
+        final ViewGroup.LayoutParams toolbarLayoutParams
+                = mToolbar.getLayoutParams();
         toolbarLayoutParams.height = delta;
         mToolbar.setLayoutParams(toolbarLayoutParams);
 
         updatePhotoTintAndDropShadow();
-        updateHeaderTextSize();
+        updateHeaderTextSizeAndMargin();
     }
 
     @NeededForReflection
@@ -615,12 +630,12 @@
      */
     @NeededForReflection
     public void setHeaderHeight(int height) {
-        final LinearLayout.LayoutParams toolbarLayoutParams
-                = (LayoutParams) mToolbar.getLayoutParams();
+        final ViewGroup.LayoutParams toolbarLayoutParams
+                = mToolbar.getLayoutParams();
         toolbarLayoutParams.height = height;
         mToolbar.setLayoutParams(toolbarLayoutParams);
         updatePhotoTintAndDropShadow();
-        updateHeaderTextSize();
+        updateHeaderTextSizeAndMargin();
     }
 
     @NeededForReflection
@@ -639,10 +654,8 @@
      */
     @NeededForReflection
     public int getScroll() {
-        final LinearLayout.LayoutParams toolbarLayoutParams
-                = (LayoutParams) mToolbar.getLayoutParams();
         return mTransparentStartHeight - getTransparentViewHeight()
-                + getMaximumScrollableHeaderHeight() - toolbarLayoutParams.height
+                + getMaximumScrollableHeaderHeight() - getToolbarHeight()
                 + mScrollView.getScrollY();
     }
 
@@ -662,10 +675,8 @@
      * This value should never be used in conjunction with {@link #getScroll} values.
      */
     private int getScroll_ignoreOversizedHeaderForSnapping() {
-        final LinearLayout.LayoutParams toolbarLayoutParams
-                = (LayoutParams) mToolbar.getLayoutParams();
         return mTransparentStartHeight - getTransparentViewHeight()
-                + Math.max(getMaximumScrollableHeaderHeight() - toolbarLayoutParams.height, 0)
+                + Math.max(getMaximumScrollableHeaderHeight() - getToolbarHeight(), 0)
                 + mScrollView.getScrollY();
     }
 
@@ -787,8 +798,8 @@
             setTransparentViewHeight(Math.max(0, getTransparentViewHeight()));
             delta -= originalValue - getTransparentViewHeight();
         }
-        final LinearLayout.LayoutParams toolbarLayoutParams
-                = (LayoutParams) mToolbar.getLayoutParams();
+        final ViewGroup.LayoutParams toolbarLayoutParams
+                = mToolbar.getLayoutParams();
         if (toolbarLayoutParams.height > getFullyCompressedHeaderHeight()) {
             final int originalValue = toolbarLayoutParams.height;
             toolbarLayoutParams.height -= delta;
@@ -823,8 +834,7 @@
             mScrollView.scrollBy(0, delta);
             delta -= mScrollView.getScrollY() - originalValue;
         }
-        final LinearLayout.LayoutParams toolbarLayoutParams
-                = (LayoutParams) mToolbar.getLayoutParams();
+        final ViewGroup.LayoutParams toolbarLayoutParams = mToolbar.getLayoutParams();
         if (toolbarLayoutParams.height < getMaximumScrollableHeaderHeight()) {
             final int originalValue = toolbarLayoutParams.height;
             toolbarLayoutParams.height -= delta;
@@ -852,9 +862,9 @@
     /**
      * Set the header size and padding, based on the current scroll position.
      */
-    private void updateHeaderTextSize() {
+    private void updateHeaderTextSizeAndMargin() {
         if (mIsTwoPanel) {
-            // The text size stays constant on two panel layouts.
+            // The text size stays at a constant size & location in two panel layouts.
             return;
         }
 
@@ -866,25 +876,25 @@
         }
         mLargeTextView.setPivotY(mLargeTextView.getHeight() / 2);
 
-        final int START_TEXT_SCALING_THRESHOLD_COEFFICIENT = 2;
-        final int threshold = START_TEXT_SCALING_THRESHOLD_COEFFICIENT * mMinimumHeaderHeight;
         final int toolbarHeight = mToolbar.getLayoutParams().height;
-        if (toolbarHeight >= threshold) {
-            // Keep the text at maximum size since the header is smaller than threshold.
+        if (toolbarHeight >= mMaximumHeaderHeight) {
+            // Everything is full size when the header is fully expanded.
             mLargeTextView.setScaleX(1);
             mLargeTextView.setScaleY(1);
-            setInterpolatedTitleMargin(1);
+            setInterpolatedTitleMargins(1);
             return;
         }
-        final float ratio = (toolbarHeight  - mMinimumHeaderHeight)
-                / (float)(threshold - mMinimumHeaderHeight);
+
+        float ratio = (toolbarHeight  - mMinimumHeaderHeight)
+                / (float)(mMaximumHeaderHeight - mMinimumHeaderHeight);
         final float minimumSize = mInvisiblePlaceholderTextView.getHeight();
-        final float scale = (minimumSize + (mMaximumHeaderTextSize - minimumSize) * ratio)
+        final float bezierOutput = mTextSizePathInterpolator.getInterpolation(ratio);
+        float scale = (minimumSize + (mMaximumHeaderTextSize - minimumSize) * bezierOutput)
                 / mMaximumHeaderTextSize;
 
         mLargeTextView.setScaleX(scale);
         mLargeTextView.setScaleY(scale);
-        setInterpolatedTitleMargin(ratio);
+        setInterpolatedTitleMargins(bezierOutput);
     }
 
     /**
@@ -917,14 +927,21 @@
      * Interpolate the title's margin size. When {@param x}=1, use the maximum title margins.
      * When {@param x}=0, use the margin values taken from {@link #mInvisiblePlaceholderTextView}.
      */
-    private void setInterpolatedTitleMargin(float x) {
-        final FrameLayout.LayoutParams layoutParams
+    private void setInterpolatedTitleMargins(float x) {
+        final FrameLayout.LayoutParams titleLayoutParams
                 = (FrameLayout.LayoutParams) mLargeTextView.getLayoutParams();
-        layoutParams.bottomMargin = (int) (mCollapsedTitleBottomMargin * (1 - x)
-                + mMaximumTitleMargin * x) ;
-        layoutParams.setMarginStart((int) (mCollapsedTitleStartMargin * (1 - x)
+        final LinearLayout.LayoutParams toolbarLayoutParams
+                = (LinearLayout.LayoutParams) mToolbar.getLayoutParams();
+        titleLayoutParams.setMarginStart((int) (mCollapsedTitleStartMargin * (1 - x)
                 + mMaximumTitleMargin * x));
-        mLargeTextView.setLayoutParams(layoutParams);
+        // How offset the title should be from the bottom of the toolbar
+        final int pretendBottomMargin =  (int) (mCollapsedTitleBottomMargin * (1 - x)
+                + mMaximumTitleMargin * x) ;
+        // Calculate how offset the title should be from the top of the screen.
+        titleLayoutParams.topMargin = getTransparentViewHeight()
+                + toolbarLayoutParams.height - pretendBottomMargin
+                - mLargeTextView.getHeight();
+        mLargeTextView.setLayoutParams(titleLayoutParams);
     }
 
     private void updatePhotoTintAndDropShadow() {
@@ -943,7 +960,7 @@
 
         // We need to use toolbarLayoutParams to determine the height, since the layout
         // params can be updated before the height change is reflected inside the View#getHeight().
-        final int toolbarHeight = mToolbar.getLayoutParams().height;
+        final int toolbarHeight = getToolbarHeight();
 
         if (toolbarHeight <= mMinimumHeaderHeight && !mIsTwoPanel) {
             mPhotoViewContainer.setElevation(mToolbarElevation);
@@ -1139,7 +1156,7 @@
 
         final int newEmptyScrollViewSpace = -getOverflowingChildViewSize() + heightDelta;
         if (newEmptyScrollViewSpace > 0 && !mIsTwoPanel) {
-            final int newDesiredToolbarHeight = Math.min(mToolbar.getLayoutParams().height
+            final int newDesiredToolbarHeight = Math.min(getToolbarHeight()
                     + newEmptyScrollViewSpace, getMaximumScrollableHeaderHeight());
             ObjectAnimator.ofInt(this, "toolbarHeight", newDesiredToolbarHeight).setDuration(
                     ExpandingEntryCardView.DURATION_COLLAPSE_ANIMATION_CHANGE_BOUNDS).start();