Merge "Import translations. DO NOT MERGE"
diff --git a/res/drawable-hdpi/ic_ab_search_holo_dark.png b/res/drawable-hdpi/ic_ab_search_holo_dark.png
deleted file mode 100644
index 6dff03e..0000000
--- a/res/drawable-hdpi/ic_ab_search_holo_dark.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/ic_create_24dp.png b/res/drawable-hdpi/ic_create_24dp.png
index ecdc4b9..540ab4d 100644
--- a/res/drawable-hdpi/ic_create_24dp.png
+++ b/res/drawable-hdpi/ic_create_24dp.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_star_24dp.png b/res/drawable-hdpi/ic_star_24dp.png
index d053adb..b3d2f44 100644
--- a/res/drawable-hdpi/ic_star_24dp.png
+++ b/res/drawable-hdpi/ic_star_24dp.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_star_outline_24dp.png b/res/drawable-hdpi/ic_star_outline_24dp.png
index 809f1ee..4d4b7c1 100644
--- a/res/drawable-hdpi/ic_star_outline_24dp.png
+++ b/res/drawable-hdpi/ic_star_outline_24dp.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_ab_search_holo_dark.png b/res/drawable-mdpi/ic_ab_search_holo_dark.png
deleted file mode 100644
index 5a10e93..0000000
--- a/res/drawable-mdpi/ic_ab_search_holo_dark.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/ic_create_24dp.png b/res/drawable-mdpi/ic_create_24dp.png
index 97a46ee..8a2df39 100644
--- a/res/drawable-mdpi/ic_create_24dp.png
+++ b/res/drawable-mdpi/ic_create_24dp.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_star_24dp.png b/res/drawable-mdpi/ic_star_24dp.png
index f68b428..b8f32f8 100644
--- a/res/drawable-mdpi/ic_star_24dp.png
+++ b/res/drawable-mdpi/ic_star_24dp.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_star_outline_24dp.png b/res/drawable-mdpi/ic_star_outline_24dp.png
index 743aaae..22b4fb8 100644
--- a/res/drawable-mdpi/ic_star_outline_24dp.png
+++ b/res/drawable-mdpi/ic_star_outline_24dp.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_ab_search_holo_dark.png b/res/drawable-xhdpi/ic_ab_search_holo_dark.png
deleted file mode 100644
index b2d23c9..0000000
--- a/res/drawable-xhdpi/ic_ab_search_holo_dark.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/ic_create_24dp.png b/res/drawable-xhdpi/ic_create_24dp.png
index 74b2555..48e75be 100644
--- a/res/drawable-xhdpi/ic_create_24dp.png
+++ b/res/drawable-xhdpi/ic_create_24dp.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_star_24dp.png b/res/drawable-xhdpi/ic_star_24dp.png
index 49faab8..e1ae246 100644
--- a/res/drawable-xhdpi/ic_star_24dp.png
+++ b/res/drawable-xhdpi/ic_star_24dp.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_star_outline_24dp.png b/res/drawable-xhdpi/ic_star_outline_24dp.png
index 0ce8d31..f7dacfd 100644
--- a/res/drawable-xhdpi/ic_star_outline_24dp.png
+++ b/res/drawable-xhdpi/ic_star_outline_24dp.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_ab_search_holo_dark.png b/res/drawable-xxhdpi/ic_ab_search_holo_dark.png
deleted file mode 100644
index d56194d..0000000
--- a/res/drawable-xxhdpi/ic_ab_search_holo_dark.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_create_24dp.png b/res/drawable-xxhdpi/ic_create_24dp.png
index 74138ca..24142c7 100644
--- a/res/drawable-xxhdpi/ic_create_24dp.png
+++ b/res/drawable-xxhdpi/ic_create_24dp.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_star_24dp.png b/res/drawable-xxhdpi/ic_star_24dp.png
index 0aa8a26..eeb659e 100644
--- a/res/drawable-xxhdpi/ic_star_24dp.png
+++ b/res/drawable-xxhdpi/ic_star_24dp.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_star_outline_24dp.png b/res/drawable-xxhdpi/ic_star_outline_24dp.png
index 1f9a7a2..d1728ff 100644
--- a/res/drawable-xxhdpi/ic_star_outline_24dp.png
+++ b/res/drawable-xxhdpi/ic_star_outline_24dp.png
Binary files differ
diff --git a/res/drawable-xxxhdpi/ic_create_24dp.png b/res/drawable-xxxhdpi/ic_create_24dp.png
new file mode 100644
index 0000000..d3ff0ec
--- /dev/null
+++ b/res/drawable-xxxhdpi/ic_create_24dp.png
Binary files differ
diff --git a/res/drawable-xxxhdpi/ic_star_24dp.png b/res/drawable-xxxhdpi/ic_star_24dp.png
index 7477c14..bd1cd8d 100644
--- a/res/drawable-xxxhdpi/ic_star_24dp.png
+++ b/res/drawable-xxxhdpi/ic_star_24dp.png
Binary files differ
diff --git a/res/drawable-xxxhdpi/ic_star_outline_24dp.png b/res/drawable-xxxhdpi/ic_star_outline_24dp.png
index 3ae24c7..cb90707 100644
--- a/res/drawable-xxxhdpi/ic_star_outline_24dp.png
+++ b/res/drawable-xxxhdpi/ic_star_outline_24dp.png
Binary files differ
diff --git a/res/drawable/ic_person_add_tinted_24dp.xml b/res/drawable/ic_person_add_tinted_24dp.xml
new file mode 100644
index 0000000..6d79663
--- /dev/null
+++ b/res/drawable/ic_person_add_tinted_24dp.xml
@@ -0,0 +1,20 @@
+<?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
+  -->
+<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
+    android:src="@drawable/ic_person_add_24dp"
+    android:autoMirrored="true"
+    android:tint="@color/actionbar_icon_color" />
\ No newline at end of file
diff --git a/res/layout/quickcontact_activity.xml b/res/layout/quickcontact_activity.xml
index a7c12dd..8f78811 100644
--- a/res/layout/quickcontact_activity.xml
+++ b/res/layout/quickcontact_activity.xml
@@ -26,7 +26,7 @@
 
     <FrameLayout
         android:layout_width="match_parent"
