Loading src/com/android/contacts/detail/ContactDetailDisplayUtils.java +46 −14 Original line number Diff line number Diff line Loading @@ -20,13 +20,13 @@ import com.android.contacts.ContactLoader; 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; Loading @@ -37,16 +37,15 @@ import android.content.res.Resources; 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; Loading @@ -71,6 +70,27 @@ public class ContactDetailDisplayUtils { 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. } Loading Loading @@ -244,7 +264,8 @@ public class ContactDetailDisplayUtils { /** 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); Loading @@ -261,17 +282,17 @@ public class ContactDetailDisplayUtils { 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); Loading @@ -294,11 +315,22 @@ public class ContactDetailDisplayUtils { 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 Loading src/com/android/contacts/detail/ContactDetailUpdatesFragment.java +28 −5 Original line number Diff line number Diff line Loading @@ -19,9 +19,11 @@ package com.android.contacts.detail; 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; Loading Loading @@ -67,7 +69,7 @@ public class ContactDetailUpdatesFragment extends ListFragment * <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(); Loading @@ -75,9 +77,7 @@ public class ContactDetailUpdatesFragment extends ListFragment // 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()); Loading @@ -88,6 +88,28 @@ public class ContactDetailUpdatesFragment extends ListFragment } }; 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 } Loading @@ -108,7 +130,8 @@ public class ContactDetailUpdatesFragment extends ListFragment @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); Loading src/com/android/contacts/detail/StreamItemAdapter.java +13 −7 Original line number Diff line number Diff line Loading @@ -42,14 +42,17 @@ public class StreamItemAdapter extends BaseAdapter { 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(); } Loading Loading @@ -83,20 +86,23 @@ public class StreamItemAdapter extends BaseAdapter { 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; } Loading tests/src/com/android/contacts/detail/StreamItemAdapterTest.java +4 −1 Original line number Diff line number Diff line Loading @@ -28,19 +28,22 @@ import java.util.ArrayList; // 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 Loading Loading
src/com/android/contacts/detail/ContactDetailDisplayUtils.java +46 −14 Original line number Diff line number Diff line Loading @@ -20,13 +20,13 @@ import com.android.contacts.ContactLoader; 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; Loading @@ -37,16 +37,15 @@ import android.content.res.Resources; 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; Loading @@ -71,6 +70,27 @@ public class ContactDetailDisplayUtils { 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. } Loading Loading @@ -244,7 +264,8 @@ public class ContactDetailDisplayUtils { /** 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); Loading @@ -261,17 +282,17 @@ public class ContactDetailDisplayUtils { 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); Loading @@ -294,11 +315,22 @@ public class ContactDetailDisplayUtils { 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 Loading
src/com/android/contacts/detail/ContactDetailUpdatesFragment.java +28 −5 Original line number Diff line number Diff line Loading @@ -19,9 +19,11 @@ package com.android.contacts.detail; 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; Loading Loading @@ -67,7 +69,7 @@ public class ContactDetailUpdatesFragment extends ListFragment * <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(); Loading @@ -75,9 +77,7 @@ public class ContactDetailUpdatesFragment extends ListFragment // 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()); Loading @@ -88,6 +88,28 @@ public class ContactDetailUpdatesFragment extends ListFragment } }; 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 } Loading @@ -108,7 +130,8 @@ public class ContactDetailUpdatesFragment extends ListFragment @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); Loading
src/com/android/contacts/detail/StreamItemAdapter.java +13 −7 Original line number Diff line number Diff line Loading @@ -42,14 +42,17 @@ public class StreamItemAdapter extends BaseAdapter { 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(); } Loading Loading @@ -83,20 +86,23 @@ public class StreamItemAdapter extends BaseAdapter { 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; } Loading
tests/src/com/android/contacts/detail/StreamItemAdapterTest.java +4 −1 Original line number Diff line number Diff line Loading @@ -28,19 +28,22 @@ import java.util.ArrayList; // 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 Loading