Adds photo display, and primary state editing to ViewContact.
Hooks up the contact thumbnail to the actual photo data instead of
always showing the placeholder image.
Imlements changing the "primary" state of phone number and emails.
diff --git a/src/com/android/contacts/ContactEntryAdapter.java b/src/com/android/contacts/ContactEntryAdapter.java
index 64f2585..ab47b5c 100644
--- a/src/com/android/contacts/ContactEntryAdapter.java
+++ b/src/com/android/contacts/ContactEntryAdapter.java
@@ -37,33 +37,37 @@
Data._ID, // 2
Data.PACKAGE, //3
Data.MIMETYPE, //4
- Data.DATA1, //5
- Data.DATA2, //6
- Data.DATA3, //7
- Data.DATA4, //8
- Data.DATA5, //9
- Data.DATA6, //10
- Data.DATA7, //11
- Data.DATA8, //12
- Data.DATA9, //13
- Data.DATA10, //14
+ Data.IS_PRIMARY, //5
+ Data.IS_SUPER_PRIMARY, //6
+ Data.DATA1, //7
+ Data.DATA2, //8
+ Data.DATA3, //9
+ Data.DATA4, //10
+ Data.DATA5, //11
+ Data.DATA6, //12
+ Data.DATA7, //13
+ Data.DATA8, //14
+ Data.DATA9, //15
+ Data.DATA10, //16
};
public static final int AGGREGATE_DISPLAY_NAME_COLUMN = 0;
public static final int AGGREGATE_STARRED_COLUMN = 1;
public static final int DATA_ID_COLUMN = 2;
public static final int DATA_PACKAGE_COLUMN = 3;
public static final int DATA_MIMETYPE_COLUMN = 4;
- public static final int DATA_1_COLUMN = 5;
- public static final int DATA_2_COLUMN = 6;
- public static final int DATA_3_COLUMN = 7;
- public static final int DATA_4_COLUMN = 8;
- public static final int DATA_5_COLUMN = 9;
- public static final int DATA_6_COLUMN = 10;
- public static final int DATA_7_COLUMN = 11;
- public static final int DATA_8_COLUMN = 12;
- public static final int DATA_9_COLUMN = 13;
- public static final int DATA_10_COLUMN = 14;
-
+ public static final int DATA_IS_PRIMARY_COLUMN = 5;
+ public static final int DATA_IS_SUPER_PRIMARY_COLUMN = 6;
+ public static final int DATA_1_COLUMN = 7;
+ public static final int DATA_2_COLUMN = 8;
+ public static final int DATA_3_COLUMN = 9;
+ public static final int DATA_4_COLUMN = 10;
+ public static final int DATA_5_COLUMN = 11;
+ public static final int DATA_6_COLUMN = 12;
+ public static final int DATA_7_COLUMN = 13;
+ public static final int DATA_8_COLUMN = 14;
+ public static final int DATA_9_COLUMN = 15;
+ public static final int DATA_10_COLUMN = 16;
+
protected ArrayList<ArrayList<E>> mSections;
protected LayoutInflater mInflater;
protected Context mContext;
@@ -87,8 +91,10 @@
public Uri uri;
public long id = 0;
public int maxLines = 1;
+ // TODO(emillar): remove "kind" completely once it is removed from EditContactActivity
public int kind;
-
+ public String mimetype;
+
/**
* Helper for making subclasses parcelable.
*/
@@ -98,9 +104,9 @@
p.writeParcelable(uri, 0);
p.writeLong(id);
p.writeInt(maxLines);
- p.writeInt(kind);
+ p.writeString(mimetype);
}
-
+
/**
* Helper for making subclasses parcelable.
*/
@@ -110,7 +116,7 @@
uri = p.readParcelable(null);
id = p.readLong();
maxLines = p.readInt();
- kind = p.readInt();
+ mimetype = p.readString();
}
}
@@ -123,7 +129,7 @@
/**
* Resets the section data.
- *
+ *
* @param sections the section data
*/
public final void setSections(ArrayList<ArrayList<E>> sections, boolean separators) {
@@ -134,7 +140,7 @@
/**
* Resets the section data and returns the position of the given entry.
- *
+ *
* @param sections the section data
* @param entry the entry to return the position for
* @return the position of entry, or -1 if it isn't found
@@ -210,7 +216,7 @@
/**
* Get the entry for the given position.
- *
+ *
* @param sections the list of sections
* @param position the position for the desired entry
* @return the ContactEntry for the given position
@@ -235,7 +241,7 @@
/**
* Get the count of entries in all sections
- *
+ *
* @param sections the list of sections
* @return the count of entries in all sections
*/
@@ -283,7 +289,7 @@
/**
* Create a new view for an entry.
- *
+ *
* @parent the parent ViewGroup
* @return the newly created view
*/
@@ -291,7 +297,7 @@
/**
* Binds the data from an entry to a view.
- *
+ *
* @param view the view to display the entry in
* @param entry the data to bind
*/
diff --git a/src/com/android/contacts/ContactsUtils.java b/src/com/android/contacts/ContactsUtils.java
index e812cc8..18d6dfb 100644
--- a/src/com/android/contacts/ContactsUtils.java
+++ b/src/com/android/contacts/ContactsUtils.java
@@ -1,18 +1,43 @@
+/*
+ * Copyright (C) 2009 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.
+ */
+
package com.android.contacts;
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+
+import android.net.Uri;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.database.Cursor;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.provider.Contacts;
+import android.provider.Contacts.Photos;
import android.provider.ContactsContract.CommonDataKinds.Email;
import android.provider.ContactsContract.CommonDataKinds.Im;
import android.provider.ContactsContract.CommonDataKinds.Organization;
import android.provider.ContactsContract.CommonDataKinds.Phone;
import android.provider.ContactsContract.CommonDataKinds.Postal;
import android.provider.Im.ProviderNames;
-
-import android.content.Context;
import android.text.TextUtils;
public class ContactsUtils {
-
+
public static final CharSequence getDisplayLabel(Context context, String mimetype, int type,
CharSequence label) {
CharSequence display = "";
@@ -40,7 +65,7 @@
// Can't return display label for given mimetype.
return display;
}
-
+
if (type != customType) {
CharSequence[] labels = context.getResources().getTextArray(arrayResId);
try {
@@ -55,7 +80,7 @@
}
return display;
}
-
+
public static Object decodeImProtocol(String encodedString) {
if (encodedString == null) {
return null;
@@ -72,9 +97,43 @@
throw new IllegalArgumentException(
"the value is not a valid encoded protocol, " + encodedString);
}
-
-
+ /**
+ * Opens an InputStream for the person's photo and returns the photo as a Bitmap.
+ * If the person's photo isn't present returns null.
+ *
+ * @param aggCursor the Cursor pointing to the data record containing the photo.
+ * @param bitmapColumnIndex the column index where the photo Uri is stored.
+ * @param options the decoding options, can be set to null
+ * @return the photo Bitmap
+ */
+ public static Bitmap loadContactPhoto(Cursor aggCursor, int bitmapColumnIndex,
+ BitmapFactory.Options options) {
+ if (aggCursor == null) {
+ return null;
+ }
+
+ byte[] data = aggCursor.getBlob(bitmapColumnIndex);;
+ return BitmapFactory.decodeByteArray(data, 0, data.length, options);
+ }
+
+ /**
+ * Loads a placeholder photo.
+ *
+ * @param placeholderImageResource the resource to use for the placeholder image
+ * @param context the Context
+ * @param options the decoding options, can be set to null
+ * @return the placeholder Bitmap.
+ */
+ public static Bitmap loadPlaceholderPhoto(int placeholderImageResource, Context context,
+ BitmapFactory.Options options) {
+ if (placeholderImageResource == 0) {
+ return null;
+ }
+ return BitmapFactory.decodeResource(context.getResources(),
+ placeholderImageResource, options);
+ }
+
/**
* This looks up the provider name defined in
* {@link android.provider.Im.ProviderNames} from the predefined IM protocol id.
diff --git a/src/com/android/contacts/ViewContactActivity.java b/src/com/android/contacts/ViewContactActivity.java
index a40d8b4..4b90199 100644
--- a/src/com/android/contacts/ViewContactActivity.java
+++ b/src/com/android/contacts/ViewContactActivity.java
@@ -22,6 +22,8 @@
import static com.android.contacts.ContactEntryAdapter.DATA_ID_COLUMN;
import static com.android.contacts.ContactEntryAdapter.DATA_PACKAGE_COLUMN;
import static com.android.contacts.ContactEntryAdapter.DATA_MIMETYPE_COLUMN;
+import static com.android.contacts.ContactEntryAdapter.DATA_IS_PRIMARY_COLUMN;
+import static com.android.contacts.ContactEntryAdapter.DATA_IS_SUPER_PRIMARY_COLUMN;
import static com.android.contacts.ContactEntryAdapter.DATA_1_COLUMN;
import static com.android.contacts.ContactEntryAdapter.DATA_2_COLUMN;
import static com.android.contacts.ContactEntryAdapter.DATA_3_COLUMN;
@@ -50,6 +52,7 @@
import android.content.res.Resources;
import android.database.ContentObserver;
import android.database.Cursor;
+import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.Drawable;
import android.media.Ringtone;
@@ -62,6 +65,7 @@
import android.os.SystemClock;
import android.provider.ContactsContract.CommonDataKinds;
import android.provider.ContactsContract.Aggregates;
+import android.provider.ContactsContract.Contacts;
import android.provider.ContactsContract.Data;
import android.provider.Im;
import android.text.TextUtils;
@@ -101,6 +105,7 @@
public static final int MENU_ITEM_SHOW_BARCODE = 3;
private Uri mUri;
+ private Uri mAggDataUri;
private ContentResolver mResolver;
private ViewAdapter mAdapter;
private int mNumPhoneNumbers = 0;
@@ -194,7 +199,8 @@
mNoPhotoResource = R.drawable.ic_contact_picture_3;
}
- mUri = Uri.withAppendedPath(getIntent().getData(), "data");
+ mUri = getIntent().getData();
+ mAggDataUri = Uri.withAppendedPath(mUri, "data");
mResolver = getContentResolver();
// Build the list of sections. The order they're added to mSections dictates the
@@ -211,7 +217,8 @@
//TODO Read this value from a preference
mShowSmsLinksForAllPhones = true;
- mCursor = mResolver.query(mUri, AGGREGATE_PROJECTION, null, null, null);
+ mCursor = mResolver.query(mAggDataUri,
+ AGGREGATE_PROJECTION, null, null, null);
}
@Override
@@ -274,18 +281,11 @@
mNameView.setText(name);
}
- // TODO(emillar) Bring this back.
+ // TODO(emillar) Bring this back.
/*if (mPhoneticNameView != null) {
String phoneticName = mCursor.getString(CONTACT_PHONETIC_NAME_COLUMN);
mPhoneticNameView.setText(phoneticName);
- }
-
- // Load the photo
- mPhotoView.setImageBitmap(People.loadContactPhoto(this, mUri, mNoPhotoResource,
- null)); */
-
- mPhotoView.setImageBitmap(BitmapFactory.decodeResource(getResources(),
- mNoPhotoResource, null));
+ } */
// Set the star
mStarView.setChecked(mCursor.getInt(AGGREGATE_STARRED_COLUMN) == 1 ? true : false);
@@ -356,33 +356,25 @@
return;
}
- // TODO(emillar) Bring this back.
- /*ViewEntry entry = ContactEntryAdapter.getEntry(mSections, info.position, SHOW_SEPARATORS);
- switch (entry.kind) {
- case Contacts.KIND_PHONE: {
- menu.add(0, 0, 0, R.string.menu_call).setIntent(entry.intent);
- menu.add(0, 0, 0, R.string.menu_sendSMS).setIntent(entry.auxIntent);
- if (entry.primaryIcon == -1) {
- menu.add(0, MENU_ITEM_MAKE_DEFAULT, 0, R.string.menu_makeDefaultNumber);
- }
- break;
+ ViewEntry entry = ContactEntryAdapter.getEntry(mSections, info.position, SHOW_SEPARATORS);
+ if (entry.mimetype.equals(CommonDataKinds.Phone.CONTENT_ITEM_TYPE)) {
+ menu.add(0, 0, 0, R.string.menu_call).setIntent(entry.intent);
+ menu.add(0, 0, 0, R.string.menu_sendSMS).setIntent(entry.auxIntent);
+ if (entry.primaryIcon == -1) {
+ menu.add(0, MENU_ITEM_MAKE_DEFAULT, 0, R.string.menu_makeDefaultNumber);
}
-
- case Contacts.KIND_EMAIL: {
- menu.add(0, 0, 0, R.string.menu_sendEmail).setIntent(entry.intent);
- break;
+ } else if (entry.mimetype.equals(CommonDataKinds.Email.CONTENT_ITEM_TYPE)) {
+ menu.add(0, 0, 0, R.string.menu_sendEmail).setIntent(entry.intent);
+ if (entry.primaryIcon == -1) {
+ menu.add(0, MENU_ITEM_MAKE_DEFAULT, 0, R.string.menu_makeDefaultEmail);
}
-
- case Contacts.KIND_POSTAL: {
- menu.add(0, 0, 0, R.string.menu_viewAddress).setIntent(entry.intent);
- break;
- }
-
- case ContactEntryAdapter.Entry.KIND_GROUP: {
- menu.add(0, 0, 0, R.string.menu_viewGroup).setIntent(entry.intent);
- break;
- }
- } */
+ } else if (entry.mimetype.equals(CommonDataKinds.Postal.CONTENT_ITEM_TYPE)) {
+ menu.add(0, 0, 0, R.string.menu_viewAddress).setIntent(entry.intent);
+ }
+ // TODO(emillar): add back with group support.
+ /* else if (entry.mimetype.equals()) {
+ menu.add(0, 0, 0, R.string.menu_viewGroup).setIntent(entry.intent);
+ } */
}
@Override
@@ -444,8 +436,7 @@
public boolean onContextItemSelected(MenuItem item) {
switch (item.getItemId()) {
case MENU_ITEM_MAKE_DEFAULT: {
- //TODO(emillar) Bring this back.
- /*AdapterView.AdapterContextMenuInfo info;
+ AdapterView.AdapterContextMenuInfo info;
try {
info = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo();
} catch (ClassCastException e) {
@@ -455,10 +446,16 @@
ViewEntry entry = ContactEntryAdapter.getEntry(mSections, info.position,
SHOW_SEPARATORS);
+
+ // Update the primary values in the data record.
ContentValues values = new ContentValues(1);
- values.put(PRIMARY_PHONE_ID, entry.id);
- getContentResolver().update(mUri, values, null, null);
- dataChanged();*/
+ values.put(Data.IS_PRIMARY, 1);
+ values.put(Data.IS_SUPER_PRIMARY, 1);
+
+ Log.i(TAG, mUri.toString());
+ getContentResolver().update(ContentUris.withAppendedId(Data.CONTENT_URI, entry.id),
+ values, null, null);
+ dataChanged();
return true;
}
}
@@ -530,55 +527,8 @@
//TODO: implement this when we have the sonification APIs
}
- /**
- * Build separator entries for all of the sections.
- */
- private void buildSeparators() {
- ViewEntry separator;
-
- separator = new ViewEntry();
- separator.kind = ViewEntry.KIND_SEPARATOR;
- separator.data = getString(R.string.listSeparatorCallNumber);
- mPhoneEntries.add(separator);
-
- separator = new ViewEntry();
- separator.kind = ViewEntry.KIND_SEPARATOR;
- separator.data = getString(R.string.listSeparatorSendSmsMms);
- mSmsEntries.add(separator);
-
- separator = new ViewEntry();
- separator.kind = ViewEntry.KIND_SEPARATOR;
- separator.data = getString(R.string.listSeparatorSendEmail);
- mEmailEntries.add(separator);
-
- separator = new ViewEntry();
- separator.kind = ViewEntry.KIND_SEPARATOR;
- separator.data = getString(R.string.listSeparatorSendIm);
- mImEntries.add(separator);
-
- separator = new ViewEntry();
- separator.kind = ViewEntry.KIND_SEPARATOR;
- separator.data = getString(R.string.listSeparatorMapAddress);
- mPostalEntries.add(separator);
-
- separator = new ViewEntry();
- separator.kind = ViewEntry.KIND_SEPARATOR;
- separator.data = getString(R.string.listSeparatorOrganizations);
- mOrganizationEntries.add(separator);
-
- separator = new ViewEntry();
- separator.kind = ViewEntry.KIND_SEPARATOR;
- separator.data = getString(R.string.listSeparatorGroups);
- mGroupEntries.add(separator);
-
- separator = new ViewEntry();
- separator.kind = ViewEntry.KIND_SEPARATOR;
- separator.data = getString(R.string.listSeparatorOtherInformation);
- mOtherEntries.add(separator);
- }
-
private Uri constructImToUrl(String host, String data) {
- // don't encode the url, because the Activity Manager can't find using the encoded url
+ // don't encode the url, because the Activity Manager can't find using the encoded url
StringBuilder buf = new StringBuilder("imto://");
buf.append(host);
buf.append('/');
@@ -598,12 +548,9 @@
mSections.get(i).clear();
}
- if (SHOW_SEPARATORS) {
- buildSeparators();
- }
-
// Build up method entries
if (mUri != null) {
+ Bitmap photoBitmap = null;
while (aggCursor.moveToNext()) {
final String mimetype = aggCursor.getString(DATA_MIMETYPE_COLUMN);
final String pkg = aggCursor.getString(DATA_PACKAGE_COLUMN);
@@ -614,17 +561,17 @@
final Uri uri = ContentUris.withAppendedId(Data.CONTENT_URI, id);
entry.id = id;
entry.uri = uri;
- //TODO(emillar) Can we get rid of kind?
- entry.kind = 0;
+ entry.mimetype = mimetype;
if (mimetype.equals(CommonDataKinds.Phone.CONTENT_ITEM_TYPE)
|| mimetype.equals(CommonDataKinds.Email.CONTENT_ITEM_TYPE)
|| mimetype.equals(CommonDataKinds.Postal.CONTENT_ITEM_TYPE)
|| mimetype.equals(CommonDataKinds.Im.CONTENT_ITEM_TYPE)) {
final int type = aggCursor.getInt(DATA_1_COLUMN);
- final String label = aggCursor.getString(DATA_2_COLUMN);
- final String data = aggCursor.getString(DATA_3_COLUMN);
- final boolean isPrimary = "1".equals(aggCursor.getString(DATA_4_COLUMN));
+ final String label = aggCursor.getString(DATA_3_COLUMN);
+ final String data = aggCursor.getString(DATA_2_COLUMN);
+ final boolean isSuperPrimary = "1".equals(
+ aggCursor.getString(DATA_IS_SUPER_PRIMARY_COLUMN));
// Don't crash if the data is bogus
if (TextUtils.isEmpty(data)) {
@@ -643,7 +590,7 @@
entry.intent = new Intent(Intent.ACTION_CALL_PRIVILEGED, entry.uri);
entry.auxIntent = new Intent(Intent.ACTION_SENDTO,
Uri.fromParts("sms", data, null));
- if (isPrimary) {
+ if (isSuperPrimary) {
entry.primaryIcon = R.drawable.ic_default_number;
}
entry.actionIcon = android.R.drawable.sym_action_call;
@@ -659,7 +606,7 @@
smsEntry.id = id;
smsEntry.uri = uri;
smsEntry.intent = entry.auxIntent;
- smsEntry.kind = ViewEntry.KIND_SMS;
+ smsEntry.mimetype = FastTrackWindow.MIME_SMS_ADDRESS;
smsEntry.actionIcon = R.drawable.sym_action_sms;
mSmsEntries.add(smsEntry);
}
@@ -671,7 +618,7 @@
entry.intent = new Intent(Intent.ACTION_SENDTO,
Uri.fromParts("mailto", data, null));
entry.actionIcon = android.R.drawable.sym_action_email;
- if (isPrimary) {
+ if (isSuperPrimary) {
entry.primaryIcon = R.drawable.ic_default_number;
}
mEmailEntries.add(entry);
@@ -790,8 +737,12 @@
}
}
}
+ // Load the photo
+ } else if (mimetype.equals(CommonDataKinds.Photo.CONTENT_ITEM_TYPE)) {
+ photoBitmap = ContactsUtils.loadContactPhoto(aggCursor, DATA_1_COLUMN, null);
}
+
// TODO(emillar) Add group entries
// // Build the group entries
// final Uri groupsUri = Uri.withAppendedPath(mUri, GroupMembership.CONTENT_DIRECTORY);
@@ -836,6 +787,11 @@
// }
}
+
+ if (photoBitmap == null) {
+ photoBitmap = ContactsUtils.loadPlaceholderPhoto(mNoPhotoResource, this, null);
+ }
+ mPhotoView.setImageBitmap(photoBitmap);
}
}
@@ -886,14 +842,6 @@
ViewEntry entry = getEntry(mSections, position, false);
View v;
- // Handle separators specially
- if (entry.kind == ViewEntry.KIND_SEPARATOR) {
- TextView separator = (TextView) mInflater.inflate(
- R.layout.list_separator, parent, SHOW_SEPARATORS);
- separator.setText(entry.data);
- return separator;
- }
-
ViewCache views;
// Check to see if we can reuse convertView