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