Merge "Fine-tuned enlarging of contact photos" into jb-dev
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index c53e03f..5037279 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -16,8 +16,6 @@
 <resources>
     <dimen name="account_selector_popup_width">400dip</dimen>
 
-    <dimen name="photo_action_popup_width">400dip</dimen>
-
     <!-- Top position of quick contact. If this is -1, the vertical position is determined
     based on the source of the request -->
     <dimen name="quick_contact_top_position">48dip</dimen>
@@ -82,6 +80,16 @@
     <!-- Width and height of the contact photo on the contact detail page -->
     <dimen name="detail_contact_photo_size">128dip</dimen>
 
+    <!-- Width and height of the expanded contact photo on the contact detail page -->
+    <dimen name="detail_contact_photo_expanded_size">400dip</dimen>
+
+    <!-- This is the minimum amount of space to leave underneath an expanded contact detail
+         photo -->
+    <dimen name="expanded_photo_height_offset">100dip</dimen>
+
+    <!-- Minimum width for the photo action popup options -->
+    <dimen name="photo_action_popup_min_width">300dip</dimen>
+
     <!-- Left and right padding for a contact detail item -->
     <dimen name="detail_item_icon_margin">8dip</dimen>
 
diff --git a/src/com/android/contacts/activities/PhotoSelectionActivity.java b/src/com/android/contacts/activities/PhotoSelectionActivity.java
index 0610bb6..21cf192 100644
--- a/src/com/android/contacts/activities/PhotoSelectionActivity.java
+++ b/src/com/android/contacts/activities/PhotoSelectionActivity.java
@@ -37,7 +37,6 @@
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.Parcelable;
-import android.util.Log;
 import android.view.View;
 import android.view.ViewGroup.MarginLayoutParams;
 import android.widget.FrameLayout.LayoutParams;
@@ -105,6 +104,15 @@
     /** Whether to animate the photo to an expanded view covering more of the screen. */
     private boolean mExpandPhoto;
 
+    /**
+     * Side length (in pixels) of the expanded photo if to be expanded. Photos are expected to
+     * be square.
+     */
+    private int mExpandedPhotoSize;
+
+    /** Height (in pixels) to leave underneath the expanded photo to show the list popup */
+    private int mHeightOffset;
+
     /** The semi-transparent backdrop. */
     private View mBackdrop;
 
@@ -164,6 +172,12 @@
         mIsDirectoryContact = intent.getBooleanExtra(IS_DIRECTORY_CONTACT, false);
         mExpandPhoto = intent.getBooleanExtra(EXPAND_PHOTO, false);
 
+        // Pull out photo expansion properties from resources
+        mExpandedPhotoSize = getResources().getDimensionPixelSize(
+                R.dimen.detail_contact_photo_expanded_size);
+        mHeightOffset = getResources().getDimensionPixelOffset(
+                R.dimen.expanded_photo_height_offset);
+
         mBackdrop = findViewById(R.id.backdrop);
         mPhotoView = (ImageView) findViewById(R.id.photo);
         mSourceBounds = intent.getSourceBounds();
@@ -188,6 +202,30 @@
         });
     }
 
