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