Merge "Launch viewStreamItemPhotoActivity when photo is tapped..."
diff --git a/src/com/android/contacts/detail/ContactDetailDisplayUtils.java b/src/com/android/contacts/detail/ContactDetailDisplayUtils.java
index cbdf148..18a4750 100644
--- a/src/com/android/contacts/detail/ContactDetailDisplayUtils.java
+++ b/src/com/android/contacts/detail/ContactDetailDisplayUtils.java
@@ -20,13 +20,13 @@
 import com.android.contacts.ContactLoader.Result;
 import com.android.contacts.ContactPhotoManager;
 import com.android.contacts.R;
-import com.android.contacts.format.FormatUtils;
 import com.android.contacts.preference.ContactsPreferences;
 import com.android.contacts.util.ContactBadgeUtil;
 import com.android.contacts.util.StreamItemEntry;
 import com.android.contacts.util.StreamItemPhotoEntry;
 import com.google.common.annotations.VisibleForTesting;
 
+import android.content.ContentUris;
 import android.content.ContentValues;
 import android.content.Context;
 import android.content.Entity;
@@ -37,16 +37,15 @@
 import android.content.res.Resources.NotFoundException;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
-import android.graphics.Typeface;
 import android.graphics.drawable.Drawable;
 import android.net.Uri;
 import android.provider.ContactsContract;
 import android.provider.ContactsContract.CommonDataKinds.Organization;
 import android.provider.ContactsContract.Data;
 import android.provider.ContactsContract.DisplayNameSources;
+import android.provider.ContactsContract.StreamItems;
 import android.text.Html;
 import android.text.Html.ImageGetter;
-import android.text.Spanned;
 import android.text.TextUtils;
 import android.util.Log;
 import android.view.LayoutInflater;
@@ -71,6 +70,27 @@
 
     private static final int PHOTO_FADE_IN_ANIMATION_DURATION_MILLIS = 100;
 
+    /**
+     * Tag object used for stream item photos.
+     */
+    public static class StreamPhotoTag {
+        public final StreamItemEntry streamItem;
+        public final StreamItemPhotoEntry streamItemPhoto;
+
+        public StreamPhotoTag(StreamItemEntry streamItem, StreamItemPhotoEntry streamItemPhoto) {
+            this.streamItem = streamItem;
+            this.streamItemPhoto = streamItemPhoto;
+        }
+
+        public Uri getStreamItemPhotoUri() {
+            final Uri.Builder builder = StreamItems.CONTENT_URI.buildUpon();
+            ContentUris.appendId(builder, streamItem.getId());
+            builder.appendPath(StreamItems.StreamItemPhotos.CONTENT_DIRECTORY);
+            ContentUris.appendId(builder, streamItemPhoto.getId());
+            return builder.build();
+        }
+    }
+
     private ContactDetailDisplayUtils() {
         // Disallow explicit creation of this class.
     }
@@ -244,7 +264,8 @@
 
     /** Creates the view that represents a stream item. */
     public static View createStreamItemView(LayoutInflater inflater, Context context,
-            StreamItemEntry streamItem, LinearLayout parent) {
+            StreamItemEntry streamItem, LinearLayout parent,
+            View.OnClickListener photoClickListener) {
         View container = inflater.inflate(R.layout.stream_item_container, parent, false);
         ViewGroup contentTable = (ViewGroup) container.findViewById(R.id.stream_item_content);
 
@@ -261,17 +282,17 @@
 
                 View photoContainer = inflater.inflate(R.layout.stream_item_row_two_images,
                         contentTable, false);
-                loadPhoto(contactPhotoManager, firstPhoto, photoContainer,
-                        R.id.stream_item_first_image);
-                loadPhoto(contactPhotoManager, secondPhoto, photoContainer,
-                        R.id.stream_item_second_image);
+                loadPhoto(contactPhotoManager, streamItem, firstPhoto, photoContainer,
+                        R.id.stream_item_first_image, photoClickListener);
+                loadPhoto(contactPhotoManager, streamItem, secondPhoto, photoContainer,
+                        R.id.stream_item_second_image, photoClickListener);
                 contentTable.addView(photoContainer);
             } else {
                 // Put in a single photo with text on the side.
                 View photoContainer = inflater.inflate(
                         R.layout.stream_item_row_image_and_text, contentTable, false);
-                loadPhoto(contactPhotoManager, firstPhoto, photoContainer,
-                        R.id.stream_item_first_image);
+                loadPhoto(contactPhotoManager, streamItem, firstPhoto, photoContainer,
+                        R.id.stream_item_first_image, photoClickListener);
                 addStreamItemText(context, streamItem,
                         photoContainer.findViewById(R.id.stream_item_second_text));
                 contentTable.addView(photoContainer);
@@ -294,11 +315,22 @@
         return container;
     }
 
