• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 com.android.internal.R;
20 
21 import android.content.AsyncQueryHandler;
22 import android.content.ContentResolver;
23 import android.content.Context;
24 import android.content.Intent;
25 import android.content.res.TypedArray;
26 import android.database.Cursor;
27 import android.graphics.Canvas;
28 import android.graphics.drawable.Drawable;
29 import android.net.Uri;
30 import android.provider.ContactsContract.CommonDataKinds.Email;
31 import android.provider.ContactsContract.Contacts;
32 import android.provider.ContactsContract.Intents;
33 import android.provider.ContactsContract.PhoneLookup;
34 import android.provider.ContactsContract.QuickContact;
35 import android.provider.ContactsContract.RawContacts;
36 import android.util.AttributeSet;
37 import android.view.View;
38 import android.view.View.OnClickListener;
39 import android.view.accessibility.AccessibilityEvent;
40 import android.view.accessibility.AccessibilityNodeInfo;
41 
42 /**
43  * Widget used to show an image with the standard QuickContact badge
44  * and on-click behavior.
45  */
46 public class QuickContactBadge extends ImageView implements OnClickListener {
47     private Uri mContactUri;
48     private String mContactEmail;
49     private String mContactPhone;
50     private Drawable mOverlay;
51     private QueryHandler mQueryHandler;
52     private Drawable mDefaultAvatar;
53 
54     protected String[] mExcludeMimes = null;
55 
56     static final private int TOKEN_EMAIL_LOOKUP = 0;
57     static final private int TOKEN_PHONE_LOOKUP = 1;
58     static final private int TOKEN_EMAIL_LOOKUP_AND_TRIGGER = 2;
59     static final private int TOKEN_PHONE_LOOKUP_AND_TRIGGER = 3;
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 
QuickContactBadge(Context context)75     public QuickContactBadge(Context context) {
76         this(context, null);
77     }
78 
QuickContactBadge(Context context, AttributeSet attrs)79     public QuickContactBadge(Context context, AttributeSet attrs) {
80         this(context, attrs, 0);
81     }
82 
QuickContactBadge(Context context, AttributeSet attrs, int defStyle)83     public QuickContactBadge(Context context, AttributeSet attrs, int defStyle) {
84         super(context, attrs, defStyle);
85 
86         TypedArray styledAttributes = mContext.obtainStyledAttributes(R.styleable.Theme);
87         mOverlay = styledAttributes.getDrawable(
88                 com.android.internal.R.styleable.Theme_quickContactBadgeOverlay);
89         styledAttributes.recycle();
90 
91         mQueryHandler = new QueryHandler(mContext.getContentResolver());
92         setOnClickListener(this);
93     }
94 
95     @Override
drawableStateChanged()96     protected void drawableStateChanged() {
97         super.drawableStateChanged();
98         if (mOverlay != null && mOverlay.isStateful()) {
99             mOverlay.setState(getDrawableState());
100             invalidate();
101         }
102     }
103 
104     /** This call has no effect anymore, as there is only one QuickContact mode */
105     @SuppressWarnings("unused")
setMode(int size)106     public void setMode(int size) {
107     }
108 
109     @Override
onDraw(Canvas canvas)110     protected void onDraw(Canvas canvas) {
111         super.onDraw(canvas);
112 
113         if (!isEnabled()) {
114             // not clickable? don't show triangle
115             return;
116         }
117 
118         if (mOverlay == null || mOverlay.getIntrinsicWidth() == 0 ||
119                 mOverlay.getIntrinsicHeight() == 0) {
120             // nothing to draw
121             return;
122         }
123 
124         mOverlay.setBounds(0, 0, getWidth(), getHeight());
125 
126         if (mPaddingTop == 0 && mPaddingLeft == 0) {
127             mOverlay.draw(canvas);
128         } else {
129             int saveCount = canvas.getSaveCount();
130             canvas.save();
131             canvas.translate(mPaddingLeft, mPaddingTop);
132             mOverlay.draw(canvas);
133             canvas.restoreToCount(saveCount);
134         }
135     }
136 
137     /** True if a contact, an email address or a phone number has been assigned */
isAssigned()138     private boolean isAssigned() {
139         return mContactUri != null || mContactEmail != null || mContactPhone != null;
140     }
141 
142     /**
143      * Resets the contact photo to the default state.
144      */
setImageToDefault()145     public void setImageToDefault() {
146         if (mDefaultAvatar == null) {
147             mDefaultAvatar = getResources().getDrawable(R.drawable.ic_contact_picture);
148         }
149         setImageDrawable(mDefaultAvatar);
150     }
151 
152     /**
153      * Assign the contact uri that this QuickContactBadge should be associated
154      * with. Note that this is only used for displaying the QuickContact window and
155      * won't bind the contact's photo for you. Call {@link #setImageDrawable(Drawable)} to set the
156      * photo.
157      *
158      * @param contactUri Either a {@link Contacts#CONTENT_URI} or
159      *            {@link Contacts#CONTENT_LOOKUP_URI} style URI.
160      */
assignContactUri(Uri contactUri)161     public void assignContactUri(Uri contactUri) {
162         mContactUri = contactUri;
163         mContactEmail = null;
164         mContactPhone = null;
165         onContactUriChanged();
166     }
167 
168     /**
169      * Assign a contact based on an email address. This should only be used when
170      * the contact's URI is not available, as an extra query will have to be
171      * performed to lookup the URI based on the email.
172      *
173      * @param emailAddress The email address of the contact.
174      * @param lazyLookup If this is true, the lookup query will not be performed
175      * until this view is clicked.
176      */
assignContactFromEmail(String emailAddress, boolean lazyLookup)177     public void assignContactFromEmail(String emailAddress, boolean lazyLookup) {
178         mContactEmail = emailAddress;
179         if (!lazyLookup) {
180             mQueryHandler.startQuery(TOKEN_EMAIL_LOOKUP, null,
181                     Uri.withAppendedPath(Email.CONTENT_LOOKUP_URI, Uri.encode(mContactEmail)),
182                     EMAIL_LOOKUP_PROJECTION, null, null, null);
183         } else {
184             mContactUri = null;
185             onContactUriChanged();
186         }
187     }
188 
189     /**
190      * Assign a contact based on a phone number. This should only be used when
191      * the contact's URI is not available, as an extra query will have to be
192      * performed to lookup the URI based on the phone number.
193      *
194      * @param phoneNumber The phone number of the contact.
195      * @param lazyLookup If this is true, the lookup query will not be performed
196      * until this view is clicked.
197      */
assignContactFromPhone(String phoneNumber, boolean lazyLookup)198     public void assignContactFromPhone(String phoneNumber, boolean lazyLookup) {
199         mContactPhone = phoneNumber;
200         if (!lazyLookup) {
201             mQueryHandler.startQuery(TOKEN_PHONE_LOOKUP, null,
202                     Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, mContactPhone),
203                     PHONE_LOOKUP_PROJECTION, null, null, null);
204         } else {
205             mContactUri = null;
206             onContactUriChanged();
207         }
208     }
209 
onContactUriChanged()210     private void onContactUriChanged() {
211         setEnabled(isAssigned());
212     }
213 
214     @Override
onClick(View v)215     public void onClick(View v) {
216         if (mContactUri != null) {
217             QuickContact.showQuickContact(getContext(), QuickContactBadge.this, mContactUri,
218                     QuickContact.MODE_LARGE, mExcludeMimes);
219         } else if (mContactEmail != null) {
220             mQueryHandler.startQuery(TOKEN_EMAIL_LOOKUP_AND_TRIGGER, mContactEmail,
221                     Uri.withAppendedPath(Email.CONTENT_LOOKUP_URI, Uri.encode(mContactEmail)),
222                     EMAIL_LOOKUP_PROJECTION, null, null, null);
223         } else if (mContactPhone != null) {
224             mQueryHandler.startQuery(TOKEN_PHONE_LOOKUP_AND_TRIGGER, mContactPhone,
225                     Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, mContactPhone),
226                     PHONE_LOOKUP_PROJECTION, null, null, null);
227         } else {
228             // If a contact hasn't been assigned, don't react to click.
229             return;
230         }
231     }
232 
233     @Override
onInitializeAccessibilityEvent(AccessibilityEvent event)234     public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
235         super.onInitializeAccessibilityEvent(event);
236         event.setClassName(QuickContactBadge.class.getName());
237     }
238 
239     @Override
onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info)240     public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
241         super.onInitializeAccessibilityNodeInfo(info);
242         info.setClassName(QuickContactBadge.class.getName());
243     }
244 
245     /**
246      * Set a list of specific MIME-types to exclude and not display. For
247      * example, this can be used to hide the {@link Contacts#CONTENT_ITEM_TYPE}
248      * profile icon.
249      */
setExcludeMimes(String[] excludeMimes)250     public void setExcludeMimes(String[] excludeMimes) {
251         mExcludeMimes = excludeMimes;
252     }
253 
254     private class QueryHandler extends AsyncQueryHandler {
255 
QueryHandler(ContentResolver cr)256         public QueryHandler(ContentResolver cr) {
257             super(cr);
258         }
259 
260         @Override
onQueryComplete(int token, Object cookie, Cursor cursor)261         protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
262             Uri lookupUri = null;
263             Uri createUri = null;
264             boolean trigger = false;
265 
266             try {
267                 switch(token) {
268                     case TOKEN_PHONE_LOOKUP_AND_TRIGGER:
269                         trigger = true;
270                         createUri = Uri.fromParts("tel", (String)cookie, null);
271 
272                         //$FALL-THROUGH$
273                     case TOKEN_PHONE_LOOKUP: {
274                         if (cursor != null && cursor.moveToFirst()) {
275                             long contactId = cursor.getLong(PHONE_ID_COLUMN_INDEX);
276                             String lookupKey = cursor.getString(PHONE_LOOKUP_STRING_COLUMN_INDEX);
277                             lookupUri = Contacts.getLookupUri(contactId, lookupKey);
278                         }
279 
280                         break;
281                     }
282                     case TOKEN_EMAIL_LOOKUP_AND_TRIGGER:
283                         trigger = true;
284                         createUri = Uri.fromParts("mailto", (String)cookie, null);
285 
286                         //$FALL-THROUGH$
287                     case TOKEN_EMAIL_LOOKUP: {
288                         if (cursor != null && cursor.moveToFirst()) {
289                             long contactId = cursor.getLong(EMAIL_ID_COLUMN_INDEX);
290                             String lookupKey = cursor.getString(EMAIL_LOOKUP_STRING_COLUMN_INDEX);
291                             lookupUri = Contacts.getLookupUri(contactId, lookupKey);
292                         }
293                         break;
294                     }
295                 }
296             } finally {
297                 if (cursor != null) {
298                     cursor.close();
299                 }
300             }
301 
302             mContactUri = lookupUri;
303             onContactUriChanged();
304 
305             if (trigger && lookupUri != null) {
306                 // Found contact, so trigger QuickContact
307                 QuickContact.showQuickContact(getContext(), QuickContactBadge.this, lookupUri,
308                         QuickContact.MODE_LARGE, mExcludeMimes);
309             } else if (createUri != null) {
310                 // Prompt user to add this person to contacts
311                 final Intent intent = new Intent(Intents.SHOW_OR_CREATE_CONTACT, createUri);
312                 getContext().startActivity(intent);
313             }
314         }
315     }
316 }
317