-        android:layout_height="@dimen/quickcontact_maximum_header_height"
+        android:layout_height="match_parent"
         android:layout_marginTop="@dimen/quickcontact_starting_empty_height"
         android:background="@color/card_margin_color"
         android:id="@+id/toolbar_parent">
diff --git a/res/menu-sw600dp/people_options.xml b/res/menu-sw600dp/people_options.xml
index b1659c7..931b456 100644
--- a/res/menu-sw600dp/people_options.xml
+++ b/res/menu-sw600dp/people_options.xml
@@ -16,7 +16,7 @@
 <menu xmlns:android="http://schemas.android.com/apk/res/android">
     <item
         android:id="@+id/menu_search"
-        android:icon="@drawable/ic_search_dk"
+        android:icon="@drawable/ic_ab_search"
         android:title="@string/menu_search"
         android:showAsAction="ifRoom" />
 
diff --git a/res/menu/people_options.xml b/res/menu/people_options.xml
index 6b0696d..4aae1a1 100644
--- a/res/menu/people_options.xml
+++ b/res/menu/people_options.xml
@@ -16,8 +16,7 @@
 <menu xmlns:android="http://schemas.android.com/apk/res/android">
     <item
         android:id="@+id/menu_search"
-        android:icon="@drawable/ic_search_dk"
-        android:title="@string/menu_search"
+        android:icon="@drawable/ic_ab_search"
         android:showAsAction="ifRoom" />
 
     <item
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index cb9f101..99bc345 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -18,15 +18,8 @@
 
     <!-- Initial height of transparent space above QuickContacts -->
     <dimen name="quickcontact_starting_empty_height">150dp</dimen>
