blob: b590814f4f63762ea90c7db6b5fbd6d3992ce5b0 [file] [log] [blame]
Daniel Lehmannfbb87632011-09-30 20:54:15 -07001/*
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
Daniel Lehmannaf8e3862010-11-19 15:38:44 -080017package com.android.contacts.quickcontact;
18
David Braun76de0fa2013-09-24 17:08:14 -070019import android.content.ComponentName;
Daniel Lehmannaf8e3862010-11-19 15:38:44 -080020import android.content.ContentUris;
21import android.content.Context;
22import android.content.Intent;
23import android.content.pm.PackageManager;
Daniel Lehmannaf8e3862010-11-19 15:38:44 -080024import android.graphics.drawable.Drawable;
25import android.net.Uri;
Dmitri Plotnikov15dcf1d2010-12-09 17:12:54 -080026import android.net.WebAddress;
Daniel Lehmannaf8e3862010-11-19 15:38:44 -080027import android.provider.ContactsContract.CommonDataKinds.Im;
Daisuke Miyakawaf31df5d2011-08-02 15:37:50 -070028import android.provider.ContactsContract.Data;
Daniel Lehmannaf8e3862010-11-19 15:38:44 -080029import android.text.TextUtils;
30import android.util.Log;
31
Paul Soulos16339332014-06-24 13:59:56 -070032import com.android.contacts.R;
Chiao Cheng3a8df862012-09-04 16:30:17 -070033import com.android.contacts.common.CallUtil;
Yorke Leecd321f62013-10-28 15:20:15 -070034import com.android.contacts.common.ContactsUtils;
Chiao Chengd7ca03e2012-10-24 15:14:08 -070035import com.android.contacts.common.MoreContactUtils;
Chiao Cheng428f0082012-11-13 18:38:56 -080036import com.android.contacts.common.model.account.AccountType.EditType;
Yorke Leecd321f62013-10-28 15:20:15 -070037import com.android.contacts.common.model.dataitem.DataItem;
Chiao Cheng428f0082012-11-13 18:38:56 -080038import com.android.contacts.common.model.dataitem.DataKind;
Yorke Leecd321f62013-10-28 15:20:15 -070039import com.android.contacts.common.model.dataitem.EmailDataItem;
40import com.android.contacts.common.model.dataitem.ImDataItem;
41import com.android.contacts.common.model.dataitem.PhoneDataItem;
42import com.android.contacts.common.model.dataitem.SipAddressDataItem;
43import com.android.contacts.common.model.dataitem.StructuredPostalDataItem;
44import com.android.contacts.common.model.dataitem.WebsiteDataItem;
Chiao Chenge0b2f1e2012-06-12 13:07:56 -070045import com.android.contacts.util.PhoneCapabilityTester;
46import com.android.contacts.util.StructuredPostalUtils;
47
Daniel Lehmannaf8e3862010-11-19 15:38:44 -080048/**
49 * Description of a specific {@link Data#_ID} item, with style information
50 * defined by a {@link DataKind}.
51 */
52public 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;
Paul Soulos16339332014-06-24 13:59:56 -070058 private final Integer mTimesUsed;
59 private final Long mLastTimeUsed;
Daniel Lehmannaf8e3862010-11-19 15:38:44 -080060
Daniel Lehmannaf8e3862010-11-19 15:38:44 -080061 private CharSequence mBody;
Daniel Lehmannedb576a2011-07-27 16:45:13 -070062 private CharSequence mSubtitle;
Daniel Lehmannaf8e3862010-11-19 15:38:44 -080063 private Intent mIntent;
Daniel Lehmannedb576a2011-07-27 16:45:13 -070064 private Intent mAlternateIntent;
Katherine Kuanee05dcd2011-10-05 20:18:12 -070065 private int mAlternateIconDescriptionRes;
Daniel Lehmannedb576a2011-07-27 16:45:13 -070066 private int mAlternateIconRes;
Daniel Lehmann9daca142011-12-20 11:41:22 +020067 private int mPresence = -1;
Daniel Lehmannaf8e3862010-11-19 15:38:44 -080068
Daniel Lehmannaf8e3862010-11-19 15:38:44 -080069 private Uri mDataUri;
Daniel Lehmann0f78e8b2010-11-24 17:32:03 -080070 private long mDataId;
Daniel Lehmannaf8e3862010-11-19 15:38:44 -080071 private boolean mIsPrimary;
Paul Soulos16339332014-06-24 13:59:56 -070072 private boolean mIsSuperPrimary;
Daniel Lehmannaf8e3862010-11-19 15:38:44 -080073
74 /**
75 * Create an action from common {@link Data} elements.
76 */
Chiao Cheng47b6f702012-09-07 17:28:17 -070077 public DataAction(Context context, DataItem item, DataKind kind) {
Daniel Lehmannaf8e3862010-11-19 15:38:44 -080078 mContext = context;
Chiao Cheng47b6f702012-09-07 17:28:17 -070079 mKind = kind;
Maurice Chu851222a2012-06-21 11:43:08 -070080 mMimeType = item.getMimeType();
Paul Soulos16339332014-06-24 13:59:56 -070081 mTimesUsed = item.getTimesUsed();
82 mLastTimeUsed = item.getLastTimeUsed();
Daniel Lehmannaf8e3862010-11-19 15:38:44 -080083
Daniel Lehmannedb576a2011-07-27 16:45:13 -070084 // Determine type for subtitle
85 mSubtitle = "";
Chiao Cheng47b6f702012-09-07 17:28:17 -070086 if (item.hasKindTypeColumn(kind)) {
87 final int typeValue = item.getKindTypeColumn(kind);
Daniel Lehmannedb576a2011-07-27 16:45:13 -070088
Maurice Chu851222a2012-06-21 11:43:08 -070089 // get type string
Chiao Cheng47b6f702012-09-07 17:28:17 -070090 for (EditType type : kind.typeList) {
Maurice Chu851222a2012-06-21 11:43:08 -070091 if (type.rawValue == typeValue) {
92 if (type.customColumn == null) {
93 // Non-custom type. Get its description from the resource
94 mSubtitle = context.getString(type.labelRes);
95 } else {
96 // Custom type. Read it from the database
97 mSubtitle = item.getContentValues().getAsString(type.customColumn);
Daniel Lehmannedb576a2011-07-27 16:45:13 -070098 }
Maurice Chu851222a2012-06-21 11:43:08 -070099 break;
Daniel Lehmannedb576a2011-07-27 16:45:13 -0700100 }
101 }
Daniel Lehmannaf8e3862010-11-19 15:38:44 -0800102 }
103
Paul Soulos16339332014-06-24 13:59:56 -0700104 mIsPrimary = item.isPrimary();
105 mIsSuperPrimary = item.isSuperPrimary();
Yorke Leeb2b435a2012-11-12 16:47:06 -0800106 mBody = item.buildDataStringForDisplay(context, kind);
Daniel Lehmannaf8e3862010-11-19 15:38:44 -0800107
Maurice Chu851222a2012-06-21 11:43:08 -0700108 mDataId = item.getId();
109 mDataUri = ContentUris.withAppendedId(Data.CONTENT_URI, mDataId);
Daniel Lehmannaf8e3862010-11-19 15:38:44 -0800110
Daniel Lehmannedb576a2011-07-27 16:45:13 -0700111 final boolean hasPhone = PhoneCapabilityTester.isPhone(mContext);
David Braun76de0fa2013-09-24 17:08:14 -0700112 final ComponentName smsComponent = PhoneCapabilityTester.getSmsComponent(mContext);
113 final boolean hasSms = (smsComponent != null);
Daniel Lehmannedb576a2011-07-27 16:45:13 -0700114
Daniel Lehmannaf8e3862010-11-19 15:38:44 -0800115 // Handle well-known MIME-types with special care
Maurice Chu851222a2012-06-21 11:43:08 -0700116 if (item instanceof PhoneDataItem) {
Daniel Lehmannaf8e3862010-11-19 15:38:44 -0800117 if (PhoneCapabilityTester.isPhone(mContext)) {
Maurice Chu851222a2012-06-21 11:43:08 -0700118 PhoneDataItem phone = (PhoneDataItem) item;
119 final String number = phone.getNumber();
Daniel Lehmannaf8e3862010-11-19 15:38:44 -0800120 if (!TextUtils.isEmpty(number)) {
Daniel Lehmannedb576a2011-07-27 16:45:13 -0700121
Chiao Cheng3a8df862012-09-04 16:30:17 -0700122 final Intent phoneIntent = hasPhone ? CallUtil.getCallIntent(number)
Daisuke Miyakawafadd5e12011-12-01 17:34:18 -0800123 : null;
David Braun76de0fa2013-09-24 17:08:14 -0700124 Intent smsIntent = null;
125 if (hasSms) {
126 smsIntent = new Intent(Intent.ACTION_SENDTO,
127 Uri.fromParts(CallUtil.SCHEME_SMSTO, number, null));
128 smsIntent.setComponent(smsComponent);
129 }
Daniel Lehmannedb576a2011-07-27 16:45:13 -0700130
131 // Configure Icons and Intents. Notice actionIcon is already set to the phone
132 if (hasPhone && hasSms) {
133 mIntent = phoneIntent;
134 mAlternateIntent = smsIntent;
Chiao Cheng47b6f702012-09-07 17:28:17 -0700135 mAlternateIconRes = kind.iconAltRes;
136 mAlternateIconDescriptionRes = kind.iconAltDescriptionRes;
Daniel Lehmannedb576a2011-07-27 16:45:13 -0700137 } else if (hasPhone) {
138 mIntent = phoneIntent;
139 } else if (hasSms) {
140 mIntent = smsIntent;
141 }
Daniel Lehmannaf8e3862010-11-19 15:38:44 -0800142 }
143 }
Maurice Chu851222a2012-06-21 11:43:08 -0700144 } else if (item instanceof SipAddressDataItem) {
Daniel Lehmannaf8e3862010-11-19 15:38:44 -0800145 if (PhoneCapabilityTester.isSipPhone(mContext)) {
Maurice Chu851222a2012-06-21 11:43:08 -0700146 final SipAddressDataItem sip = (SipAddressDataItem) item;
147 final String address = sip.getSipAddress();
Daniel Lehmannaf8e3862010-11-19 15:38:44 -0800148 if (!TextUtils.isEmpty(address)) {
Chiao Cheng3a8df862012-09-04 16:30:17 -0700149 final Uri callUri = Uri.fromParts(CallUtil.SCHEME_SIP, address, null);
150 mIntent = CallUtil.getCallIntent(callUri);
Daniel Lehmannaf8e3862010-11-19 15:38:44 -0800151 // Note that this item will get a SIP-specific variant
152 // of the "call phone" icon, rather than the standard
153 // app icon for the Phone app (which we show for
154 // regular phone numbers.) That's because the phone
155 // app explicitly specifies an android:icon attribute
156 // for the SIP-related intent-filters in its manifest.
157 }
158 }
Maurice Chu851222a2012-06-21 11:43:08 -0700159 } else if (item instanceof EmailDataItem) {
160 final EmailDataItem email = (EmailDataItem) item;
161 final String address = email.getData();
Daniel Lehmannaf8e3862010-11-19 15:38:44 -0800162 if (!TextUtils.isEmpty(address)) {
Chiao Cheng3a8df862012-09-04 16:30:17 -0700163 final Uri mailUri = Uri.fromParts(CallUtil.SCHEME_MAILTO, address, null);
Daniel Lehmannaf8e3862010-11-19 15:38:44 -0800164 mIntent = new Intent(Intent.ACTION_SENDTO, mailUri);
165 }
166
Maurice Chu851222a2012-06-21 11:43:08 -0700167 } else if (item instanceof WebsiteDataItem) {
168 final WebsiteDataItem website = (WebsiteDataItem) item;
169 final String url = website.getUrl();
Daniel Lehmannaf8e3862010-11-19 15:38:44 -0800170 if (!TextUtils.isEmpty(url)) {
Dmitri Plotnikov15dcf1d2010-12-09 17:12:54 -0800171 WebAddress webAddress = new WebAddress(url);
172 mIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(webAddress.toString()));
Daniel Lehmannaf8e3862010-11-19 15:38:44 -0800173 }
174
Maurice Chu851222a2012-06-21 11:43:08 -0700175 } 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();
Daniel Lehmannaf8e3862010-11-19 15:38:44 -0800180
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.
Daniel Lehmann9daca142011-12-20 11:41:22 +0200184 mSubtitle = Im.getProtocolLabel(context.getResources(), Im.PROTOCOL_GOOGLE_TALK,
185 null);
Daniel Lehmannaf8e3862010-11-19 15:38:44 -0800186 mDataUri = null;
187 }
188
Maurice Chu851222a2012-06-21 11:43:08 -0700189 String host = im.getCustomProtocol();
190 String data = im.getData();
Daniel Lehmannaf8e3862010-11-19 15:38:44 -0800191 if (protocol != Im.PROTOCOL_CUSTOM) {
192 // Try bringing in a well-known host for specific protocols
193 host = ContactsUtils.lookupProviderNameFromId(protocol);
194 }
195
Daisuke Miyakawaf31df5d2011-08-02 15:37:50 -0700196 if (!TextUtils.isEmpty(host) && !TextUtils.isEmpty(data)) {
Daniel Lehmannaf8e3862010-11-19 15:38:44 -0800197 final String authority = host.toLowerCase();
Chiao Cheng3a8df862012-09-04 16:30:17 -0700198 final Uri imUri = new Uri.Builder().scheme(CallUtil.SCHEME_IMTO).authority(
Daniel Lehmannaf8e3862010-11-19 15:38:44 -0800199 authority).appendPath(data).build();
200 mIntent = new Intent(Intent.ACTION_SENDTO, imUri);
Daisuke Miyakawaf31df5d2011-08-02 15:37:50 -0700201
202 // If the address is also available for a video chat, we'll show the capability
203 // as a secondary action.
Maurice Chu851222a2012-06-21 11:43:08 -0700204 final int chatCapability = im.getChatCapability();
Daisuke Miyakawaf31df5d2011-08-02 15:37:50 -0700205 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) {
Daisuke Miyakawaf31df5d2011-08-02 15:37:50 -0700210 mAlternateIntent = new Intent(
211 Intent.ACTION_SENDTO, Uri.parse("xmpp:" + data + "?call"));
Katherine Kuanee05dcd2011-10-05 20:18:12 -0700212 if (isVideoChatCapable) {
213 mAlternateIconRes = R.drawable.sym_action_videochat_holo_light;
214 mAlternateIconDescriptionRes = R.string.video_chat;
215 } else {
216 mAlternateIconRes = R.drawable.sym_action_audiochat_holo_light;
217 mAlternateIconDescriptionRes = R.string.audio_chat;
218 }
Daisuke Miyakawaf31df5d2011-08-02 15:37:50 -0700219 }
Daniel Lehmannaf8e3862010-11-19 15:38:44 -0800220 }
221 }
Maurice Chu851222a2012-06-21 11:43:08 -0700222 } else if (item instanceof StructuredPostalDataItem) {
223 StructuredPostalDataItem postal = (StructuredPostalDataItem) item;
224 final String postalAddress = postal.getFormattedAddress();
Makoto Onukibfb59d82011-09-30 16:34:38 -0700225 if (!TextUtils.isEmpty(postalAddress)) {
226 mIntent = StructuredPostalUtils.getViewPostalAddressIntent(postalAddress);
227 }
Daniel Lehmannaf8e3862010-11-19 15:38:44 -0800228 }
229
230 if (mIntent == null) {
231 // Otherwise fall back to default VIEW action
Dmitri Plotnikov1b89adc2010-12-09 17:05:54 -0800232 mIntent = new Intent(Intent.ACTION_VIEW);
Maurice Chu851222a2012-06-21 11:43:08 -0700233 mIntent.setDataAndType(mDataUri, item.getMimeType());
Daniel Lehmannaf8e3862010-11-19 15:38:44 -0800234 }
235
Adam Powell8ca93ed2012-04-23 13:28:28 -0700236 mIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
Daniel Lehmannaf8e3862010-11-19 15:38:44 -0800237 }
238
Daniel Lehmann9daca142011-12-20 11:41:22 +0200239 @Override
240 public int getPresence() {
241 return mPresence;
242 }
243
244 public void setPresence(int presence) {
245 mPresence = presence;
246 }
247
Daniel Lehmannaf8e3862010-11-19 15:38:44 -0800248 @Override
Daniel Lehmannedb576a2011-07-27 16:45:13 -0700249 public CharSequence getSubtitle() {
250 return mSubtitle;
Daniel Lehmannaf8e3862010-11-19 15:38:44 -0800251 }
252
Daniel Lehmannaf8e3862010-11-19 15:38:44 -0800253 @Override
254 public CharSequence getBody() {
255 return mBody;
256 }
257
Daniel Lehmannaf8e3862010-11-19 15:38:44 -0800258 @Override
259 public String getMimeType() {
260 return mMimeType;
261 }
262
Daniel Lehmannaf8e3862010-11-19 15:38:44 -0800263 @Override
264 public Uri getDataUri() {
265 return mDataUri;
266 }
267
Daniel Lehmannaf8e3862010-11-19 15:38:44 -0800268 @Override
Daniel Lehmann0f78e8b2010-11-24 17:32:03 -0800269 public long getDataId() {
270 return mDataId;
271 }
272
Daniel Lehmann0f78e8b2010-11-24 17:32:03 -0800273 @Override
Paul Soulos16339332014-06-24 13:59:56 -0700274 public boolean isPrimary() {
Daniel Lehmannaf8e3862010-11-19 15:38:44 -0800275 return mIsPrimary;
276 }
277
Daniel Lehmannaf8e3862010-11-19 15:38:44 -0800278 @Override
Paul Soulos16339332014-06-24 13:59:56 -0700279 public boolean isSuperPrimary() {
280 return mIsSuperPrimary;
281 }
282
283 @Override
Daniel Lehmannedb576a2011-07-27 16:45:13 -0700284 public Drawable getAlternateIcon() {
285 if (mAlternateIconRes == 0) return null;
286
Makoto Onuki82a4f442012-05-07 17:18:33 -0700287 final String resourcePackageName = mKind.resourcePackageName;
288 if (resourcePackageName == null) {
Daniel Lehmannedb576a2011-07-27 16:45:13 -0700289 return mContext.getResources().getDrawable(mAlternateIconRes);
290 }
Daniel Lehmannaf8e3862010-11-19 15:38:44 -0800291
292 final PackageManager pm = mContext.getPackageManager();
Makoto Onuki82a4f442012-05-07 17:18:33 -0700293 return pm.getDrawable(resourcePackageName, mAlternateIconRes, null);
Daniel Lehmannaf8e3862010-11-19 15:38:44 -0800294 }
295
Daniel Lehmannaf8e3862010-11-19 15:38:44 -0800296 @Override
Katherine Kuanee05dcd2011-10-05 20:18:12 -0700297 public String getAlternateIconDescription() {
298 if (mAlternateIconDescriptionRes == 0) return null;
299 return mContext.getResources().getString(mAlternateIconDescriptionRes);
300 }
301
302 @Override
Daniel Lehmannaf8e3862010-11-19 15:38:44 -0800303 public Intent getIntent() {
304 return mIntent;
305 }
306
Daniel Lehmannedb576a2011-07-27 16:45:13 -0700307 @Override
308 public Intent getAlternateIntent() {
309 return mAlternateIntent;
310 }
311
Daniel Lehmannaf8e3862010-11-19 15:38:44 -0800312 @Override
Jay Shraunerad29eae2013-01-08 11:42:17 -0800313 public void collapseWith(Action other) {
314 // No-op
Daniel Lehmannaf8e3862010-11-19 15:38:44 -0800315 }
316
Daniel Lehmannaf8e3862010-11-19 15:38:44 -0800317 @Override
Paul Soulos0646ee32014-06-26 16:40:28 -0700318 public boolean shouldCollapseWith(Action t, Context context) {
Daniel Lehmannaf8e3862010-11-19 15:38:44 -0800319 if (t == null) {
320 return false;
321 }
322 if (!(t instanceof DataAction)) {
323 Log.e(TAG, "t must be DataAction");
324 return false;
325 }
Daniel Lehmann69fad282011-08-28 21:15:27 -0700326 DataAction that = (DataAction)t;
Chiao Chengd7ca03e2012-10-24 15:14:08 -0700327 if (!MoreContactUtils.shouldCollapse(mMimeType, mBody, that.mMimeType, that.mBody)) {
Daniel Lehmannaf8e3862010-11-19 15:38:44 -0800328 return false;
329 }
Daniel Lehmann69fad282011-08-28 21:15:27 -0700330 if (!TextUtils.equals(mMimeType, that.mMimeType)
331 || !ContactsUtils.areIntentActionEqual(mIntent, that.mIntent)) {
Daniel Lehmannaf8e3862010-11-19 15:38:44 -0800332 return false;
333 }
334 return true;
335 }
Paul Soulos16339332014-06-24 13:59:56 -0700336
337 @Override
338 public Integer getTimesUsed() {
339 return mTimesUsed;
340 }
341
342 @Override
343 public Long getLastTimeUsed() {
344 return mLastTimeUsed;
345 }
Daniel Lehmannaf8e3862010-11-19 15:38:44 -0800346}