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