Home | History | Annotate | Download | only in quickcontact
      1 /*
      2  * Copyright (C) 2010 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 com.android.contacts.quickcontact;
     18 
     19 import android.content.ContentUris;
     20 import android.content.Context;
     21 import android.content.Intent;
     22 import android.content.pm.PackageManager;
     23 import android.graphics.drawable.Drawable;
     24 import android.net.Uri;
     25 import android.net.WebAddress;
     26 import android.provider.ContactsContract.CommonDataKinds.Im;
     27 import android.provider.ContactsContract.Data;
     28 import android.text.TextUtils;
     29 import android.util.Log;
     30 
     31 import com.android.contacts.common.CallUtil;
     32 import com.android.contacts.ContactsUtils;
     33 import com.android.contacts.R;
     34 import com.android.contacts.common.MoreContactUtils;
     35 import com.android.contacts.common.model.account.AccountType.EditType;
     36 import com.android.contacts.model.dataitem.DataItem;
     37 import com.android.contacts.common.model.dataitem.DataKind;
     38 import com.android.contacts.model.dataitem.EmailDataItem;
     39 import com.android.contacts.model.dataitem.ImDataItem;
     40 import com.android.contacts.model.dataitem.PhoneDataItem;
     41 import com.android.contacts.model.dataitem.SipAddressDataItem;
     42 import com.android.contacts.model.dataitem.StructuredPostalDataItem;
     43 import com.android.contacts.model.dataitem.WebsiteDataItem;
     44 import com.android.contacts.util.PhoneCapabilityTester;
     45 import com.android.contacts.util.StructuredPostalUtils;
     46 
     47 /**
     48  * Description of a specific {@link Data#_ID} item, with style information
     49  * defined by a {@link DataKind}.
     50  */
     51 public class DataAction implements Action {
     52     private static final String TAG = "DataAction";
     53 
     54     private final Context mContext;
     55     private final DataKind mKind;
     56     private final String mMimeType;
     57 
     58     private CharSequence mBody;
     59     private CharSequence mSubtitle;
     60     private Intent mIntent;
     61     private Intent mAlternateIntent;
     62     private int mAlternateIconDescriptionRes;
     63     private int mAlternateIconRes;
     64     private int mPresence = -1;
     65 
     66     private Uri mDataUri;
     67     private long mDataId;
     68     private boolean mIsPrimary;
     69 
     70     /**
     71      * Create an action from common {@link Data} elements.
     72      */
     73     public DataAction(Context context, DataItem item, DataKind kind) {
     74         mContext = context;
     75         mKind = kind;
     76         mMimeType = item.getMimeType();
     77 
     78         // Determine type for subtitle
     79         mSubtitle = "";
     80         if (item.hasKindTypeColumn(kind)) {
     81             final int typeValue = item.getKindTypeColumn(kind);
     82 
     83             // get type string
     84             for (EditType type : kind.typeList) {
     85                 if (type.rawValue == typeValue) {
     86                     if (type.customColumn == null) {
     87                         // Non-custom type. Get its description from the resource
     88                         mSubtitle = context.getString(type.labelRes);
     89                     } else {
     90                         // Custom type. Read it from the database
     91                         mSubtitle = item.getContentValues().getAsString(type.customColumn);
     92                     }
     93                     break;
     94                 }
     95             }
     96         }
     97 
     98         mIsPrimary = item.isSuperPrimary();
     99         mBody = item.buildDataStringForDisplay(context, kind);
    100 
    101         mDataId = item.getId();
    102         mDataUri = ContentUris.withAppendedId(Data.CONTENT_URI, mDataId);
    103 
    104         final boolean hasPhone = PhoneCapabilityTester.isPhone(mContext);
    105         final boolean hasSms = PhoneCapabilityTester.isSmsIntentRegistered(mContext);
    106 
    107         // Handle well-known MIME-types with special care
    108         if (item instanceof PhoneDataItem) {
    109             if (PhoneCapabilityTester.isPhone(mContext)) {
    110                 PhoneDataItem phone = (PhoneDataItem) item;
    111                 final String number = phone.getNumber();
    112                 if (!TextUtils.isEmpty(number)) {
    113 
    114                     final Intent phoneIntent = hasPhone ? CallUtil.getCallIntent(number)
    115                             : null;
    116                     final Intent smsIntent = hasSms ? new Intent(Intent.ACTION_SENDTO,
    117                             Uri.fromParts(CallUtil.SCHEME_SMSTO, number, null)) : null;
    118 
    119                     // Configure Icons and Intents. Notice actionIcon is already set to the phone
    120                     if (hasPhone && hasSms) {
    121                         mIntent = phoneIntent;
    122                         mAlternateIntent = smsIntent;
    123                         mAlternateIconRes = kind.iconAltRes;
    124                         mAlternateIconDescriptionRes = kind.iconAltDescriptionRes;
    125                     } else if (hasPhone) {
    126                         mIntent = phoneIntent;
    127                     } else if (hasSms) {
    128                         mIntent = smsIntent;
    129                     }
    130                 }
    131             }
    132         } else if (item instanceof SipAddressDataItem) {
    133             if (PhoneCapabilityTester.isSipPhone(mContext)) {
    134                 final SipAddressDataItem sip = (SipAddressDataItem) item;
    135                 final String address = sip.getSipAddress();
    136                 if (!TextUtils.isEmpty(address)) {
    137                     final Uri callUri = Uri.fromParts(CallUtil.SCHEME_SIP, address, null);
    138                     mIntent = CallUtil.getCallIntent(callUri);
    139                     // Note that this item will get a SIP-specific variant
    140                     // of the "call phone" icon, rather than the standard
    141                     // app icon for the Phone app (which we show for
    142                     // regular phone numbers.)  That's because the phone
    143                     // app explicitly specifies an android:icon attribute
    144                     // for the SIP-related intent-filters in its manifest.
    145                 }
    146             }
    147         } else if (item instanceof EmailDataItem) {
    148             final EmailDataItem email = (EmailDataItem) item;
    149             final String address = email.getData();
    150             if (!TextUtils.isEmpty(address)) {
    151                 final Uri mailUri = Uri.fromParts(CallUtil.SCHEME_MAILTO, address, null);
    152                 mIntent = new Intent(Intent.ACTION_SENDTO, mailUri);
    153             }
    154 
    155         } else if (item instanceof WebsiteDataItem) {
    156             final WebsiteDataItem website = (WebsiteDataItem) item;
    157             final String url = website.getUrl();
    158             if (!TextUtils.isEmpty(url)) {
    159                 WebAddress webAddress = new WebAddress(url);
    160                 mIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(webAddress.toString()));
    161             }
    162 
    163         } else if (item instanceof ImDataItem) {
    164             ImDataItem im = (ImDataItem) item;
    165             final boolean isEmail = im.isCreatedFromEmail();
    166             if (isEmail || im.isProtocolValid()) {
    167                 final int protocol = isEmail ? Im.PROTOCOL_GOOGLE_TALK : im.getProtocol();
    168 
    169                 if (isEmail) {
    170                     // Use Google Talk string when using Email, and clear data
    171                     // Uri so we don't try saving Email as primary.
    172                     mSubtitle = Im.getProtocolLabel(context.getResources(), Im.PROTOCOL_GOOGLE_TALK,
    173                             null);
    174                     mDataUri = null;
    175                 }
    176 
    177                 String host = im.getCustomProtocol();
    178                 String data = im.getData();
    179                 if (protocol != Im.PROTOCOL_CUSTOM) {
    180                     // Try bringing in a well-known host for specific protocols
    181                     host = ContactsUtils.lookupProviderNameFromId(protocol);
    182                 }
    183 
    184                 if (!TextUtils.isEmpty(host) && !TextUtils.isEmpty(data)) {
    185                     final String authority = host.toLowerCase();
    186                     final Uri imUri = new Uri.Builder().scheme(CallUtil.SCHEME_IMTO).authority(
    187                             authority).appendPath(data).build();
    188                     mIntent = new Intent(Intent.ACTION_SENDTO, imUri);
    189 
    190                     // If the address is also available for a video chat, we'll show the capability
    191                     // as a secondary action.
    192                     final int chatCapability = im.getChatCapability();
    193                     final boolean isVideoChatCapable =
    194                             (chatCapability & Im.CAPABILITY_HAS_CAMERA) != 0;
    195                     final boolean isAudioChatCapable =
    196                             (chatCapability & Im.CAPABILITY_HAS_VOICE) != 0;
    197                     if (isVideoChatCapable || isAudioChatCapable) {
    198                         mAlternateIntent = new Intent(
    199                                 Intent.ACTION_SENDTO, Uri.parse("xmpp:" + data + "?call"));
    200                         if (isVideoChatCapable) {
    201                             mAlternateIconRes = R.drawable.sym_action_videochat_holo_light;
    202                             mAlternateIconDescriptionRes = R.string.video_chat;
    203                         } else {
    204                             mAlternateIconRes = R.drawable.sym_action_audiochat_holo_light;
    205                             mAlternateIconDescriptionRes = R.string.audio_chat;
    206                         }
    207                     }
    208                 }
    209             }
    210         } else if (item instanceof StructuredPostalDataItem) {
    211             StructuredPostalDataItem postal = (StructuredPostalDataItem) item;
    212             final String postalAddress = postal.getFormattedAddress();
    213             if (!TextUtils.isEmpty(postalAddress)) {
    214                 mIntent = StructuredPostalUtils.getViewPostalAddressIntent(postalAddress);
    215             }
    216         }
    217 
    218         if (mIntent == null) {
    219             // Otherwise fall back to default VIEW action
    220             mIntent = new Intent(Intent.ACTION_VIEW);
    221             mIntent.setDataAndType(mDataUri, item.getMimeType());
    222         }
    223 
    224         mIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
    225     }
    226 
    227     @Override
    228     public int getPresence() {
    229         return mPresence;
    230     }
    231 
    232     public void setPresence(int presence) {
    233         mPresence = presence;
    234     }
    235 
    236     @Override
    237     public CharSequence getSubtitle() {
    238         return mSubtitle;
    239     }
    240 
    241     @Override
    242     public CharSequence getBody() {
    243         return mBody;
    244     }
    245 
    246     @Override
    247     public String getMimeType() {
    248         return mMimeType;
    249     }
    250 
    251     @Override
    252     public Uri getDataUri() {
    253         return mDataUri;
    254     }
    255 
    256     @Override
    257     public long getDataId() {
    258         return mDataId;
    259     }
    260 
    261     @Override
    262     public Boolean isPrimary() {
    263         return mIsPrimary;
    264     }
    265 
    266     @Override
    267     public Drawable getAlternateIcon() {
    268         if (mAlternateIconRes == 0) return null;
    269 
    270         final String resourcePackageName = mKind.resourcePackageName;
    271         if (resourcePackageName == null) {
    272             return mContext.getResources().getDrawable(mAlternateIconRes);
    273         }
    274 
    275         final PackageManager pm = mContext.getPackageManager();
    276         return pm.getDrawable(resourcePackageName, mAlternateIconRes, null);
    277     }
    278 
    279     @Override
    280     public String getAlternateIconDescription() {
    281         if (mAlternateIconDescriptionRes == 0) return null;
    282         return mContext.getResources().getString(mAlternateIconDescriptionRes);
    283     }
    284 
    285     @Override
    286     public Intent getIntent() {
    287         return mIntent;
    288     }
    289 
    290     @Override
    291     public Intent getAlternateIntent() {
    292         return mAlternateIntent;
    293     }
    294 
    295     @Override
    296     public void collapseWith(Action other) {
    297         // No-op
    298     }
    299 
    300     @Override
    301     public boolean shouldCollapseWith(Action t) {
    302         if (t == null) {
    303             return false;
    304         }
    305         if (!(t instanceof DataAction)) {
    306             Log.e(TAG, "t must be DataAction");
    307             return false;
    308         }
    309         DataAction that = (DataAction)t;
    310         if (!MoreContactUtils.shouldCollapse(mMimeType, mBody, that.mMimeType, that.mBody)) {
    311             return false;
    312         }
    313         if (!TextUtils.equals(mMimeType, that.mMimeType)
    314                 || !ContactsUtils.areIntentActionEqual(mIntent, that.mIntent)) {
    315             return false;
    316         }
    317         return true;
    318     }
    319 }
    320