• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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      */
DataAction(Context context, DataItem item, DataKind kind)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
getPresence()228     public int getPresence() {
229         return mPresence;
230     }
231 
setPresence(int presence)232     public void setPresence(int presence) {
233         mPresence = presence;
234     }
235 
236     @Override
getSubtitle()237     public CharSequence getSubtitle() {
238         return mSubtitle;
239     }
240 
241     @Override
getBody()242     public CharSequence getBody() {
243         return mBody;
244     }
245 
246     @Override
getMimeType()247     public String getMimeType() {
248         return mMimeType;
249     }
250 
251     @Override
getDataUri()252     public Uri getDataUri() {
253         return mDataUri;
254     }
255 
256     @Override
getDataId()257     public long getDataId() {
258         return mDataId;
259     }
260 
261     @Override
isPrimary()262     public Boolean isPrimary() {
263         return mIsPrimary;
264     }
265 
266     @Override
getAlternateIcon()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
getAlternateIconDescription()280     public String getAlternateIconDescription() {
281         if (mAlternateIconDescriptionRes == 0) return null;
282         return mContext.getResources().getString(mAlternateIconDescriptionRes);
283     }
284 
285     @Override
getIntent()286     public Intent getIntent() {
287         return mIntent;
288     }
289 
290     @Override
getAlternateIntent()291     public Intent getAlternateIntent() {
292         return mAlternateIntent;
293     }
294 
295     @Override
collapseWith(Action other)296     public void collapseWith(Action other) {
297         // No-op
298     }
299 
300     @Override
shouldCollapseWith(Action t)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