Home | History | Annotate | Download | only in widget
      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