-    <!-- Initial/maximum height of QuickContact's header/avatar-photo -->
-    <dimen name="quickcontact_maximum_header_height">200dp</dimen>
-    <!-- Minimum height of QuickContact's header/avatar-photo -->
-    <dimen name="quickcontact_minimum_header_height">64dp</dimen>
-    <!-- If you scroll the QuickContact by this amount over the top of viewport,
-         the MultiShrinkScroller will smoothScroll the QuickContact to the top of the
-         viewport. This is used to give a sense of elasticity surrounding
-         the top of the viewport. -->
-    <dimen name="quickcontact_elastic_scroll_over_top_region">50dp</dimen>
+    <!-- Initial height of QuickContact's header/avatar-photo -->
+    <dimen name="quickcontact_starting_header_height">200dp</dimen>
 
     <!-- Top padding of the entire contact editor  -->
     <dimen name="editor_padding_top">0dip</dimen>
diff --git a/src/com/android/contacts/quickcontact/QuickContactActivity.java b/src/com/android/contacts/quickcontact/QuickContactActivity.java
index dcdeb1c..a36c258 100644
--- a/src/com/android/contacts/quickcontact/QuickContactActivity.java
+++ b/src/com/android/contacts/quickcontact/QuickContactActivity.java
@@ -322,7 +322,9 @@
                 mScroller.setVisibility(View.VISIBLE);
                 mScroller.setScroll(mScroller.getScrollNeededToBeFullScreen());
             } else {
-                mScroller.setVisibility(View.GONE);
+                // mScroller needs to perform asynchronous measurements after initalize(), therefore
+                // we can't mark this as GONE.
+                mScroller.setVisibility(View.INVISIBLE);
             }
         }
 
@@ -1098,7 +1100,7 @@
             editMenuItem.setVisible(true);
             if (DirectoryContactUtil.isDirectoryContact(mContactData) || InvisibleContactUtil
                     .isInvisibleAndAddable(mContactData, this)) {
-                editMenuItem.setIcon(R.drawable.ic_person_add_24dp);
+                editMenuItem.setIcon(R.drawable.ic_person_add_tinted_24dp);
             } else if (isContactEditable()) {
                 editMenuItem.setIcon(R.drawable.ic_create_24dp);
             } else {
diff --git a/src/com/android/contacts/widget/MultiShrinkScroller.java b/src/com/android/contacts/widget/MultiShrinkScroller.java
index 01aeb4e..0315cc5 100644
--- a/src/com/android/contacts/widget/MultiShrinkScroller.java
+++ b/src/com/android/contacts/widget/MultiShrinkScroller.java
@@ -2,9 +2,13 @@
 
 import com.android.contacts.R;
 import com.android.contacts.test.NeededForReflection;
+import com.android.contacts.util.SchedulingUtils;
 
+import android.animation.Animator;
+import android.animation.Animator.AnimatorListener;
 import android.animation.ObjectAnimator;
 import android.content.Context;
+import android.content.res.TypedArray;
 import android.graphics.Canvas;
 import android.graphics.PorterDuff;
 import android.graphics.PorterDuffColorFilter;
@@ -54,16 +58,16 @@
     private View mPhotoViewContainer;
     private MultiShrinkScrollerListener mListener;
     private int mHeaderTintColor;
+    private int mMaximumHeaderHeight;
 
     private final Scroller mScroller;
     private final EdgeEffect mEdgeGlowBottom;
     private final int mTouchSlop;
     private final int mMaximumVelocity;
     private final int mMinimumVelocity;
-    private final int mMaximumHeaderHeight;
+    private final int mIntermediateHeaderHeight;
     private final int mMinimumHeaderHeight;
     private final int mTransparentStartHeight;
-    private final int mElasticScrollOverTopRegion;
     private final float mToolbarElevation;
     private final PorterDuffColorFilter mColorFilter
             = new PorterDuffColorFilter(0, PorterDuff.Mode.SRC_ATOP);
@@ -76,7 +80,26 @@
         void onExitFullscreen();
     }
 
