blob: 5a49c77d85834ed3699c171a88b969b6cfe97e00 [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;
Daniel Lehmannaf8e3862010-11-19 15:38:44 -080026import android.provider.ContactsContract.CommonDataKinds.Im;
Daisuke Miyakawaf31df5d2011-08-02 15:37:50 -070027import android.provider.ContactsContract.Data;
Tyler Gunn03192222014-09-10 15:20:09 -070028import android.telecom.PhoneAccount;
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;
Brian Attwell493f8d12014-12-18 12:42:03 -080045import com.android.contacts.quickcontact.WebAddress.ParseException;
Chiao Chenge0b2f1e2012-06-12 13:07:56 -070046import com.android.contacts.util.PhoneCapabilityTester;
47import com.android.contacts.util.StructuredPostalUtils;
48
Daniel Lehmannaf8e3862010-11-19 15:38:44 -080049/**
50 * Description of a specific {@link Data#_ID} item, with style information
51 * defined by a {@link DataKind}.
52 */
53public 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;
Paul Soulos16339332014-06-24 13:59:56 -070059 private final Integer mTimesUsed;
60 private final Long mLastTimeUsed;
Daniel Lehmannaf8e3862010-11-19 15:38:44 -080061
Daniel Lehmannaf8e3862010-11-19 15:38:44 -080062 private CharSequence mBody;
Daniel Lehmannedb576a2011-07-27 16:45:13 -070063 private CharSequence mSubtitle;
Daniel Lehmannaf8e3862010-11-19 15:38:44 -080064 private Intent mIntent;
Daniel Lehmannedb576a2011-07-27 16:45:13 -070065 private Intent mAlternateIntent;
Katherine Kuanee05dcd2011-10-05 20:18:12 -070066 private int mAlternateIconDescriptionRes;
Daniel Lehmannedb576a2011-07-27 16:45:13 -070067 private int mAlternateIconRes;
Daniel Lehmann9daca142011-12-20 11:41:22 +020068 private int mPresence = -1;
Daniel Lehmannaf8e3862010-11-19 15:38:44 -080069
Daniel Lehmannaf8e3862010-11-19 15:38:44 -080070 private Uri mDataUri;
Daniel Lehmann0f78e8b2010-11-24 17:32:03 -080071 private long mDataId;
Daniel Lehmannaf8e3862010-11-19 15:38:44 -080072 private boolean mIsPrimary;
Paul Soulos16339332014-06-24 13:59:56 -070073 private boolean mIsSuperPrimary;
Daniel Lehmannaf8e3862010-11-19 15:38:44 -080074
75 /**
76 * Create an action from common {@link Data} elements.
77 */
Chiao Cheng47b6f702012-09-07 17:28:17 -070078 public DataAction(Context context, DataItem item, DataKind kind) {
Daniel Lehmannaf8e3862010-11-19 15:38:44 -080079 mContext = context;
Chiao Cheng47b6f702012-09-07 17:28:17 -070080 mKind = kind;
Maurice Chu851222a2012-06-21 11:43:08 -070081 mMimeType = item.getMimeType();
Paul Soulos16339332014-06-24 13:59:56 -070082 mTimesUsed = item.getTimesUsed();
83 mLastTimeUsed = item.getLastTimeUsed();
Daniel Lehmannaf8e3862010-11-19 15:38:44 -080084
Daniel Lehmannedb576a2011-07-27 16:45:13 -070085 // Determine type for subtitle
86 mSubtitle = "";
Chiao Cheng47b6f702012-09-07 17:28:17 -070087 if (item.hasKindTypeColumn(kind)) {
88 final int typeValue = item.getKindTypeColumn(kind);
Daniel Lehmannedb576a2011-07-27 16:45:13 -070089
Maurice Chu851222a2012-06-21 11:43:08 -070090 // get type string
Chiao Cheng47b6f702012-09-07 17:28:17 -070091 for (EditType type : kind.typeList) {
Maurice Chu851222a2012-06-21 11:43:08 -070092 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);
Daniel Lehmannedb576a2011-07-27 16:45:13 -070099 }
Maurice Chu851222a2012-06-21 11:43:08 -0700100 break;
Daniel Lehmannedb576a2011-07-27 16:45:13 -0700101 }
102 }
Daniel Lehmannaf8e3862010-11-19 15:38:44 -0800103 }
104
Paul Soulos16339332014-06-24 13:59:56 -0700105 mIsPrimary = item.isPrimary();
106 mIsSuperPrimary = item.isSuperPrimary();
Yorke Leeb2b435a2012-11-12 16:47:06 -0800107 mBody = item.buildDataStringForDisplay(context, kind);
Daniel Lehmannaf8e3862010-11-19 15:38:44 -0800108
Maurice Chu851222a2012-06-21 11:43:08 -0700109 mDataId = item.getId();
110 mDataUri = ContentUris.withAppendedId(Data.CONTENT_URI, mDataId);
Daniel Lehmannaf8e3862010-11-19 15:38:44 -0800111
Daniel Lehmannedb576a2011-07-27 16:45:13 -0700112 final boolean hasPhone = PhoneCapabilityTester.isPhone(mContext);
David Braun76de0fa2013-09-24 17:08:14 -0700113 final ComponentName smsComponent = PhoneCapabilityTester.getSmsComponent(mContext);
114 final boolean hasSms = (smsComponent != null);
Daniel Lehmannedb576a2011-07-27 16:45:13 -0700115
Daniel Lehmannaf8e3862010-11-19 15:38:44 -0800116 // Handle well-known MIME-types with special care
Maurice Chu851222a2012-06-21 11:43:08 -0700117 if (item instanceof PhoneDataItem) {
Daniel Lehmannaf8e3862010-11-19 15:38:44 -0800118 if (PhoneCapabilityTester.isPhone(mContext)) {
Maurice Chu851222a2012-06-21 11:43:08 -0700119 PhoneDataItem phone = (PhoneDataItem) item;
120 final String number = phone.getNumber();
Daniel Lehmannaf8e3862010-11-19 15:38:44 -0800121 if (!TextUtils.isEmpty(number)) {
Daniel Lehmannedb576a2011-07-27 16:45:13 -0700122
Chiao Cheng3a8df862012-09-04 16:30:17 -0700123 final Intent phoneIntent = hasPhone ? CallUtil.getCallIntent(number)
Daisuke Miyakawafadd5e12011-12-01 17:34:18 -0800124 : null;
David Braun76de0fa2013-09-24 17:08:14 -0700125 Intent smsIntent = null;
126 if (hasSms) {
127 smsIntent = new Intent(Intent.ACTION_SENDTO,
Jay Shrauner1cd88e32014-09-05 15:37:55 -0700128 Uri.fromParts(ContactsUtils.SCHEME_SMSTO, number, null));
David Braun76de0fa2013-09-24 17:08:14 -0700129 smsIntent.setComponent(smsComponent);
130 }
Daniel Lehmannedb576a2011-07-27 16:45:13 -0700131
132 // Configure Icons and Intents. Notice actionIcon is already set to the phone
133 if (hasPhone && hasSms) {
134 mIntent = phoneIntent;
135 mAlternateIntent = smsIntent;
Chiao Cheng47b6f702012-09-07 17:28:17 -0700136 mAlternateIconRes = kind.iconAltRes;
137 mAlternateIconDescriptionRes = kind.iconAltDescriptionRes;
Daniel Lehmannedb576a2011-07-27 16:45:13 -0700138 } else if (hasPhone) {
139 mIntent = phoneIntent;
140 } else if (hasSms) {
141 mIntent = smsIntent;
142 }
Daniel Lehmannaf8e3862010-11-19 15:38:44 -0800143 }
144 }
Maurice Chu851222a2012-06-21 11:43:08 -0700145 } else if (item instanceof SipAddressDataItem) {
Daniel Lehmannaf8e3862010-11-19 15:38:44 -0800146 if (PhoneCapabilityTester.isSipPhone(mContext)) {
Maurice Chu851222a2012-06-21 11:43:08 -0700147 final SipAddressDataItem sip = (SipAddressDataItem) item;
148 final String address = sip.getSipAddress();
Daniel Lehmannaf8e3862010-11-19 15:38:44 -0800149 if (!TextUtils.isEmpty(address)) {
Jay Shrauner1cd88e32014-09-05 15:37:55 -0700150 final Uri callUri = Uri.fromParts(PhoneAccount.SCHEME_SIP, address, null);
Chiao Cheng3a8df862012-09-04 16:30:17 -0700151 mIntent = CallUtil.getCallIntent(callUri);
Daniel Lehmannaf8e3862010-11-19 15:38:44 -0800152 // 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 }
Maurice Chu851222a2012-06-21 11:43:08 -0700160 } else if (item instanceof EmailDataItem) {
161 final EmailDataItem email = (EmailDataItem) item;
162 final String address = email.getData();
Daniel Lehmannaf8e3862010-11-19 15:38:44 -0800163 if (!TextUtils.isEmpty(address)) {
Jay Shrauner1cd88e32014-09-05 15:37:55 -0700164 final Uri mailUri = Uri.fromParts(ContactsUtils.SCHEME_MAILTO, address, null);
Daniel Lehmannaf8e3862010-11-19 15:38:44 -0800165 mIntent = new Intent(Intent.ACTION_SENDTO, mailUri);
166 }
167
Maurice Chu851222a2012-06-21 11:43:08 -0700168 } else if (item instanceof WebsiteDataItem) {
169 final WebsiteDataItem website = (WebsiteDataItem) item;
170 final String url = website.getUrl();
Daniel Lehmannaf8e3862010-11-19 15:38:44 -0800171 if (!TextUtils.isEmpty(url)) {
Brian Attwell493f8d12014-12-18 12:42:03 -0800172 try {
173 final WebAddress webAddress = new WebAddress(url);
174 mIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(webAddress.toString()));
175 } catch (ParseException e) {
176 mIntent = null;
177 }
Daniel Lehmannaf8e3862010-11-19 15:38:44 -0800178 }
179
Maurice Chu851222a2012-06-21 11:43:08 -0700180 } else if (item instanceof ImDataItem) {
181 ImDataItem im = (ImDataItem) item;
182 final boolean isEmail = im.isCreatedFromEmail();
183 if (isEmail || im.isProtocolValid()) {
184 final int protocol = isEmail ? Im.PROTOCOL_GOOGLE_TALK : im.getProtocol();
Daniel Lehmannaf8e3862010-11-19 15:38:44 -0800185
186 if (isEmail) {
187 // Use Google Talk string when using Email, and clear data
188 // Uri so we don't try saving Email as primary.
Daniel Lehmann9daca142011-12-20 11:41:22 +0200189 mSubtitle = Im.getProtocolLabel(context.getResources(), Im.PROTOCOL_GOOGLE_TALK,
190 null);
Daniel Lehmannaf8e3862010-11-19 15:38:44 -0800191 mDataUri = null;
192 }
193
Maurice Chu851222a2012-06-21 11:43:08 -0700194 String host = im.getCustomProtocol();
195 String data = im.getData();
Daniel Lehmannaf8e3862010-11-19 15:38:44 -0800196 if (protocol != Im.PROTOCOL_CUSTOM) {
197 // Try bringing in a well-known host for specific protocols
198 host = ContactsUtils.lookupProviderNameFromId(protocol);
199 }
200
Daisuke Miyakawaf31df5d2011-08-02 15:37:50 -0700201 if (!TextUtils.isEmpty(host) && !TextUtils.isEmpty(data)) {
Daniel Lehmannaf8e3862010-11-19 15:38:44 -0800202 final String authority = host.toLowerCase();
Jay Shrauner1cd88e32014-09-05 15:37:55 -0700203 final Uri imUri = new Uri.Builder().scheme(ContactsUtils.SCHEME_IMTO).authority(
Daniel Lehmannaf8e3862010-11-19 15:38:44 -0800204 authority).appendPath(data).build();
205 mIntent = new Intent(Intent.ACTION_SENDTO, imUri);
Daisuke Miyakawaf31df5d2011-08-02 15:37:50 -0700206
207 // If the address is also available for a video chat, we'll show the capability
208 // as a secondary action.
Maurice Chu851222a2012-06-21 11:43:08 -0700209 final int chatCapability = im.getChatCapability();
Daisuke Miyakawaf31df5d2011-08-02 15:37:50 -0700210 final boolean isVideoChatCapable =
211 (chatCapability & Im.CAPABILITY_HAS_CAMERA) != 0;
212 final boolean isAudioChatCapable =
213 (chatCapability & Im.CAPABILITY_HAS_VOICE) != 0;
214 if (isVideoChatCapable || isAudioChatCapable) {
Daisuke Miyakawaf31df5d2011-08-02 15:37:50 -0700215 mAlternateIntent = new Intent(
216 Intent.ACTION_SENDTO, Uri.parse("xmpp:" + data + "?call"));
Katherine Kuanee05dcd2011-10-05 20:18:12 -0700217 if (isVideoChatCapable) {
218 mAlternateIconRes = R.drawable.sym_action_videochat_holo_light;
219 mAlternateIconDescriptionRes = R.string.video_chat;
220 } else {
221 mAlternateIconRes = R.drawable.sym_action_audiochat_holo_light;
222 mAlternateIconDescriptionRes = R.string.audio_chat;
223 }
Daisuke Miyakawaf31df5d2011-08-02 15:37:50 -0700224 }
Daniel Lehmannaf8e3862010-11-19 15:38:44 -0800225 }
226 }
Maurice Chu851222a2012-06-21 11:43:08 -0700227 } else if (item instanceof StructuredPostalDataItem) {
228 StructuredPostalDataItem postal = (StructuredPostalDataItem) item;
229 final String postalAddress = postal.getFormattedAddress();
Makoto Onukibfb59d82011-09-30 16:34:38 -0700230 if (!TextUtils.isEmpty(postalAddress)) {
231 mIntent = StructuredPostalUtils.getViewPostalAddressIntent(postalAddress);
232 }
Daniel Lehmannaf8e3862010-11-19 15:38:44 -0800233 }
234
235 if (mIntent == null) {
236 // Otherwise fall back to default VIEW action
Dmitri Plotnikov1b89adc2010-12-09 17:05:54 -0800237 mIntent = new Intent(Intent.ACTION_VIEW);
Maurice Chu851222a2012-06-21 11:43:08 -0700238 mIntent.setDataAndType(mDataUri, item.getMimeType());
Daniel Lehmannaf8e3862010-11-19 15:38:44 -0800239 }
240
Adam Powell8ca93ed2012-04-23 13:28:28 -0700241 mIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
Daniel Lehmannaf8e3862010-11-19 15:38:44 -0800242 }
243
Daniel Lehmann9daca142011-12-20 11:41:22 +0200244 @Override
245 public int getPresence() {
246 return mPresence;
247 }
248
249 public void setPresence(int presence) {
250 mPresence = presence;
251 }
252
Daniel Lehmannaf8e3862010-11-19 15:38:44 -0800253 @Override
Daniel Lehmannedb576a2011-07-27 16:45:13 -0700254 public CharSequence getSubtitle() {
255 return mSubtitle;
Daniel Lehmannaf8e3862010-11-19 15:38:44 -0800256 }
257
Daniel Lehmannaf8e3862010-11-19 15:38:44 -0800258 @Override
259 public CharSequence getBody() {
260 return mBody;
261 }
262
Daniel Lehmannaf8e3862010-11-19 15:38:44 -0800263 @Override
264 public String getMimeType() {
265 return mMimeType;
266 }
267
Daniel Lehmannaf8e3862010-11-19 15:38:44 -0800268 @Override
269 public Uri getDataUri() {
270 return mDataUri;
271 }
272
Daniel Lehmannaf8e3862010-11-19 15:38:44 -0800273 @Override
Daniel Lehmann0f78e8b2010-11-24 17:32:03 -0800274 public long getDataId() {
275 return mDataId;
276 }
277
Daniel Lehmann0f78e8b2010-11-24 17:32:03 -0800278 @Override
Paul Soulos16339332014-06-24 13:59:56 -0700279 public boolean isPrimary() {
Daniel Lehmannaf8e3862010-11-19 15:38:44 -0800280 return mIsPrimary;
281 }
282
Daniel Lehmannaf8e3862010-11-19 15:38:44 -0800283 @Override
Paul Soulos16339332014-06-24 13:59:56 -0700284 public boolean isSuperPrimary() {
285 return mIsSuperPrimary;
286 }
287
288 @Override
Daniel Lehmannedb576a2011-07-27 16:45:13 -0700289 public Drawable getAlternateIcon() {
290 if (mAlternateIconRes == 0) return null;
291
Makoto Onuki82a4f442012-05-07 17:18:33 -0700292 final String resourcePackageName = mKind.resourcePackageName;
293 if (resourcePackageName == null) {
Daniel Lehmannedb576a2011-07-27 16:45:13 -0700294 return mContext.getResources().getDrawable(mAlternateIconRes);
295 }
Daniel Lehmannaf8e3862010-11-19 15:38:44 -0800296
297 final PackageManager pm = mContext.getPackageManager();
Makoto Onuki82a4f442012-05-07 17:18:33 -0700298 return pm.getDrawable(resourcePackageName, mAlternateIconRes, null);
Daniel Lehmannaf8e3862010-11-19 15:38:44 -0800299 }
300
Daniel Lehmannaf8e3862010-11-19 15:38:44 -0800301 @Override
Katherine Kuanee05dcd2011-10-05 20:18:12 -0700302 public String getAlternateIconDescription() {
303 if (mAlternateIconDescriptionRes == 0) return null;
304 return mContext.getResources().getString(mAlternateIconDescriptionRes);
305 }
306
307 @Override
Daniel Lehmannaf8e3862010-11-19 15:38:44 -0800308 public Intent getIntent() {
309 return mIntent;
310 }
311
Daniel Lehmannedb576a2011-07-27 16:45:13 -0700312 @Override
313 public Intent getAlternateIntent() {
314 return mAlternateIntent;
315 }
316
Daniel Lehmannaf8e3862010-11-19 15:38:44 -0800317 @Override
Jay Shraunerad29eae2013-01-08 11:42:17 -0800318 public void collapseWith(Action other) {
319 // No-op
Daniel Lehmannaf8e3862010-11-19 15:38:44 -0800320 }
321
Daniel Lehmannaf8e3862010-11-19 15:38:44 -0800322 @Override
Paul Soulos0646ee32014-06-26 16:40:28 -0700323 public boolean shouldCollapseWith(Action t, Context context) {
Daniel Lehmannaf8e3862010-11-19 15:38:44 -0800324 if (t == null) {
325 return false;
326 }
327 if (!(t instanceof DataAction)) {
328 Log.e(TAG, "t must be DataAction");
329 return false;
330 }
Daniel Lehmann69fad282011-08-28 21:15:27 -0700331 DataAction that = (DataAction)t;
Chiao Chengd7ca03e2012-10-24 15:14:08 -0700332 if (!MoreContactUtils.shouldCollapse(mMimeType, mBody, that.mMimeType, that.mBody)) {
Daniel Lehmannaf8e3862010-11-19 15:38:44 -0800333 return false;
334 }
Daniel Lehmann69fad282011-08-28 21:15:27 -0700335 if (!TextUtils.equals(mMimeType, that.mMimeType)
336 || !ContactsUtils.areIntentActionEqual(mIntent, that.mIntent)) {
Daniel Lehmannaf8e3862010-11-19 15:38:44 -0800337 return false;
338 }
339 return true;
340 }
Paul Soulos16339332014-06-24 13:59:56 -0700341
342 @Override
343 public Integer getTimesUsed() {
344 return mTimesUsed;
345 }
346
347 @Override
348 public Long getLastTimeUsed() {
349 return mLastTimeUsed;
350 }
Daniel Lehmannaf8e3862010-11-19 15:38:44 -0800351}