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