-    /** Loads a photo into an image view. The image view is identifiedc by the given id. */
+    /** Loads a photo into an image view. The image view is identified by the given id. */
     private static void loadPhoto(ContactPhotoManager contactPhotoManager,
-            final StreamItemPhotoEntry firstPhoto, View photoContainer, int imageViewId) {
-        ImageView firstImageView = (ImageView) photoContainer.findViewById(imageViewId);
-        contactPhotoManager.loadPhoto(firstImageView, Uri.parse(firstPhoto.getPhotoUri()));
+            final StreamItemEntry streamItem, final StreamItemPhotoEntry streamItemPhoto,
+            View photoContainer, int imageViewId, View.OnClickListener photoClickListener) {
+        ImageView imageView = (ImageView) photoContainer.findViewById(imageViewId);
+        if (photoClickListener != null) {
+            imageView.setOnClickListener(photoClickListener);
+            imageView.setTag(new StreamPhotoTag(streamItem, streamItemPhoto));
+            imageView.setFocusable(true);
+        } else {
+            imageView.setOnClickListener(null);
+            imageView.setTag(null);
+            imageView.setFocusable(false);
+            imageView.setClickable(false); // setOnClickListener makes it clickable, so overwrite it
+        }
+        contactPhotoManager.loadPhoto(imageView, Uri.parse(streamItemPhoto.getPhotoUri()));
     }
 
     @VisibleForTesting
diff --git a/src/com/android/contacts/detail/ContactDetailUpdatesFragment.java b/src/com/android/contacts/detail/ContactDetailUpdatesFragment.java
index 846a957..99766f2 100644
--- a/src/com/android/contacts/detail/ContactDetailUpdatesFragment.java
+++ b/src/com/android/contacts/detail/ContactDetailUpdatesFragment.java
@@ -19,9 +19,11 @@
 import com.android.contacts.ContactLoader;
 import com.android.contacts.R;
 import com.android.contacts.activities.ContactDetailActivity.FragmentKeyListener;
+import com.android.contacts.detail.ContactDetailDisplayUtils.StreamPhotoTag;
 import com.android.contacts.model.AccountType;
 import com.android.contacts.model.AccountTypeManager;
 import com.android.contacts.util.StreamItemEntry;
+import com.android.contacts.util.StreamItemPhotoEntry;
 
 import android.app.ListFragment;
 import android.content.ContentUris;
@@ -67,7 +69,7 @@
      * <p>
      * It assumes the view has a tag of type {@link StreamItemEntry} associated with it.
      */
-    private View.OnClickListener mStreamItemClickListener = new View.OnClickListener() {
+    private final View.OnClickListener mStreamItemClickListener = new View.OnClickListener() {
         @Override
         public void onClick(View view) {
             StreamItemEntry streamItemEntry = (StreamItemEntry) view.getTag();
@@ -75,9 +77,7 @@
                 // Ignore if this item does not have a stream item associated with it.
                 return;
             }
-            final AccountTypeManager manager = AccountTypeManager.getInstance(getActivity());
-            final AccountType accountType = manager.getAccountType(
-                    streamItemEntry.getAccountType(), streamItemEntry.getDataSet());
+            final AccountType accountType = getAccountTypeForStreamItemEntry(streamItemEntry);
 
             final Uri uri = ContentUris.withAppendedId(StreamItems.CONTENT_URI,
                     streamItemEntry.getId());
@@ -88,6 +88,28 @@
         }
     };
 
+    private final View.OnClickListener mStreamItemPhotoItemClickListener
+            = new View.OnClickListener() {
+        @Override
+        public void onClick(View view) {
+            StreamPhotoTag tag = (StreamPhotoTag) view.getTag();
+            if (tag == null) {
+                return;
+            }
+            final AccountType accountType = getAccountTypeForStreamItemEntry(tag.streamItem);
+
+            final Intent intent = new Intent(Intent.ACTION_VIEW, tag.getStreamItemPhotoUri());
+            intent.setClassName(accountType.resPackageName,
+                    accountType.getViewStreamItemPhotoActivity());
+            startActivity(intent);
+        }
+    };
+
+    private AccountType getAccountTypeForStreamItemEntry(StreamItemEntry streamItemEntry) {
+        return AccountTypeManager.getInstance(getActivity()).getAccountType(
+                streamItemEntry.getAccountType(), streamItemEntry.getDataSet());
+    }
+
     public ContactDetailUpdatesFragment() {
         // Explicit constructor for inflation
     }