-    // Interpolator from android.support.v4.view.ViewPager
+    private final AnimatorListener mHeaderExpandAnimationListener = new AnimatorListener() {
+        @Override
+        public void onAnimationStart(Animator animation) {}
+
+        @Override
+        public void onAnimationEnd(Animator animation) {
+            mPhotoView.setClickable(true);
+        }
+
+        @Override
+        public void onAnimationCancel(Animator animation) {}
+
+        @Override
+        public void onAnimationRepeat(Animator animation) {}
+    };
+
+    /**
+     * Interpolator from android.support.v4.view.ViewPager. Snappier and more elastic feeling
+     * than the default interpolator.
+     */
     private static final Interpolator sInterpolator = new Interpolator() {
 
         /**
@@ -110,18 +133,19 @@
         mTouchSlop = configuration.getScaledTouchSlop();
         mMinimumVelocity = configuration.getScaledMinimumFlingVelocity();
         mMaximumVelocity = configuration.getScaledMaximumFlingVelocity();
-        mMaximumHeaderHeight = (int) getResources().getDimension(
-                R.dimen.quickcontact_maximum_header_height);
-        mMinimumHeaderHeight = (int) getResources().getDimension(
-                R.dimen.quickcontact_minimum_header_height);
+        mIntermediateHeaderHeight = (int) getResources().getDimension(
+                R.dimen.quickcontact_starting_header_height);
         mTransparentStartHeight = (int) getResources().getDimension(
                 R.dimen.quickcontact_starting_empty_height);
-        mElasticScrollOverTopRegion = (int) getResources().getDimension(
-                R.dimen.quickcontact_elastic_scroll_over_top_region);
         mHeaderTintColor = mContext.getResources().getColor(
                 R.color.actionbar_background_color);
-        mToolbarElevation = (float) mContext.getResources().getDimension(
+        mToolbarElevation = mContext.getResources().getDimension(
                 R.dimen.quick_contact_toolbar_elevation);
+
+        final TypedArray attributeArray = context.obtainStyledAttributes(
+                new int[]{android.R.attr.actionBarSize});
+        mMinimumHeaderHeight = attributeArray.getDimensionPixelSize(0, 0);
+        attributeArray.recycle();
     }
 
     /**
@@ -131,9 +155,25 @@
         mScrollView = (ScrollView) findViewById(R.id.content_scroller);
         mScrollViewChild = findViewById(R.id.card_container);
         mToolbar = findViewById(R.id.toolbar_parent);
-        mPhotoView = (ImageView) findViewById(R.id.photo);
         mPhotoViewContainer = findViewById(R.id.toolbar_parent);
         mListener = listener;
+
+        mPhotoView = (ImageView) findViewById(R.id.photo);
+        setHeaderHeight(mIntermediateHeaderHeight);
+        mPhotoView.setOnClickListener(new OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                expandCollapseHeader();
+            }
+        });
+
+        SchedulingUtils.doOnPreDraw(this, /* drawNextFrame = */ true, new Runnable() {
+            @Override
+            public void run() {
+                // We never want the height of the photo view to exceed its width.
+                mMaximumHeaderHeight = mToolbar.getWidth();
+            }
+        });
     }
 
     @Override
@@ -233,6 +273,30 @@
         updatePhotoTintAndDropShadow();
     }
 
