1 /* 2 * Copyright (C) 2009 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.widget; 18 19 import android.content.AsyncQueryHandler; 20 import android.content.ContentResolver; 21 import android.content.Context; 22 import android.content.Intent; 23 import android.content.res.TypedArray; 24 import android.database.Cursor; 25 import android.graphics.drawable.Drawable; 26 import android.net.Uri; 27 import android.provider.ContactsContract.Contacts; 28 import android.provider.ContactsContract.Intents; 29 import android.provider.ContactsContract.PhoneLookup; 30 import android.provider.ContactsContract.QuickContact; 31 import android.provider.ContactsContract.RawContacts; 32 import android.provider.ContactsContract.CommonDataKinds.Email; 33 import android.util.AttributeSet; 34 import android.view.View; 35 import android.view.View.OnClickListener; 36 import com.android.internal.R; 37 38 /** 39 * Widget used to show an image with the standard QuickContact badge 40 * and on-click behavior. 41 */ 42 public class QuickContactBadge extends ImageView implements OnClickListener { 43 44 private Uri mContactUri; 45 private String mContactEmail; 46 private String mContactPhone; 47 private int mMode; 48 private QueryHandler mQueryHandler; 49 private Drawable mBadgeBackground; 50 private Drawable mNoBadgeBackground; 51 private int mSelectedContactsAppTabIndex = -1; 52 53 protected String[] mExcludeMimes = null; 54 55 static final private int TOKEN_EMAIL_LOOKUP = 0; 56 static final private int TOKEN_PHONE_LOOKUP = 1; 57 static final private int TOKEN_EMAIL_LOOKUP_AND_TRIGGER = 2; 58 static final private int TOKEN_PHONE_LOOKUP_AND_TRIGGER = 3; 59 static final private int TOKEN_CONTACT_LOOKUP_AND_TRIGGER = 4; 60 61 static final String[] EMAIL_LOOKUP_PROJECTION = new String[] { 62 RawContacts.CONTACT_ID, 63 Contacts.LOOKUP_KEY, 64 }; 65 static final int EMAIL_ID_COLUMN_INDEX = 0; 66 static final int EMAIL_LOOKUP_STRING_COLUMN_INDEX = 1; 67 68 static final String[] PHONE_LOOKUP_PROJECTION = new String[] { 69 PhoneLookup._ID, 70 PhoneLookup.LOOKUP_KEY, 71 }; 72 static final int PHONE_ID_COLUMN_INDEX = 0; 73 static final int PHONE_LOOKUP_STRING_COLUMN_INDEX = 1; 74 75 static final String[] CONTACT_LOOKUP_PROJECTION = new String[] { 76 Contacts._ID, 77 Contacts.LOOKUP_KEY, 78 }; 79 static final int CONTACT_ID_COLUMN_INDEX = 0; 80 static final int CONTACT_LOOKUPKEY_COLUMN_INDEX = 1; 81 82 83 public QuickContactBadge(Context context) { 84 this(context, null); 85 } 86 87 public QuickContactBadge(Context context, AttributeSet attrs) { 88 this(context, attrs, 0); 89 } 90 91 public QuickContactBadge(Context context, AttributeSet attrs, int defStyle) { 92 super(context, attrs, defStyle); 93 94 TypedArray a = 95 context.obtainStyledAttributes(attrs, 96 com.android.internal.R.styleable.QuickContactBadge, defStyle, 0); 97 98 mMode = a.getInt(com.android.internal.R.styleable.QuickContactBadge_quickContactWindowSize, 99 QuickContact.MODE_MEDIUM); 100 101 a.recycle(); 102 103 init(); 104 105 mBadgeBackground = getBackground(); 106 } 107 108 private void init() { 109 mQueryHandler = new QueryHandler(mContext.getContentResolver()); 110 setOnClickListener(this); 111 } 112 113 /** 114 * Set the QuickContact window mode. Options are {@link QuickContact#MODE_SMALL}, 115 * {@link QuickContact#MODE_MEDIUM}, {@link QuickContact#MODE_LARGE}. 116 * @param size 117 */ 118 public void setMode(int size) { 119 mMode = size; 120 } 121 122 /** 123 * Assign the contact uri that this QuickContactBadge should be associated 124 * with. Note that this is only used for displaying the QuickContact window and 125 * won't bind the contact's photo for you. 126 * 127 * @param contactUri Either a {@link Contacts#CONTENT_URI} or 128 * {@link Contacts#CONTENT_LOOKUP_URI} style URI. 129 */ 130 public void assignContactUri(Uri contactUri) { 131 mContactUri = contactUri; 132 mContactEmail = null; 133 mContactPhone = null; 134 onContactUriChanged(); 135 } 136 137 /** 138 * Sets the currently selected tab of the Contacts application. If not set, this is -1 139 * and therefore does not save a tab selection when a phone call is being made 140 * @hide 141 */ 142 public void setSelectedContactsAppTabIndex(int value) { 143 mSelectedContactsAppTabIndex = value; 144 } 145 146 private void onContactUriChanged() { 147 if (mContactUri == null && mContactEmail == null && mContactPhone == null) { 148 if (mNoBadgeBackground == null) { 149 mNoBadgeBackground = getResources().getDrawable(R.drawable.quickcontact_nobadge); 150 } 151 setBackgroundDrawable(mNoBadgeBackground); 152 } else { 153 setBackgroundDrawable(mBadgeBackground); 154 } 155 } 156 157 /** 158 * Assign a contact based on an email address. This should only be used when 159 * the contact's URI is not available, as an extra query will have to be 160 * performed to lookup the URI based on the email. 161 * 162 * @param emailAddress The email address of the contact. 163 * @param lazyLookup If this is true, the lookup query will not be performed 164 * until this view is clicked. 165 */ 166 public void assignContactFromEmail(String emailAddress, boolean lazyLookup) { 167 mContactEmail = emailAddress; 168 if (!lazyLookup) { 169 mQueryHandler.startQuery(TOKEN_EMAIL_LOOKUP, null, 170 Uri.withAppendedPath(Email.CONTENT_LOOKUP_URI, Uri.encode(mContactEmail)), 171 EMAIL_LOOKUP_PROJECTION, null, null, null); 172 } else { 173 mContactUri = null; 174 onContactUriChanged(); 175 } 176 } 177 178 /** 179 * Assign a contact based on a phone number. This should only be used when 180 * the contact's URI is not available, as an extra query will have to be 181 * performed to lookup the URI based on the phone number. 182 * 183 * @param phoneNumber The phone number of the contact. 184 * @param lazyLookup If this is true, the lookup query will not be performed 185 * until this view is clicked. 186 */ 187 public void assignContactFromPhone(String phoneNumber, boolean lazyLookup) { 188 mContactPhone = phoneNumber; 189 if (!lazyLookup) { 190 mQueryHandler.startQuery(TOKEN_PHONE_LOOKUP, null, 191 Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, mContactPhone), 192 PHONE_LOOKUP_PROJECTION, null, null, null); 193 } else { 194 mContactUri = null; 195 onContactUriChanged(); 196 } 197 } 198 199 public void onClick(View v) { 200 if (mContactUri != null) { 201 mQueryHandler.startQuery(TOKEN_CONTACT_LOOKUP_AND_TRIGGER, null, 202 mContactUri, 203 CONTACT_LOOKUP_PROJECTION, null, null, null); 204 } else if (mContactEmail != null) { 205 mQueryHandler.startQuery(TOKEN_EMAIL_LOOKUP_AND_TRIGGER, mContactEmail, 206 Uri.withAppendedPath(Email.CONTENT_LOOKUP_URI, Uri.encode(mContactEmail)), 207 EMAIL_LOOKUP_PROJECTION, null, null, null); 208 } else if (mContactPhone != null) { 209 mQueryHandler.startQuery(TOKEN_PHONE_LOOKUP_AND_TRIGGER, mContactPhone, 210 Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, mContactPhone), 211 PHONE_LOOKUP_PROJECTION, null, null, null); 212 } else { 213 // If a contact hasn't been assigned, don't react to click. 214 return; 215 } 216 } 217 218 /** 219 * Set a list of specific MIME-types to exclude and not display. For 220 * example, this can be used to hide the {@link Contacts#CONTENT_ITEM_TYPE} 221 * profile icon. 222 */ 223 public void setExcludeMimes(String[] excludeMimes) { 224 mExcludeMimes = excludeMimes; 225 } 226 227 private void trigger(Uri lookupUri) { 228 final Intent intent = QuickContact.getQuickContactIntent(getContext(), this, lookupUri, 229 mMode, mExcludeMimes); 230 if (mSelectedContactsAppTabIndex != -1) { 231 intent.putExtra(QuickContact.EXTRA_SELECTED_CONTACTS_APP_TAB_INDEX, 232 mSelectedContactsAppTabIndex); 233 } 234 getContext().startActivity(intent); 235 } 236 237 private class QueryHandler extends AsyncQueryHandler { 238 239 public QueryHandler(ContentResolver cr) { 240 super(cr); 241 } 242 243 @Override 244 protected void onQueryComplete(int token, Object cookie, Cursor cursor) { 245 Uri lookupUri = null; 246 Uri createUri = null; 247 boolean trigger = false; 248 249 try { 250 switch(token) { 251 case TOKEN_PHONE_LOOKUP_AND_TRIGGER: 252 trigger = true; 253 createUri = Uri.fromParts("tel", (String)cookie, null); 254 255 //$FALL-THROUGH$ 256 case TOKEN_PHONE_LOOKUP: { 257 if (cursor != null && cursor.moveToFirst()) { 258 long contactId = cursor.getLong(PHONE_ID_COLUMN_INDEX); 259 String lookupKey = cursor.getString(PHONE_LOOKUP_STRING_COLUMN_INDEX); 260 lookupUri = Contacts.getLookupUri(contactId, lookupKey); 261 } 262 263 break; 264 } 265 case TOKEN_EMAIL_LOOKUP_AND_TRIGGER: 266 trigger = true; 267 createUri = Uri.fromParts("mailto", (String)cookie, null); 268 269 //$FALL-THROUGH$ 270 case TOKEN_EMAIL_LOOKUP: { 271 if (cursor != null && cursor.moveToFirst()) { 272 long contactId = cursor.getLong(EMAIL_ID_COLUMN_INDEX); 273 String lookupKey = cursor.getString(EMAIL_LOOKUP_STRING_COLUMN_INDEX); 274 lookupUri = Contacts.getLookupUri(contactId, lookupKey); 275 } 276 break; 277 } 278 279 case TOKEN_CONTACT_LOOKUP_AND_TRIGGER: { 280 if (cursor != null && cursor.moveToFirst()) { 281 long contactId = cursor.getLong(CONTACT_ID_COLUMN_INDEX); 282 String lookupKey = cursor.getString(CONTACT_LOOKUPKEY_COLUMN_INDEX); 283 lookupUri = Contacts.getLookupUri(contactId, lookupKey); 284 trigger = true; 285 } 286 287 break; 288 } 289 } 290 } finally { 291 if (cursor != null) { 292 cursor.close(); 293 } 294 } 295 296 mContactUri = lookupUri; 297 onContactUriChanged(); 298 299 if (trigger && lookupUri != null) { 300 // Found contact, so trigger track 301 trigger(lookupUri); 302 } else if (createUri != null) { 303 // Prompt user to add this person to contacts 304 final Intent intent = new Intent(Intents.SHOW_OR_CREATE_CONTACT, createUri); 305 getContext().startActivity(intent); 306 } 307 } 308 } 309 } 310