+    /**
+     * Compute the adjusted expanded photo size to fit within the enclosing view with the same
+     * aspect ratio.
+     * @param enclosingView This is the view that the photo must fit within.
+     * @param heightOffset This is the amount of height to leave open for the photo action popup.
+     */
+    private int getAdjustedExpandedPhotoSize(View enclosingView, int heightOffset) {
+        // pull out the bounds of the backdrop
+        final Rect bounds = new Rect();
+        enclosingView.getDrawingRect(bounds);
+        final int boundsWidth = bounds.width();
+        final int boundsHeight = bounds.height() - heightOffset;
+
+        // ensure that the new expanded photo size can fit within the backdrop
+        final float alpha = Math.min((float) boundsHeight / (float) mExpandedPhotoSize,
+                (float) boundsWidth / (float) mExpandedPhotoSize);
+        if (alpha < 1.0f) {
+            // need to shrink width and height while maintaining aspect ratio
+            return (int) (alpha * mExpandedPhotoSize);
+        } else {
+            return mExpandedPhotoSize;
+        }
+    }
+
     @Override
     public void onConfigurationChanged(Configuration newConfig) {
         super.onConfigurationChanged(newConfig);
@@ -279,7 +317,6 @@
 
         // Load the photo.
         int photoWidth = getPhotoEndParams().width;
-        Log.d(TAG, "Photo width: " + photoWidth);
         if (mPhotoUri != null) {
             // If we have a URI, the bitmap should be cached directly.
             ContactPhotoManager.getInstance(this).loadPhoto(mPhotoView, mPhotoUri, photoWidth,
@@ -317,25 +354,32 @@
         attachPhotoHandler();
     }
 
+    /**
+     * This sets the photo's layout params at the end of the animation.
+     * <p>
+     * The scheme is to enlarge the photo to the desired size with the enlarged photo shifted
+     * to the top left of the screen as much as possible while keeping the underlying smaller
+     * photo occluded.
+     */
     private LayoutParams getPhotoEndParams() {
         if (mPhotoEndParams == null) {
             mPhotoEndParams = new LayoutParams(mPhotoStartParams);
             if (mExpandPhoto) {
-                Rect bounds = new Rect();
-                mBackdrop.getDrawingRect(bounds);
-                if (bounds.height() > bounds.width()) {
-                    //Take up full width.
-                    mPhotoEndParams.width = bounds.width();
-                    mPhotoEndParams.height = bounds.width();
-                } else {
-                    // Take up full height, leaving space for the popup.
-                    mPhotoEndParams.height = bounds.height() - 150;
-                    mPhotoEndParams.width = bounds.height() - 150;
+                final int adjustedPhotoSize = getAdjustedExpandedPhotoSize(mBackdrop,
+                        mHeightOffset);
+                int widthDelta = adjustedPhotoSize - mPhotoStartParams.width;
+                int heightDelta = adjustedPhotoSize - mPhotoStartParams.height;
+                if (widthDelta >= 1 || heightDelta >= 1) {
+                    // This is an actual expansion.
+                    mPhotoEndParams.width = adjustedPhotoSize;
+                    mPhotoEndParams.height = adjustedPhotoSize;
+                    mPhotoEndParams.topMargin =
+                            Math.max(mPhotoStartParams.topMargin - heightDelta, 0);
+                    mPhotoEndParams.leftMargin =
+                            Math.max(mPhotoStartParams.leftMargin - widthDelta, 0);
+                    mPhotoEndParams.bottomMargin = 0;
+                    mPhotoEndParams.rightMargin = 0;
                 }
-                mPhotoEndParams.topMargin = 0;
-                mPhotoEndParams.leftMargin = 0;
-                mPhotoEndParams.bottomMargin = mPhotoEndParams.height;
-                mPhotoEndParams.rightMargin = mPhotoEndParams.width;
             }
         }
         return mPhotoEndParams;
diff --git a/src/com/android/contacts/detail/ContactDetailFragment.java b/src/com/android/contacts/detail/ContactDetailFragment.java
index 29aa51a..1322e6b 100644
--- a/src/com/android/contacts/detail/ContactDetailFragment.java
+++ b/src/com/android/contacts/detail/ContactDetailFragment.java
@@ -425,12 +425,14 @@
             // updates or not.
             if (mShowStaticPhoto) {
                 mStaticPhotoContainer.setVisibility(View.VISIBLE);
-                ImageView photoView = (ImageView) mStaticPhotoContainer.findViewById(R.id.photo);
-                OnClickListener listener = mPhotoSetter.setupContactPhotoForClick(
-                        mContext, mContactData, photoView, false);
+                final ImageView photoView = (ImageView) mStaticPhotoContainer.findViewById(
+                        R.id.photo);
+                final boolean expandPhotoOnClick = mContactData.getPhotoUri() != null;
+                final OnClickListener listener = mPhotoSetter.setupContactPhotoForClick(
+                        mContext, mContactData, photoView, expandPhotoOnClick);
                 if (mPhotoTouchOverlay != null) {
                     mPhotoTouchOverlay.setVisibility(View.VISIBLE);
-                    if (mContactData.isWritableContact(mContext)) {
+                    if (expandPhotoOnClick || mContactData.isWritableContact(mContext)) {
                         mPhotoTouchOverlay.setOnClickListener(listener);
                     } else {
                         mPhotoTouchOverlay.setClickable(false);
@@ -1524,8 +1526,8 @@
 
             // Set the photo if it should be displayed
             if (viewCache.photoView != null) {
-                final boolean expandOnClick = !PhoneCapabilityTester.isUsingTwoPanes(mContext);
-                OnClickListener listener = mPhotoSetter.setupContactPhotoForClick(
+                final boolean expandOnClick = mContactData.getPhotoUri() != null;
+                final OnClickListener listener = mPhotoSetter.setupContactPhotoForClick(
                         mContext, mContactData, viewCache.photoView, expandOnClick);
 
                 if (expandOnClick || mContactData.isWritableContact(mContext)) {
diff --git a/src/com/android/contacts/detail/ContactDetailPhotoSetter.java b/src/com/android/contacts/detail/ContactDetailPhotoSetter.java
index b674dc0..dffb37b 100644
--- a/src/com/android/contacts/detail/ContactDetailPhotoSetter.java
+++ b/src/com/android/contacts/detail/ContactDetailPhotoSetter.java
@@ -72,6 +72,7 @@
             final int[] pos = new int[2];
             v.getLocationOnScreen(pos);
 
+            // rect is the bounds (in pixels) of the photo view in screen coordinates
             final Rect rect = new Rect();
             rect.left = (int) (pos[0] * appScale + 0.5f);
             rect.top = (int) (pos[1] * appScale + 0.5f);
diff --git a/src/com/android/contacts/detail/ContactDetailTabCarousel.java b/src/com/android/contacts/detail/ContactDetailTabCarousel.java
index dd0723d..3929281 100644
--- a/src/com/android/contacts/detail/ContactDetailTabCarousel.java
+++ b/src/com/android/contacts/detail/ContactDetailTabCarousel.java
@@ -472,8 +472,8 @@
 
         // TODO: Move this into the {@link CarouselTab} class when the updates
         // fragment code is more finalized.
-        final boolean expandOnClick = !PhoneCapabilityTester.isUsingTwoPanes(mContext);
-        OnClickListener listener = mPhotoSetter.setupContactPhotoForClick(
+        final boolean expandOnClick = contactData.getPhotoUri() != null;
+        final OnClickListener listener = mPhotoSetter.setupContactPhotoForClick(
                 mContext, contactData, mPhotoView, expandOnClick);
 
         if (expandOnClick || contactData.isWritableContact(mContext)) {
diff --git a/src/com/android/contacts/editor/PhotoActionPopup.java b/src/com/android/contacts/editor/PhotoActionPopup.java
index 9744308..a27dd8a 100644
--- a/src/com/android/contacts/editor/PhotoActionPopup.java
+++ b/src/com/android/contacts/editor/PhotoActionPopup.java
@@ -126,10 +126,13 @@
         listPopupWindow.setAnchorView(anchorView);
         listPopupWindow.setAdapter(adapter);
         listPopupWindow.setOnItemClickListener(clickListener);
-        listPopupWindow.setWidth(context.getResources().getDimensionPixelSize(
-                R.dimen.photo_action_popup_width));
         listPopupWindow.setModal(true);
         listPopupWindow.setInputMethodMode(ListPopupWindow.INPUT_METHOD_NOT_NEEDED);
+        final int minWidth = context.getResources().getDimensionPixelSize(
+                R.dimen.photo_action_popup_min_width);
+        if (anchorView.getWidth() < minWidth) {
+            listPopupWindow.setWidth(minWidth);
+        }
         return listPopupWindow;
     }