blob: 74b41c9611ed3af04f6f9b6c74e4d1df5c320ae8 [file] [log] [blame]
Evan Millare727f182009-08-27 11:15:55 -07001/*
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
17package android.widget;
18
Gilles Debunne92350582011-01-07 19:39:26 -080019import com.android.internal.R;
20
Evan Millare727f182009-08-27 11:15:55 -070021import android.content.AsyncQueryHandler;
22import android.content.ContentResolver;
23import android.content.Context;
24import android.content.Intent;
25import android.content.res.TypedArray;
26import android.database.Cursor;
Gilles Debunne92350582011-01-07 19:39:26 -080027import android.graphics.Canvas;
Mark Wagnerf5935a92009-09-22 13:49:26 -070028import android.graphics.drawable.Drawable;
Evan Millare727f182009-08-27 11:15:55 -070029import android.net.Uri;
Yorke Lee02f304f2013-01-14 08:57:43 -080030import android.os.Bundle;
Gilles Debunne92350582011-01-07 19:39:26 -080031import android.provider.ContactsContract.CommonDataKinds.Email;
Evan Millare727f182009-08-27 11:15:55 -070032import android.provider.ContactsContract.Contacts;
33import android.provider.ContactsContract.Intents;
34import android.provider.ContactsContract.PhoneLookup;
Tadashi G. Takaoka01fd4e12009-10-01 18:10:46 -070035import android.provider.ContactsContract.QuickContact;
Dmitri Plotnikovea367472009-09-18 15:04:58 -070036import android.provider.ContactsContract.RawContacts;
Evan Millare727f182009-08-27 11:15:55 -070037import android.util.AttributeSet;
38import android.view.View;
39import android.view.View.OnClickListener;
Svetoslav Ganov8a78fd42012-01-17 14:36:46 -080040import android.view.accessibility.AccessibilityEvent;
41import android.view.accessibility.AccessibilityNodeInfo;
Evan Millare727f182009-08-27 11:15:55 -070042
43/**
Evan Millarc1a2a822009-09-29 18:02:06 -070044 * Widget used to show an image with the standard QuickContact badge
Evan Millare727f182009-08-27 11:15:55 -070045 * and on-click behavior.
Evan Millare727f182009-08-27 11:15:55 -070046 */
Evan Millarc1a2a822009-09-29 18:02:06 -070047public class QuickContactBadge extends ImageView implements OnClickListener {
Evan Millare727f182009-08-27 11:15:55 -070048 private Uri mContactUri;
49 private String mContactEmail;
50 private String mContactPhone;
Gilles Debunne92350582011-01-07 19:39:26 -080051 private Drawable mOverlay;
Evan Millare727f182009-08-27 11:15:55 -070052 private QueryHandler mQueryHandler;
Evan Millar9a20aa72010-04-13 09:51:21 -070053 private Drawable mDefaultAvatar;
Yorke Lee02f304f2013-01-14 08:57:43 -080054 private Bundle mExtras = null;
Evan Millare727f182009-08-27 11:15:55 -070055
56 protected String[] mExcludeMimes = null;
57
58 static final private int TOKEN_EMAIL_LOOKUP = 0;
59 static final private int TOKEN_PHONE_LOOKUP = 1;
60 static final private int TOKEN_EMAIL_LOOKUP_AND_TRIGGER = 2;
61 static final private int TOKEN_PHONE_LOOKUP_AND_TRIGGER = 3;
62
Yorke Lee02f304f2013-01-14 08:57:43 -080063 static final private String EXTRA_URI_CONTENT = "uri_content";
64
Evan Millare727f182009-08-27 11:15:55 -070065 static final String[] EMAIL_LOOKUP_PROJECTION = new String[] {
Dmitri Plotnikovea367472009-09-18 15:04:58 -070066 RawContacts.CONTACT_ID,
Evan Millare727f182009-08-27 11:15:55 -070067 Contacts.LOOKUP_KEY,
68 };
Tadashi G. Takaoka01fd4e12009-10-01 18:10:46 -070069 static final int EMAIL_ID_COLUMN_INDEX = 0;
70 static final int EMAIL_LOOKUP_STRING_COLUMN_INDEX = 1;
Evan Millare727f182009-08-27 11:15:55 -070071
72 static final String[] PHONE_LOOKUP_PROJECTION = new String[] {
73 PhoneLookup._ID,
74 PhoneLookup.LOOKUP_KEY,
75 };
Tadashi G. Takaoka01fd4e12009-10-01 18:10:46 -070076 static final int PHONE_ID_COLUMN_INDEX = 0;
77 static final int PHONE_LOOKUP_STRING_COLUMN_INDEX = 1;
Evan Millare727f182009-08-27 11:15:55 -070078
Evan Millarc1a2a822009-09-29 18:02:06 -070079 public QuickContactBadge(Context context) {
Evan Millare727f182009-08-27 11:15:55 -070080 this(context, null);
81 }
82
Evan Millarc1a2a822009-09-29 18:02:06 -070083 public QuickContactBadge(Context context, AttributeSet attrs) {
Evan Millare727f182009-08-27 11:15:55 -070084 this(context, attrs, 0);
85 }
86
Alan Viverette617feb92013-09-09 18:09:13 -070087 public QuickContactBadge(Context context, AttributeSet attrs, int defStyleAttr) {
88 this(context, attrs, defStyleAttr, 0);
89 }
90
91 public QuickContactBadge(
92 Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
93 super(context, attrs, defStyleAttr, defStyleRes);
Evan Millare727f182009-08-27 11:15:55 -070094
Gilles Debunne92350582011-01-07 19:39:26 -080095 TypedArray styledAttributes = mContext.obtainStyledAttributes(R.styleable.Theme);
Daniel Lehmanne13e55b2011-08-07 19:51:28 -070096 mOverlay = styledAttributes.getDrawable(
97 com.android.internal.R.styleable.Theme_quickContactBadgeOverlay);
Gilles Debunne92350582011-01-07 19:39:26 -080098 styledAttributes.recycle();
99
Deepanshu Gupta34e9c692013-10-18 11:22:46 -0700100 if (!isInEditMode()) {
101 mQueryHandler = new QueryHandler(mContext.getContentResolver());
102 }
Daniel Lehmanne13e55b2011-08-07 19:51:28 -0700103 setOnClickListener(this);
Evan Millare727f182009-08-27 11:15:55 -0700104 }
105
Gilles Debunne5cba8622011-01-12 19:52:56 -0800106 @Override
107 protected void drawableStateChanged() {
108 super.drawableStateChanged();
Daniel Lehmanne13e55b2011-08-07 19:51:28 -0700109 if (mOverlay != null && mOverlay.isStateful()) {
110 mOverlay.setState(getDrawableState());
Gilles Debunne5cba8622011-01-12 19:52:56 -0800111 invalidate();
112 }
113 }
114
Daniel Lehmanne13e55b2011-08-07 19:51:28 -0700115 /** This call has no effect anymore, as there is only one QuickContact mode */
116 @SuppressWarnings("unused")
Evan Millare3ec9972009-09-30 19:37:36 -0700117 public void setMode(int size) {
Evan Millare3ec9972009-09-30 19:37:36 -0700118 }
Gilles Debunne92350582011-01-07 19:39:26 -0800119
120 @Override
121 protected void onDraw(Canvas canvas) {
122 super.onDraw(canvas);
123
Daniel Lehmanne13e55b2011-08-07 19:51:28 -0700124 if (!isEnabled()) {
125 // not clickable? don't show triangle
126 return;
127 }
128
Gilles Debunne5cba8622011-01-12 19:52:56 -0800129 if (mOverlay == null || mOverlay.getIntrinsicWidth() == 0 ||
130 mOverlay.getIntrinsicHeight() == 0) {
Daniel Lehmanne13e55b2011-08-07 19:51:28 -0700131 // nothing to draw
132 return;
Gilles Debunne92350582011-01-07 19:39:26 -0800133 }
134
135 mOverlay.setBounds(0, 0, getWidth(), getHeight());
136
137 if (mPaddingTop == 0 && mPaddingLeft == 0) {
138 mOverlay.draw(canvas);
139 } else {
140 int saveCount = canvas.getSaveCount();
141 canvas.save();
142 canvas.translate(mPaddingLeft, mPaddingTop);
143 mOverlay.draw(canvas);
144 canvas.restoreToCount(saveCount);
145 }
146 }
147
Daniel Lehmanne13e55b2011-08-07 19:51:28 -0700148 /** True if a contact, an email address or a phone number has been assigned */
149 private boolean isAssigned() {
150 return mContactUri != null || mContactEmail != null || mContactPhone != null;
151 }
152
Evan Millar9a20aa72010-04-13 09:51:21 -0700153 /**
154 * Resets the contact photo to the default state.
155 */
156 public void setImageToDefault() {
157 if (mDefaultAvatar == null) {
Alan Viverette8eea3ea2014-02-03 18:40:20 -0800158 mDefaultAvatar = mContext.getDrawable(R.drawable.ic_contact_picture);
Evan Millar9a20aa72010-04-13 09:51:21 -0700159 }
160 setImageDrawable(mDefaultAvatar);
161 }
Evan Millare3ec9972009-09-30 19:37:36 -0700162
163 /**
Evan Millarc1a2a822009-09-29 18:02:06 -0700164 * Assign the contact uri that this QuickContactBadge should be associated
165 * with. Note that this is only used for displaying the QuickContact window and
Gilles Debunne92350582011-01-07 19:39:26 -0800166 * won't bind the contact's photo for you. Call {@link #setImageDrawable(Drawable)} to set the
167 * photo.
Evan Millare727f182009-08-27 11:15:55 -0700168 *
Jeff Sharkey0050ee32009-09-17 16:11:32 -0700169 * @param contactUri Either a {@link Contacts#CONTENT_URI} or
170 * {@link Contacts#CONTENT_LOOKUP_URI} style URI.
Evan Millare727f182009-08-27 11:15:55 -0700171 */
172 public void assignContactUri(Uri contactUri) {
173 mContactUri = contactUri;
Mark Wagnerf5935a92009-09-22 13:49:26 -0700174 mContactEmail = null;
175 mContactPhone = null;
176 onContactUriChanged();
177 }
178
Evan Millare727f182009-08-27 11:15:55 -0700179 /**
180 * Assign a contact based on an email address. This should only be used when
181 * the contact's URI is not available, as an extra query will have to be
182 * performed to lookup the URI based on the email.
183 *
184 * @param emailAddress The email address of the contact.
185 * @param lazyLookup If this is true, the lookup query will not be performed
186 * until this view is clicked.
187 */
188 public void assignContactFromEmail(String emailAddress, boolean lazyLookup) {
Yorke Lee02f304f2013-01-14 08:57:43 -0800189 assignContactFromEmail(emailAddress, lazyLookup, null);
190 }
191
192 /**
193 * Assign a contact based on an email address. This should only be used when
194 * the contact's URI is not available, as an extra query will have to be
195 * performed to lookup the URI based on the email.
196
197 @param emailAddress The email address of the contact.
198 @param lazyLookup If this is true, the lookup query will not be performed
199 until this view is clicked.
200 @param extras A bundle of extras to populate the contact edit page with if the contact
201 is not found and the user chooses to add the email address to an existing contact or
202 create a new contact. Uses the same string constants as those found in
Yorke Lee3e839f42013-01-15 16:46:00 -0800203 {@link android.provider.ContactsContract.Intents.Insert}
Yorke Lee02f304f2013-01-14 08:57:43 -0800204 */
205
206 public void assignContactFromEmail(String emailAddress, boolean lazyLookup, Bundle extras) {
Evan Millare727f182009-08-27 11:15:55 -0700207 mContactEmail = emailAddress;
Yorke Lee02f304f2013-01-14 08:57:43 -0800208 mExtras = extras;
Deepanshu Gupta34e9c692013-10-18 11:22:46 -0700209 if (!lazyLookup && mQueryHandler != null) {
Evan Millare727f182009-08-27 11:15:55 -0700210 mQueryHandler.startQuery(TOKEN_EMAIL_LOOKUP, null,
211 Uri.withAppendedPath(Email.CONTENT_LOOKUP_URI, Uri.encode(mContactEmail)),
212 EMAIL_LOOKUP_PROJECTION, null, null, null);
Jeff Sharkey0050ee32009-09-17 16:11:32 -0700213 } else {
214 mContactUri = null;
Mark Wagnerf5935a92009-09-22 13:49:26 -0700215 onContactUriChanged();
Evan Millare727f182009-08-27 11:15:55 -0700216 }
217 }
218
Yorke Lee02f304f2013-01-14 08:57:43 -0800219
Evan Millare727f182009-08-27 11:15:55 -0700220 /**
221 * Assign a contact based on a phone number. This should only be used when
222 * the contact's URI is not available, as an extra query will have to be
223 * performed to lookup the URI based on the phone number.
224 *
225 * @param phoneNumber The phone number of the contact.
226 * @param lazyLookup If this is true, the lookup query will not be performed
227 * until this view is clicked.
228 */
229 public void assignContactFromPhone(String phoneNumber, boolean lazyLookup) {
Yorke Lee02f304f2013-01-14 08:57:43 -0800230 assignContactFromPhone(phoneNumber, lazyLookup, new Bundle());
231 }
232
233 /**
234 * Assign a contact based on a phone number. This should only be used when
235 * the contact's URI is not available, as an extra query will have to be
236 * performed to lookup the URI based on the phone number.
237 *
238 * @param phoneNumber The phone number of the contact.
239 * @param lazyLookup If this is true, the lookup query will not be performed
240 * until this view is clicked.
241 * @param extras A bundle of extras to populate the contact edit page with if the contact
242 * is not found and the user chooses to add the phone number to an existing contact or
243 * create a new contact. Uses the same string constants as those found in
Yorke Lee3e839f42013-01-15 16:46:00 -0800244 * {@link android.provider.ContactsContract.Intents.Insert}
Yorke Lee02f304f2013-01-14 08:57:43 -0800245 */
246 public void assignContactFromPhone(String phoneNumber, boolean lazyLookup, Bundle extras) {
Evan Millare727f182009-08-27 11:15:55 -0700247 mContactPhone = phoneNumber;
Yorke Lee02f304f2013-01-14 08:57:43 -0800248 mExtras = extras;
Deepanshu Gupta34e9c692013-10-18 11:22:46 -0700249 if (!lazyLookup && mQueryHandler != null) {
Evan Millare727f182009-08-27 11:15:55 -0700250 mQueryHandler.startQuery(TOKEN_PHONE_LOOKUP, null,
251 Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, mContactPhone),
252 PHONE_LOOKUP_PROJECTION, null, null, null);
Jeff Sharkey0050ee32009-09-17 16:11:32 -0700253 } else {
254 mContactUri = null;
Mark Wagnerf5935a92009-09-22 13:49:26 -0700255 onContactUriChanged();
Evan Millare727f182009-08-27 11:15:55 -0700256 }
257 }
258
Daniel Lehmanne13e55b2011-08-07 19:51:28 -0700259 private void onContactUriChanged() {
260 setEnabled(isAssigned());
261 }
262
263 @Override
Evan Millare727f182009-08-27 11:15:55 -0700264 public void onClick(View v) {
Yorke Lee02f304f2013-01-14 08:57:43 -0800265 // If contact has been assigned, mExtras should no longer be null, but do a null check
266 // anyway just in case assignContactFromPhone or Email was called with a null bundle or
267 // wasn't assigned previously.
268 final Bundle extras = (mExtras == null) ? new Bundle() : mExtras;
Evan Millare727f182009-08-27 11:15:55 -0700269 if (mContactUri != null) {
Daniel Lehmanne13e55b2011-08-07 19:51:28 -0700270 QuickContact.showQuickContact(getContext(), QuickContactBadge.this, mContactUri,
271 QuickContact.MODE_LARGE, mExcludeMimes);
Deepanshu Gupta34e9c692013-10-18 11:22:46 -0700272 } else if (mContactEmail != null && mQueryHandler != null) {
Yorke Lee02f304f2013-01-14 08:57:43 -0800273 extras.putString(EXTRA_URI_CONTENT, mContactEmail);
274 mQueryHandler.startQuery(TOKEN_EMAIL_LOOKUP_AND_TRIGGER, extras,
Evan Millare727f182009-08-27 11:15:55 -0700275 Uri.withAppendedPath(Email.CONTENT_LOOKUP_URI, Uri.encode(mContactEmail)),
276 EMAIL_LOOKUP_PROJECTION, null, null, null);
Deepanshu Gupta34e9c692013-10-18 11:22:46 -0700277 } else if (mContactPhone != null && mQueryHandler != null) {
Yorke Lee02f304f2013-01-14 08:57:43 -0800278 extras.putString(EXTRA_URI_CONTENT, mContactPhone);
279 mQueryHandler.startQuery(TOKEN_PHONE_LOOKUP_AND_TRIGGER, extras,
Evan Millare727f182009-08-27 11:15:55 -0700280 Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, mContactPhone),
281 PHONE_LOOKUP_PROJECTION, null, null, null);
282 } else {
283 // If a contact hasn't been assigned, don't react to click.
284 return;
285 }
286 }
287
Svetoslav Ganov8a78fd42012-01-17 14:36:46 -0800288 @Override
289 public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
290 super.onInitializeAccessibilityEvent(event);
291 event.setClassName(QuickContactBadge.class.getName());
292 }
293
294 @Override
295 public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
296 super.onInitializeAccessibilityNodeInfo(info);
297 info.setClassName(QuickContactBadge.class.getName());
298 }
299
Evan Millare727f182009-08-27 11:15:55 -0700300 /**
301 * Set a list of specific MIME-types to exclude and not display. For
302 * example, this can be used to hide the {@link Contacts#CONTENT_ITEM_TYPE}
303 * profile icon.
304 */
305 public void setExcludeMimes(String[] excludeMimes) {
306 mExcludeMimes = excludeMimes;
307 }
308
Evan Millare727f182009-08-27 11:15:55 -0700309 private class QueryHandler extends AsyncQueryHandler {
310
311 public QueryHandler(ContentResolver cr) {
312 super(cr);
313 }
314
315 @Override
316 protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
Jeff Sharkey0050ee32009-09-17 16:11:32 -0700317 Uri lookupUri = null;
318 Uri createUri = null;
Evan Millare727f182009-08-27 11:15:55 -0700319 boolean trigger = false;
Yorke Lee02f304f2013-01-14 08:57:43 -0800320 Bundle extras = (cookie != null) ? (Bundle) cookie : new Bundle();
Jeff Sharkey0050ee32009-09-17 16:11:32 -0700321 try {
Evan Millare727f182009-08-27 11:15:55 -0700322 switch(token) {
323 case TOKEN_PHONE_LOOKUP_AND_TRIGGER:
324 trigger = true;
Yorke Lee02f304f2013-01-14 08:57:43 -0800325 createUri = Uri.fromParts("tel", extras.getString(EXTRA_URI_CONTENT), null);
Jeff Sharkey0050ee32009-09-17 16:11:32 -0700326
Makoto Onukia362e1d2010-09-07 10:46:59 -0700327 //$FALL-THROUGH$
Evan Millare727f182009-08-27 11:15:55 -0700328 case TOKEN_PHONE_LOOKUP: {
329 if (cursor != null && cursor.moveToFirst()) {
330 long contactId = cursor.getLong(PHONE_ID_COLUMN_INDEX);
331 String lookupKey = cursor.getString(PHONE_LOOKUP_STRING_COLUMN_INDEX);
Jeff Sharkey0050ee32009-09-17 16:11:32 -0700332 lookupUri = Contacts.getLookupUri(contactId, lookupKey);
Evan Millare727f182009-08-27 11:15:55 -0700333 }
Jeff Sharkey0050ee32009-09-17 16:11:32 -0700334
Evan Millare727f182009-08-27 11:15:55 -0700335 break;
336 }
337 case TOKEN_EMAIL_LOOKUP_AND_TRIGGER:
338 trigger = true;
Yorke Lee02f304f2013-01-14 08:57:43 -0800339 createUri = Uri.fromParts("mailto",
340 extras.getString(EXTRA_URI_CONTENT), null);
Jeff Sharkey0050ee32009-09-17 16:11:32 -0700341
Makoto Onukia362e1d2010-09-07 10:46:59 -0700342 //$FALL-THROUGH$
Evan Millare727f182009-08-27 11:15:55 -0700343 case TOKEN_EMAIL_LOOKUP: {
344 if (cursor != null && cursor.moveToFirst()) {
345 long contactId = cursor.getLong(EMAIL_ID_COLUMN_INDEX);
346 String lookupKey = cursor.getString(EMAIL_LOOKUP_STRING_COLUMN_INDEX);
Jeff Sharkey0050ee32009-09-17 16:11:32 -0700347 lookupUri = Contacts.getLookupUri(contactId, lookupKey);
Evan Millare727f182009-08-27 11:15:55 -0700348 }
Makoto Onukia362e1d2010-09-07 10:46:59 -0700349 break;
Evan Millare727f182009-08-27 11:15:55 -0700350 }
351 }
352 } finally {
353 if (cursor != null) {
354 cursor.close();
355 }
356 }
357
Jeff Sharkey0050ee32009-09-17 16:11:32 -0700358 mContactUri = lookupUri;
Mark Wagnerf5935a92009-09-22 13:49:26 -0700359 onContactUriChanged();
Jeff Sharkey0050ee32009-09-17 16:11:32 -0700360
361 if (trigger && lookupUri != null) {
Daniel Lehmanne13e55b2011-08-07 19:51:28 -0700362 // Found contact, so trigger QuickContact
363 QuickContact.showQuickContact(getContext(), QuickContactBadge.this, lookupUri,
364 QuickContact.MODE_LARGE, mExcludeMimes);
Jeff Sharkey0050ee32009-09-17 16:11:32 -0700365 } else if (createUri != null) {
366 // Prompt user to add this person to contacts
367 final Intent intent = new Intent(Intents.SHOW_OR_CREATE_CONTACT, createUri);
Yorke Lee02f304f2013-01-14 08:57:43 -0800368 if (extras != null) {
369 extras.remove(EXTRA_URI_CONTENT);
370 intent.putExtras(extras);
371 }
Jeff Sharkey0050ee32009-09-17 16:11:32 -0700372 getContext().startActivity(intent);
Evan Millare727f182009-08-27 11:15:55 -0700373 }
374 }
375 }
376}