@@ -108,7 +130,8 @@
     @Override
     public void onViewCreated(View view, Bundle savedInstanceState) {
         super.onViewCreated(view, savedInstanceState);
-        mStreamItemAdapter = new StreamItemAdapter(getActivity(), mStreamItemClickListener);
+        mStreamItemAdapter = new StreamItemAdapter(getActivity(), mStreamItemClickListener,
+                mStreamItemPhotoItemClickListener);
         setListAdapter(mStreamItemAdapter);
         getListView().setOnScrollListener(mVerticalScrollListener);
 
diff --git a/src/com/android/contacts/detail/StreamItemAdapter.java b/src/com/android/contacts/detail/StreamItemAdapter.java
index 5128787..9094c5c 100644
--- a/src/com/android/contacts/detail/StreamItemAdapter.java
+++ b/src/com/android/contacts/detail/StreamItemAdapter.java
@@ -42,14 +42,17 @@
     private static final int ITEM_VIEW_TYPE_STREAM_ITEM = 2;
 
     private final Context mContext;
-    private final View.OnClickListener mListener;
+    private final View.OnClickListener mItemClickListener;
+    private final View.OnClickListener mPhotoClickListener;
     private final LayoutInflater mInflater;
 
     private List<StreamItemEntry> mStreamItems;
 
-    public StreamItemAdapter(Context context, View.OnClickListener listener) {
+    public StreamItemAdapter(Context context, View.OnClickListener itemClickListener,
+            View.OnClickListener photoClickListener) {
         mContext = context;
-        mListener = listener;
+        mItemClickListener = itemClickListener;
+        mPhotoClickListener = photoClickListener;
         mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
         mStreamItems = Lists.newArrayList();
     }
@@ -83,20 +86,23 @@
         if (position == 1) {
             return mInflater.inflate(R.layout.updates_title, null);
         }
-        StreamItemEntry streamItem = (StreamItemEntry) getItem(position);
-        View view = ContactDetailDisplayUtils.createStreamItemView(
-                mInflater, mContext, streamItem, null);
+        final StreamItemEntry streamItem = (StreamItemEntry) getItem(position);
         final AccountTypeManager manager = AccountTypeManager.getInstance(mContext);
         final AccountType accountType =
                 manager.getAccountType(streamItem.getAccountType(), streamItem.getDataSet());
+        final View view = ContactDetailDisplayUtils.createStreamItemView(
+                mInflater, mContext, streamItem, null,
+                (accountType.getViewStreamItemPhotoActivity() == null) ? null : mPhotoClickListener
+                );
         if (accountType.getViewStreamItemActivity() != null) {
             view.setTag(streamItem);
             view.setFocusable(true);
-            view.setOnClickListener(mListener);
+            view.setOnClickListener(mItemClickListener);
         } else {
             view.setTag(null);
             view.setFocusable(false);
             view.setOnClickListener(null);
+            view.setClickable(false); // setOnClickListener makes it clickable, so overwrite it
         }
         return view;
     }
diff --git a/tests/src/com/android/contacts/detail/StreamItemAdapterTest.java b/tests/src/com/android/contacts/detail/StreamItemAdapterTest.java
index d862d6e..1fee9b6 100644
--- a/tests/src/com/android/contacts/detail/StreamItemAdapterTest.java
+++ b/tests/src/com/android/contacts/detail/StreamItemAdapterTest.java
@@ -28,19 +28,22 @@
 // TODO: We should have tests for action, but that requires a mock sync-adapter that specifies
 // an action or doesn't
 
+// TODO Add test for photo click
+
 /**
  * Unit tests for {@link StreamItemAdapter}.
  */
 public class StreamItemAdapterTest extends AndroidTestCase {
     private StreamItemAdapter mAdapter;
     private FakeOnClickListener mListener;
+    private FakeOnClickListener mPhotoListener;
     private View mView;
 
     @Override
     protected void setUp() throws Exception {
         super.setUp();
         mListener = new FakeOnClickListener();
-        mAdapter = new StreamItemAdapter(getContext(), mListener);
+        mAdapter = new StreamItemAdapter(getContext(), mListener, mPhotoListener);
     }
 
     @Override