From 2c867f9b7f7e15da19fbd9642baa8b5278f274d0 Mon Sep 17 00:00:00 2001 From: Evan Millar Date: Tue, 15 Sep 2009 10:35:38 -0700 Subject: [PATCH] Fix a handful of bugs in the ContactHeaderWidget -http://b/issue?id=2074981 fixed -http://b/issue?id=2088564 fixed. -http://b/issue?id=2097374 fixed. -http://b/issue?id=2095896 fixed. -http://b/issue?id=2093734 fixed. -Use FasttrackBadgeWidget. -Also changes api in ContactsHeaderWidget to accept contact uri instead of contact id. Change-Id: I6623a99c7f5011387c57fc9a6861eef63174ca6e --- .../internal/widget/ContactHeaderWidget.java | 183 ++++++++++-------- .../res/drawable-hdpi/title_bar_medium.png | Bin 0 -> 427 bytes .../res/drawable-mdpi/title_bar_medium.png | Bin 0 -> 15032 bytes core/res/res/layout/contact_header.xml | 12 +- 4 files changed, 106 insertions(+), 89 deletions(-) create mode 100644 core/res/res/drawable-hdpi/title_bar_medium.png create mode 100644 core/res/res/drawable-mdpi/title_bar_medium.png diff --git a/core/java/com/android/internal/widget/ContactHeaderWidget.java b/core/java/com/android/internal/widget/ContactHeaderWidget.java index fe01866e42259..4ec597c6f0cbb 100644 --- a/core/java/com/android/internal/widget/ContactHeaderWidget.java +++ b/core/java/com/android/internal/widget/ContactHeaderWidget.java @@ -42,6 +42,7 @@ import android.util.AttributeSet; import android.view.LayoutInflater; import android.view.View; import android.widget.CheckBox; +import android.widget.FasttrackBadgeWidget; import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.TextView; @@ -64,15 +65,13 @@ public class ContactHeaderWidget extends FrameLayout implements View.OnClickList private TextView mDisplayNameView; private TextView mPhoneticNameView; private CheckBox mStarredView; - private ImageView mPhotoView; + private FasttrackBadgeWidget mPhotoView; private ImageView mPresenceView; private TextView mStatusView; private int mNoPhotoResource; private QueryHandler mQueryHandler; - protected long mContactId; protected Uri mContactUri; - protected Uri mStatusUri; protected String[] mExcludeMimes = null; @@ -94,6 +93,8 @@ public class ContactHeaderWidget extends FrameLayout implements View.OnClickList Contacts.STARRED, Contacts.PHOTO_ID, Contacts.PRESENCE_STATUS, + Contacts._ID, + Contacts.LOOKUP_KEY, }; protected static final int HEADER_DISPLAY_NAME_COLUMN_INDEX = 0; //TODO: We need to figure out how we're going to get the phonetic name. @@ -101,6 +102,8 @@ public class ContactHeaderWidget extends FrameLayout implements View.OnClickList protected static final int HEADER_STARRED_COLUMN_INDEX = 1; protected static final int HEADER_PHOTO_ID_COLUMN_INDEX = 2; protected static final int HEADER_PRESENCE_STATUS_COLUMN_INDEX = 3; + protected static final int HEADER_CONTACT_ID_COLUMN_INDEX = 4; + protected static final int HEADER_LOOKUP_KEY_COLUMN_INDEX = 5; //Projection used for finding the most recent social status. protected static final String[] SOCIAL_PROJECTION = new String[] { @@ -113,18 +116,29 @@ public class ContactHeaderWidget extends FrameLayout implements View.OnClickList //Projection used for looking up contact id from phone number protected static final String[] PHONE_LOOKUP_PROJECTION = new String[] { PhoneLookup._ID, + PhoneLookup.LOOKUP_KEY, }; protected static final int PHONE_LOOKUP_CONTACT_ID_COLUMN_INDEX = 0; + protected static final int PHONE_LOOKUP_CONTACT_LOOKUP_KEY_COLUMN_INDEX = 1; //Projection used for looking up contact id from email address protected static final String[] EMAIL_LOOKUP_PROJECTION = new String[] { RawContacts.CONTACT_ID, + Contacts.LOOKUP_KEY, }; protected static final int EMAIL_LOOKUP_CONTACT_ID_COLUMN_INDEX = 0; + protected static final int EMAIL_LOOKUP_CONTACT_LOOKUP_KEY_COLUMN_INDEX = 1; + protected static final String[] CONTACT_LOOKUP_PROJECTION = new String[] { + Contacts._ID, + }; + protected static final int CONTACT_LOOKUP_ID_COLUMN_INDEX = 0; private static final int TOKEN_CONTACT_INFO = 0; private static final int TOKEN_SOCIAL = 1; + private static final int TOKEN_PHONE_LOOKUP = 2; + private static final int TOKEN_EMAIL_LOOKUP = 3; + private static final int TOKEN_LOOKUP_CONTACT_FOR_SOCIAL_QUERY = 4; public ContactHeaderWidget(Context context) { this(context, null); @@ -151,8 +165,7 @@ public class ContactHeaderWidget extends FrameLayout implements View.OnClickList mStarredView = (CheckBox)findViewById(R.id.star); mStarredView.setOnClickListener(this); - mPhotoView = (ImageView)findViewById(R.id.photo); - mPhotoView.setOnClickListener(this); + mPhotoView = (FasttrackBadgeWidget) findViewById(R.id.photo); mPhotoView.setOnLongClickListener(this); mPresenceView = (ImageView) findViewById(R.id.presence); @@ -217,12 +230,46 @@ public class ContactHeaderWidget extends FrameLayout implements View.OnClickList @Override protected void onQueryComplete(int token, Object cookie, Cursor cursor) { try{ - if (token == TOKEN_CONTACT_INFO) { - bindContactInfo(cursor); - invalidate(); - } else if (token == TOKEN_SOCIAL) { - bindSocial(cursor); - invalidate(); + switch (token) { + case TOKEN_CONTACT_INFO: { + bindContactInfo(cursor); + invalidate(); + break; + } + case TOKEN_SOCIAL: { + bindSocial(cursor); + invalidate(); + break; + } + case TOKEN_PHONE_LOOKUP: { + if (cursor != null && cursor.moveToFirst()) { + long contactId = cursor.getLong(PHONE_LOOKUP_CONTACT_ID_COLUMN_INDEX); + String lookupKey = cursor.getString( + PHONE_LOOKUP_CONTACT_LOOKUP_KEY_COLUMN_INDEX); + bindFromContactUri(Contacts.getLookupUri(contactId, lookupKey)); + } else { + setDisplayName((String) cookie, null); + } + break; + } + case TOKEN_EMAIL_LOOKUP: { + if (cursor != null && cursor.moveToFirst()) { + long contactId = cursor.getLong(EMAIL_LOOKUP_CONTACT_ID_COLUMN_INDEX); + String lookupKey = cursor.getString( + EMAIL_LOOKUP_CONTACT_LOOKUP_KEY_COLUMN_INDEX); + bindFromContactUri(Contacts.getLookupUri(contactId, lookupKey)); + } else { + setDisplayName((String) cookie, null); + } + break; + } + case TOKEN_LOOKUP_CONTACT_FOR_SOCIAL_QUERY: { + if (cursor != null && cursor.moveToFirst()) { + long contactId = cursor.getLong(CONTACT_LOOKUP_ID_COLUMN_INDEX); + startSocialQuery(ContentUris.withAppendedId( + Activities.CONTENT_CONTACT_STATUS_URI, contactId)); + } + } } } finally { if (cursor != null) { @@ -300,33 +347,31 @@ public class ContactHeaderWidget extends FrameLayout implements View.OnClickList * Convenience method for binding all available data from an existing * contact. * - * @param contactId the contact id of the contact whose info should be displayed. + * @param conatctUri a {Contacts.CONTENT_LOOKUP_URI} style URI. */ - public void bindFromContactId(long contactId) { - mContactId = contactId; - mContactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, mContactId); + public void bindFromContactLookupUri(Uri contactLookupUri) { + mContactUri = contactLookupUri; - bindContactUri(mContactUri); - bindSocialUri(ContentUris.withAppendedId(Activities.CONTENT_CONTACT_STATUS_URI, mContactId)); + // Query for the contactId so we can do the social query. + mQueryHandler.startQuery(TOKEN_LOOKUP_CONTACT_FOR_SOCIAL_QUERY, null, contactLookupUri, + CONTACT_LOOKUP_PROJECTION, null, null, null); + + startContactQuery(contactLookupUri); } /** - * Convenience method for binding {@link Contacts} header details from a - * {@link Contacts#CONTENT_URI} reference. + * Convenience method for binding all available data from an existing + * contact. + * + * @param conatctUri a {Contacts.CONTENT_URI} style URI. */ - public void bindContactUri(Uri contactUri) { - mQueryHandler.startQuery(TOKEN_CONTACT_INFO, null, contactUri, HEADER_PROJECTION, - null, null, null); - } + public void bindFromContactUri(Uri contactUri) { + mContactUri = contactUri; + long contactId = ContentUris.parseId(contactUri); - /** - * Convenience method for binding {@link Activities} header details from a - * {@link Activities#CONTENT_CONTACT_STATUS_URI}. - */ - public void bindSocialUri(Uri contactSocial) { - mStatusUri = contactSocial; - mQueryHandler.startQuery(TOKEN_SOCIAL, null, mStatusUri, SOCIAL_PROJECTION, null, null, - null); + startContactQuery(contactUri); + startSocialQuery(ContentUris.withAppendedId( + Activities.CONTENT_CONTACT_STATUS_URI, contactId)); } /** @@ -338,21 +383,9 @@ public class ContactHeaderWidget extends FrameLayout implements View.OnClickList * address, one of them will be chosen to bind to. */ public void bindFromEmail(String emailAddress) { - Cursor c = null; - try { - c = mContentResolver.query(Uri.withAppendedPath(Email.CONTENT_FILTER_EMAIL_URI, Uri - .encode(emailAddress)), EMAIL_LOOKUP_PROJECTION, null, null, null); - if (c != null && c.moveToFirst()) { - long contactId = c.getLong(EMAIL_LOOKUP_CONTACT_ID_COLUMN_INDEX); - bindFromContactId(contactId); - } else { - setDisplayName(emailAddress, null); - } - } finally { - if (c != null) { - c.close(); - } - } + mQueryHandler.startQuery(TOKEN_EMAIL_LOOKUP, emailAddress, + Uri.withAppendedPath(Email.CONTENT_LOOKUP_URI, Uri.encode(emailAddress)), + EMAIL_LOOKUP_PROJECTION, null, null, null); } /** @@ -364,22 +397,19 @@ public class ContactHeaderWidget extends FrameLayout implements View.OnClickList * number, one of them will be chosen to bind to. */ public void bindFromPhoneNumber(String number) { - Cursor c = null; - try { - c = mContentResolver.query( - Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, Uri.encode(number)), - PHONE_LOOKUP_PROJECTION, null, null, null); - if (c != null && c.moveToFirst()) { - long contactId = c.getLong(PHONE_LOOKUP_CONTACT_ID_COLUMN_INDEX); - bindFromContactId(contactId); - } else { - setDisplayName(number, null); - } - } finally { - if (c != null) { - c.close(); - } - } + mQueryHandler.startQuery(TOKEN_PHONE_LOOKUP, number, + Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, number), + PHONE_LOOKUP_PROJECTION, null, null, null); + } + + private void startSocialQuery(Uri contactSocial) { + mQueryHandler.startQuery(TOKEN_SOCIAL, null, contactSocial, SOCIAL_PROJECTION, null, null, + null); + } + + private void startContactQuery(Uri contactUri) { + mQueryHandler.startQuery(TOKEN_CONTACT_INFO, null, contactUri, HEADER_PROJECTION, + null, null, null); } /** @@ -390,6 +420,8 @@ public class ContactHeaderWidget extends FrameLayout implements View.OnClickList // TODO: Bring back phonetic name final String displayName = c.getString(HEADER_DISPLAY_NAME_COLUMN_INDEX); + final long contactId = c.getLong(HEADER_CONTACT_ID_COLUMN_INDEX); + final String lookupKey = c.getString(HEADER_LOOKUP_KEY_COLUMN_INDEX); final String phoneticName = null; this.setDisplayName(displayName, null); @@ -402,6 +434,7 @@ public class ContactHeaderWidget extends FrameLayout implements View.OnClickList photoBitmap = loadPlaceholderPhoto(null); } mPhotoView.setImageBitmap(photoBitmap); + mPhotoView.assignContactUri(Contacts.getLookupUri(contactId, lookupKey)); //Set the presence status int presence = c.getInt(HEADER_PRESENCE_STATUS_COLUMN_INDEX); @@ -423,27 +456,11 @@ public class ContactHeaderWidget extends FrameLayout implements View.OnClickList return; } - switch (view.getId()) { - case R.id.star: { - // Toggle "starred" state - final ContentValues values = new ContentValues(1); - values.put(Contacts.STARRED, mStarredView.isChecked()); - mContentResolver.update(mContactUri, values, null, null); - break; - } - case R.id.photo: { - // Photo launches contact detail action - final Intent intent = new Intent(Intents.SHOW_OR_CREATE_CONTACT, mContactUri); - final Rect target = getTargetRect(view); - intent.putExtra(Intents.EXTRA_TARGET_RECT, target); - intent.putExtra(Intents.EXTRA_MODE, Intents.MODE_SMALL); - if (mExcludeMimes != null) { - // Exclude specific MIME-types when requested - intent.putExtra(Intents.EXTRA_EXCLUDE_MIMES, mExcludeMimes); - } - mContext.startActivity(intent); - break; - } + if (view.getId() == R.id.star) { + // Toggle "starred" state + final ContentValues values = new ContentValues(1); + values.put(Contacts.STARRED, mStarredView.isChecked()); + mContentResolver.update(mContactUri, values, null, null); } } diff --git a/core/res/res/drawable-hdpi/title_bar_medium.png b/core/res/res/drawable-hdpi/title_bar_medium.png new file mode 100644 index 0000000000000000000000000000000000000000..c13dd2698e5f9b33113da7ca584e21b2b9c2a928 GIT binary patch literal 427 zcmeAS@N?(olHy`uVBq!ia0y~yV0-{%CvY$UNv}e)bwEn8#5JNMI6tkVJh3R1!7(L2 zDOJHUH!(dmC^a#qvhZZ84N#Y_r;B4q#jQ6tHgX;?;Bh^uQSqPGWOeWkKf#WJ9_7j_ ze%Of2tYj>hcbk*poXN8}>lhX+U^KYEz$Voo`)2{8hzSFil!GI4!UD!wA0IIUTwu`1 zU|{8KXkvpfMNEK9pgd5N$AqCqj{)D2V)G4gChAxJk^%K-;wlgCFHff7J- zkkst?gv%13j*w?y9YEKyLX6@uabSel!ORPEAy9%%ih-H8p^**9l*oWEff|8K9uuG_ zj0sc*WPVsIC`iz|5*ZCldn|yCW{9_8;$b*-H)hh6D{XIqq0ivy>gTe~DWM4fX@-4; literal 0 HcmV?d00001 diff --git a/core/res/res/drawable-mdpi/title_bar_medium.png b/core/res/res/drawable-mdpi/title_bar_medium.png new file mode 100644 index 0000000000000000000000000000000000000000..9d01f79bb0de8652d3dcedc9f13c8189eef48d66 GIT binary patch literal 15032 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 O0000 - + style="@*android:style/Widget.FasttrackBadgeWidget.WindowSmall" /> + />