Update group editor styles and avatars for dogfood
* Use standard action bar w/ done button placement
matching that on the contact editor
* Replace group member QuickContactBadge avatar with
letter tile to match avatars in the main contacts
lists. Also put it on the left side.
* Make the name in each group member row clickable.
* Don't use a two panel screen in landscape any more.
Bug 18641067
Change-Id: Id45a6ceb0a138906078356fa71a72225add07ecf
diff --git a/src/com/android/contacts/GroupMemberLoader.java b/src/com/android/contacts/GroupMemberLoader.java
index 6001f2c..43a6427 100644
--- a/src/com/android/contacts/GroupMemberLoader.java
+++ b/src/com/android/contacts/GroupMemberLoader.java
@@ -41,6 +41,7 @@
Data.DISPLAY_NAME_PRIMARY, // 2
Data.PHOTO_URI, // 3
Data.LOOKUP_KEY, // 4
+ Data.PHOTO_ID, // 5
};
public static final int CONTACT_ID = 0;
@@ -48,6 +49,7 @@
public static final int CONTACT_DISPLAY_NAME_PRIMARY = 2;
public static final int CONTACT_PHOTO_URI = 3;
public static final int CONTACT_LOOKUP_KEY = 4;
+ public static final int CONTACT_PHOTO_ID = 5;
}
public static class GroupDetailQuery {
diff --git a/src/com/android/contacts/activities/GroupEditorActivity.java b/src/com/android/contacts/activities/GroupEditorActivity.java
index d48ed97..8a285a7 100644
--- a/src/com/android/contacts/activities/GroupEditorActivity.java
+++ b/src/com/android/contacts/activities/GroupEditorActivity.java
@@ -18,20 +18,17 @@
import android.app.ActionBar;
import android.app.Dialog;
-import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.View.OnClickListener;
import com.android.contacts.ContactsActivity;
import com.android.contacts.R;
+import com.android.contacts.common.util.ImplicitIntentsUtil;
import com.android.contacts.group.GroupEditorFragment;
+import com.android.contacts.quickcontact.QuickContactActivity;
import com.android.contacts.util.DialogManager;
-import com.android.contacts.util.PhoneCapabilityTester;
public class GroupEditorActivity extends ContactsActivity
implements DialogManager.DialogShowingViewActivity {
@@ -39,8 +36,6 @@
private static final String TAG = "GroupEditorActivity";
public static final String ACTION_SAVE_COMPLETED = "saveCompleted";
- public static final String ACTION_ADD_MEMBER_COMPLETED = "addMemberCompleted";
- public static final String ACTION_REMOVE_MEMBER_COMPLETED = "removeMemberCompleted";
private GroupEditorFragment mFragment;
@@ -60,24 +55,9 @@
ActionBar actionBar = getActionBar();
if (actionBar != null) {
- // Inflate a custom action bar that contains the "done" button for saving changes
- // to the group
- LayoutInflater inflater = (LayoutInflater) getSystemService
- (Context.LAYOUT_INFLATER_SERVICE);
- View customActionBarView = inflater.inflate(R.layout.editor_custom_action_bar,
- null);
- View saveMenuItem = customActionBarView.findViewById(R.id.save_menu_item);
- saveMenuItem.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- mFragment.onDoneClicked();
- }
- });
- // Show the custom action bar but hide the home icon and title
- actionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM,
- ActionBar.DISPLAY_SHOW_CUSTOM | ActionBar.DISPLAY_SHOW_HOME |
- ActionBar.DISPLAY_SHOW_TITLE);
- actionBar.setCustomView(customActionBarView);
+ actionBar.setTitle(getResources().getString(R.string.editGroupDescription));
+ actionBar.setDisplayShowHomeEnabled(true);
+ actionBar.setDisplayHomeAsUpEnabled(true);
}
mFragment = (GroupEditorFragment) getFragmentManager().findFragmentById(
@@ -153,6 +133,12 @@
finish();
}
}
+
+ @Override
+ public void onGroupMemberClicked(Uri contactLookupUri) {
+ startActivity(ImplicitIntentsUtil.composeQuickContactIntent(
+ contactLookupUri, QuickContactActivity.MODE_FULLY_EXPANDED));
+ }
};
@Override
diff --git a/src/com/android/contacts/group/GroupEditorFragment.java b/src/com/android/contacts/group/GroupEditorFragment.java
index 1104c02..25a07f1 100644
--- a/src/com/android/contacts/group/GroupEditorFragment.java
+++ b/src/com/android/contacts/group/GroupEditorFragment.java
@@ -53,7 +53,6 @@
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.ListView;
-import android.widget.QuickContactBadge;
import android.widget.TextView;
import android.widget.Toast;
@@ -71,7 +70,6 @@
import com.android.contacts.group.SuggestedMemberListAdapter.SuggestedMember;
import com.android.contacts.common.model.AccountTypeManager;
import com.android.contacts.common.util.AccountsListAdapter.AccountListFilter;
-import com.android.contacts.common.util.ViewUtil;
import com.google.common.base.Objects;
@@ -118,6 +116,11 @@
* Fragment is created but there's no accounts set up.
*/
void onAccountsNotFound();
+
+ /**
+ * Group member name or photo was clicked in order to view contact details.
+ */
+ void onGroupMemberClicked(Uri contactLookupUri);
}
private static final int LOADER_GROUP_METADATA = 1;
@@ -514,6 +517,23 @@
inflater.inflate(R.menu.edit_group, menu);
}
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ switch (item.getItemId()) {
+ case android.R.id.home: {
+ getActivity().onBackPressed();
+ return true;
+ }
+ case R.id.menu_save:
+ onDoneClicked();
+ return true;
+ case R.id.menu_discard:
+ doRevertAction();
+ return true;
+ }
+ return false;
+ }
+
private void doRevertAction() {
// When this Fragment is closed we don't want it to auto-save
mStatus = Status.CLOSING;
@@ -768,8 +788,9 @@
String lookupKey = data.getString(GroupEditorQuery.CONTACT_LOOKUP_KEY);
String displayName = data.getString(GroupEditorQuery.CONTACT_DISPLAY_NAME_PRIMARY);
String photoUri = data.getString(GroupEditorQuery.CONTACT_PHOTO_URI);
+ long photoId = data.getLong(GroupEditorQuery.CONTACT_PHOTO_ID);
listExistingMembers.add(new Member(rawContactId, lookupKey, contactId,
- displayName, photoUri));
+ displayName, photoUri, photoId));
}
// Update the display list
@@ -813,8 +834,10 @@
String displayName = cursor.getString(CONTACT_DISPLAY_NAME_PRIMARY_COLUMN_INDEX);
String lookupKey = cursor.getString(CONTACT_LOOKUP_KEY_COLUMN_INDEX);
String photoUri = cursor.getString(CONTACT_PHOTO_URI_COLUMN_INDEX);
+ long photoId = cursor.getLong(CONTACT_PHOTO_ID_COLUMN_INDEX);
getLoaderManager().destroyLoader(LOADER_NEW_GROUP_MEMBER);
- Member member = new Member(mRawContactId, lookupKey, contactId, displayName, photoUri);
+ Member member = new Member(mRawContactId, lookupKey, contactId, displayName, photoUri,
+ photoId);
addMember(member);
}
@@ -834,15 +857,17 @@
private final String mDisplayName;
private final Uri mPhotoUri;
private final String mLookupKey;
+ private final long mPhotoId;
public Member(long rawContactId, String lookupKey, long contactId, String displayName,
- String photoUri) {
+ String photoUri, long photoId) {
mRawContactId = rawContactId;
mContactId = contactId;
mLookupKey = lookupKey;
mLookupUri = Contacts.getLookupUri(contactId, lookupKey);
mDisplayName = displayName;
mPhotoUri = (photoUri != null) ? Uri.parse(photoUri) : null;
+ mPhotoId = photoId;
}
public long getRawContactId() {
@@ -869,6 +894,10 @@
return mPhotoUri;
}
+ public long getPhotoId() {
+ return mPhotoId;
+ }
+
@Override
public boolean equals(Object object) {
if (object instanceof Member) {
@@ -897,6 +926,7 @@
dest.writeString(mLookupKey);
dest.writeString(mDisplayName);
dest.writeParcelable(mPhotoUri, flags);
+ dest.writeLong(mPhotoId);
}
private Member(Parcel in) {
@@ -906,6 +936,7 @@
mLookupKey = in.readString();
mDisplayName = in.readString();
mPhotoUri = in.readParcelable(getClass().getClassLoader());
+ mPhotoId = in.readLong();
}
public static final Parcelable.Creator<Member> CREATOR = new Parcelable.Creator<Member>() {
@@ -939,12 +970,18 @@
result = convertView;
}
final Member member = getItem(position);
-
- QuickContactBadge badge = (QuickContactBadge) result.findViewById(R.id.badge);
- badge.assignContactUri(member.getLookupUri());
+ final OnClickListener groupMemberClickListener = new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ if (mListener != null) {
+ mListener.onGroupMemberClicked(member.getLookupUri());
+ }
+ }
+ };
TextView name = (TextView) result.findViewById(R.id.name);
name.setText(member.getDisplayName());
+ name.setOnClickListener(groupMemberClickListener);
View deleteButton = result.findViewById(R.id.delete_button_container);
if (deleteButton != null) {
@@ -955,11 +992,13 @@
}
});
}
- DefaultImageRequest request = new DefaultImageRequest(member.getDisplayName(),
- member.getLookupKey(), true /* isCircular */);
- mPhotoManager.loadPhoto(badge, member.getPhotoUri(),
- ViewUtil.getConstantPreLayoutWidth(badge), false, true /* isCircular */,
- request);
+
+ // Bind photo
+ final ImageView imageView = (ImageView) result.findViewById(R.id.photo);
+ imageView.setOnClickListener(groupMemberClickListener);
+ bindPhoto(mPhotoManager, imageView, member.getPhotoId(), member.getPhotoUri(),
+ member.getDisplayName(), member.getLookupKey());
+
return result;
}
@@ -982,4 +1021,23 @@
mIsGroupMembershipEditable = editable;
}
}
+
+ /**
+ * @param identifier the {@link ContactPhotoManager.DefaultImageRequest#identifier}
+ * to use for this the group member.
+ */
+ public static void bindPhoto(ContactPhotoManager photoManager, ImageView imageView,
+ long photoId, Uri photoUri, String displayName, String identifier) {
+ if (photoId == 0) {
+ final DefaultImageRequest defaultImageRequest = photoUri == null
+ ? new DefaultImageRequest(displayName, identifier,
+ /* circularPhotos */ true)
+ : null;
+ photoManager.loadDirectoryPhoto(imageView, photoUri, /* darkTheme */ false,
+ /* isCircular */ true, defaultImageRequest);
+ } else {
+ photoManager.loadThumbnail(imageView, photoId, /* darkTheme */ false,
+ /* isCircular */ true, /* defaultImageRequest */ null);
+ }
+ }
}
diff --git a/src/com/android/contacts/group/SuggestedMemberListAdapter.java b/src/com/android/contacts/group/SuggestedMemberListAdapter.java
index 19ff611..eb80ac4 100644
--- a/src/com/android/contacts/group/SuggestedMemberListAdapter.java
+++ b/src/com/android/contacts/group/SuggestedMemberListAdapter.java
@@ -16,10 +16,17 @@
package com.android.contacts.group;
import android.content.ContentResolver;
+import android.content.ContentUris;
import android.content.Context;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffXfermode;
+import android.net.Uri;
import android.provider.ContactsContract.CommonDataKinds.Email;
import android.provider.ContactsContract.CommonDataKinds.Phone;
import android.provider.ContactsContract.CommonDataKinds.Photo;
@@ -69,6 +76,7 @@
Photo.PHOTO, // 4
};
+ private static final int ID_INDEX = 0;
private static final int MIMETYPE_COLUMN_INDEX = 2;
private static final int DATA_COLUMN_INDEX = 3;
private static final int PHOTO_COLUMN_INDEX = 4;
@@ -76,6 +84,7 @@
private Filter mFilter;
private ContentResolver mContentResolver;
private LayoutInflater mInflater;
+ private ContactPhotoManager mPhotoManager;
private String mAccountType;
private String mAccountName;
@@ -90,6 +99,7 @@
public SuggestedMemberListAdapter(Context context, int textViewResourceId) {
super(context, textViewResourceId);
mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ mPhotoManager = ContactPhotoManager.getInstance(context);
}
public void setAccountType(String accountType) {
@@ -144,16 +154,56 @@
}
byte[] byteArray = member.getPhotoByteArray();
if (byteArray == null) {
- icon.setImageDrawable(ContactPhotoManager.getDefaultAvatarDrawableForContact(
- icon.getResources(), false, null));
+ final Uri contactLookupUri = RawContacts.getContactLookupUri(mContentResolver,
+ ContentUris.withAppendedId(RawContacts.CONTENT_URI, member.getContactId()));
+ final String imageRequestIdentifier = contactLookupUri == null
+ ? null : contactLookupUri.toString();
+ GroupEditorFragment.bindPhoto(mPhotoManager, icon, member.getPhotoId(),
+ /* photoUri */ null, member.getDisplayName(), imageRequestIdentifier);
} else {
Bitmap bitmap = BitmapFactory.decodeByteArray(byteArray, 0, byteArray.length);
- icon.setImageBitmap(bitmap);
+ icon.setImageBitmap(frameBitmapInCircle(bitmap));
}
result.setTag(member);
return result;
}
+ private static Bitmap frameBitmapInCircle(Bitmap input) {
+ // Crop the image if not squared.
+ final int targetDiameter = input.getWidth();
+ final Bitmap scaled = Bitmap.createScaledBitmap(
+ input, targetDiameter, targetDiameter, /* filter */ false);
+ int inputWidth = scaled.getWidth();
+ int inputHeight = scaled.getHeight();
+ int targetX, targetY, targetSize;
+ if (inputWidth >= inputHeight) {
+ targetX = inputWidth / 2 - inputHeight / 2;
+ targetY = 0;
+ targetSize = inputHeight;
+ } else {
+ targetX = 0;
+ targetY = inputHeight / 2 - inputWidth / 2;
+ targetSize = inputWidth;
+ }
+
+ // Create an output bitmap and a canvas to draw on it.
+ final Bitmap output = Bitmap.createBitmap(targetSize, targetSize, Bitmap.Config.ARGB_8888);
+ final Canvas canvas = new Canvas(output);
+
+ // Create a black paint to draw the mask.
+ final Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ paint.setColor(Color.BLACK);
+
+ // Draw a circle.
+ canvas.drawCircle(targetDiameter / 2, targetDiameter / 2, targetDiameter / 2, paint);
+
+ // Replace the black parts of the mask with the input image.
+ paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
+ canvas.drawBitmap(scaled, targetX /* left */, targetY /* top */, paint);
+
+ return output;
+ }
+
@Override
public Filter getFilter() {
if (mFilter == null) {
@@ -277,6 +327,7 @@
String mimetype = memberDataCursor.getString(MIMETYPE_COLUMN_INDEX);
if (Photo.CONTENT_ITEM_TYPE.equals(mimetype)) {
// Set photo
+ member.setPhotoId(memberDataCursor.getLong(ID_INDEX));
byte[] bitmapArray = memberDataCursor.getBlob(PHOTO_COLUMN_INDEX);
member.setPhotoByteArray(bitmapArray);
} else if (Email.CONTENT_ITEM_TYPE.equals(mimetype) ||
@@ -327,8 +378,10 @@
private long mRawContactId;
private long mContactId;
private String mDisplayName;
+
private String mExtraInfo;
private byte[] mPhoto;
+ private long mPhotoId;
public SuggestedMember(long rawContactId, String displayName, long contactId) {
mRawContactId = rawContactId;
@@ -356,6 +409,10 @@
return mPhoto;
}
+ public long getPhotoId() {
+ return mPhotoId;
+ }
+
public boolean hasExtraInfo() {
return mExtraInfo != null;
}
@@ -371,6 +428,10 @@
mPhoto = photo;
}
+ public void setPhotoId(long photoId) {
+ mPhotoId = photoId;
+ }
+
@Override
public String toString() {
return getDisplayName();