+    /**
+     * Expand to maximum size or starting size. Disable clicks on the photo until the animation is
+     * complete.
+     */
+    private void expandCollapseHeader() {
+        mPhotoView.setClickable(false);
+        if (getHeaderHeight() != mMaximumHeaderHeight) {
+            // Expand header
+            final ObjectAnimator animator = ObjectAnimator.ofInt(this, "headerHeight",
+                    mMaximumHeaderHeight);
+            animator.addListener(mHeaderExpandAnimationListener);
+            animator.start();
+            // Scroll nested scroll view to its top
+            if (mScrollView.getScrollY() != 0) {
+                ObjectAnimator.ofInt(mScrollView, "scrollY", -mScrollView.getScrollY()).start();
+            }
+        } else if (getHeaderHeight() != mMinimumHeaderHeight) {
+            final ObjectAnimator animator = ObjectAnimator.ofInt(this, "headerHeight",
+                    mIntermediateHeaderHeight);
+            animator.addListener(mHeaderExpandAnimationListener);
+            animator.start();
+        }
+    }
+
     private void startDrag() {
         mIsBeingDragged = true;
         mScroller.abortAnimation();
@@ -272,14 +336,12 @@
      * If needed, snap the subviews to the top of the Window.
      */
     private boolean snapToTop(int flingDelta) {
-        if (-getScroll() - flingDelta < 0
-                && -getScroll() - flingDelta > -mTransparentStartHeight
-                - mElasticScrollOverTopRegion) {
+        if (-getScroll_ignoreOversizedHeader() - flingDelta < 0
+                && -getScroll_ignoreOversizedHeader() - flingDelta > -mTransparentStartHeight) {
             // We finish scrolling above the empty starting height, and aren't projected
-            // to fling past the top of the Window by mElasticScrollOverTopRegion worth of
-            // pixels, so elastically snap the empty space shut.
+            // to fling past the top of the Window, so elastically snap the empty space shut.
             mScroller.forceFinished(true);
-            smoothScrollBy(-getScroll() + mTransparentStartHeight);
+            smoothScrollBy(-getScroll_ignoreOversizedHeader() + mTransparentStartHeight);
             return true;
         }
         return false;
@@ -289,7 +351,7 @@
      * If needed, scroll all the subviews off the bottom of the Window.
      */
     private void snapToBottom(int flingDelta) {
-        if (-getScroll() - flingDelta > 0) {
+        if (-getScroll_ignoreOversizedHeader() - flingDelta > 0) {
             mScroller.forceFinished(true);
             ObjectAnimator translateAnimation = ObjectAnimator.ofInt(this, "scroll",
                     getScroll() - getScrollUntilOffBottom());
@@ -319,6 +381,23 @@
         }
     }
 
+    /**
+     * Set the height of the toolbar and update its tint accordingly.
+     */
+    @NeededForReflection
+    public void setHeaderHeight(int height) {
+        final LinearLayout.LayoutParams toolbarLayoutParams
+                = (LayoutParams) mToolbar.getLayoutParams();
+        toolbarLayoutParams.height = height;
+        mToolbar.setLayoutParams(toolbarLayoutParams);
+        updatePhotoTintAndDropShadow();
+    }
+
+    @NeededForReflection
+    public int getHeaderHeight() {
+        return mToolbar.getLayoutParams().height;
+    }
+
     @NeededForReflection
     public void setScroll(int scroll) {
         scrollTo(0, scroll);
@@ -326,13 +405,27 @@
 
     /**
      * Returns the total amount scrolled inside the nested ScrollView + the amount of shrinking
-     * performed on the ToolBar.
+     * performed on the ToolBar. This is the value inspected by animators.
      */
+    @NeededForReflection
     public int getScroll() {
         final LinearLayout.LayoutParams toolbarLayoutParams
                 = (LayoutParams) mToolbar.getLayoutParams();
         return mTransparentStartHeight - toolbarLayoutParams.topMargin
-                + mMaximumHeaderHeight - toolbarLayoutParams.height + mScrollView.getScrollY();
+                + mIntermediateHeaderHeight - toolbarLayoutParams.height + mScrollView.getScrollY();
+    }
+
+    /**
+     * A variant of {@link #getScroll} that pretends the header is never larger than
+     * than mIntermediateHeaderHeight. This function is sometimes needed when making scrolling
+     * decisions that will not change the header size (ie, snapping to the bottom or top).
+     */
+    public int getScroll_ignoreOversizedHeader() {
+        final LinearLayout.LayoutParams toolbarLayoutParams
+                = (LayoutParams) mToolbar.getLayoutParams();
+        return mTransparentStartHeight - toolbarLayoutParams.topMargin
+                + Math.max(mIntermediateHeaderHeight - toolbarLayoutParams.height, 0)
+                + mScrollView.getScrollY();
     }
 
     /**
@@ -349,7 +442,7 @@
      * bottom.
      */
     public int getScrollUntilOffBottom() {
-        return getHeight() + getScroll() - mTransparentStartHeight;
+        return getHeight() + getScroll_ignoreOversizedHeader() - mTransparentStartHeight;
     }
 
     @Override
@@ -415,7 +508,7 @@
     private int getMaximumScrollUpwards() {
         return mTransparentStartHeight
                 // How much the Header view can compress
-                + mMaximumHeaderHeight - mMinimumHeaderHeight
+                + mIntermediateHeaderHeight - mMinimumHeaderHeight
                 // How much the ScrollView can scroll. 0, if child is smaller than ScrollView.
                 + Math.max(0, mScrollViewChild.getHeight() - getHeight() + mMinimumHeaderHeight);
     }
@@ -446,10 +539,11 @@
             mScrollView.scrollBy(0, delta);
             delta -= mScrollView.getScrollY() - originalValue;
         }
-        if (toolbarLayoutParams.height != mMaximumHeaderHeight) {
+        if (toolbarLayoutParams.height < mIntermediateHeaderHeight) {
             final int originalValue = toolbarLayoutParams.height;
             toolbarLayoutParams.height -= delta;
-            toolbarLayoutParams.height = Math.min(toolbarLayoutParams.height, mMaximumHeaderHeight);
+            toolbarLayoutParams.height = Math.min(toolbarLayoutParams.height,
+                    mIntermediateHeaderHeight);
             mToolbar.setLayoutParams(toolbarLayoutParams);
             delta -= originalValue - toolbarLayoutParams.height;
         }
@@ -472,7 +566,7 @@
         final int toolbarHeight = mToolbar.getLayoutParams().height;
         // Reuse an existing mColorFilter (to avoid GC pauses) to change the photo's tint.
         mPhotoView.clearColorFilter();
-        if (toolbarHeight >= mMaximumHeaderHeight) {
+        if (toolbarHeight >= mIntermediateHeaderHeight) {
             mPhotoViewContainer.setElevation(0);
             return;
         }
@@ -480,10 +574,10 @@
             mColorFilter.setColor(mHeaderTintColor);
             mPhotoView.setColorFilter(mColorFilter);
             mPhotoViewContainer.setElevation(mToolbarElevation);
-        } else {
+        } else if (toolbarHeight <= mIntermediateHeaderHeight) {
             mPhotoViewContainer.setElevation(0);
-            final int alphaBits = 0xff - 0xff * (mToolbar.getHeight()  - mMinimumHeaderHeight)
-                    / (mMaximumHeaderHeight - mMinimumHeaderHeight);
+            final int alphaBits = 0xff - 0xff * (toolbarHeight  - mMinimumHeaderHeight)
+                    / (mIntermediateHeaderHeight - mMinimumHeaderHeight);
             final int color = alphaBits << 24 | (mHeaderTintColor & 0xffffff);
             mColorFilter.setColor(color);
             mPhotoView.setColorFilter(mColorFilter);
@@ -511,6 +605,12 @@
     }
 
     private void smoothScrollBy(int delta) {
+        if (delta == 0) {
+            // Delta=0 implies the code calling smoothScrollBy is sloppy. We should avoid doing
+            // this, since it prevents Views from being able to register any clicks for 250ms.
+            throw new IllegalArgumentException("Smooth scrolling by delta=0 is "
+                    + "pointless and harmful");
+        }
         mScroller.startScroll(0, getScroll(), 0, delta);
         invalidate();
     }