blob: 4593591ab05a5fb145b3e931b9eeec86603c7a82 [file] [log] [blame]
Daniel Lehmannaf8e3862010-11-19 15:38:44 -08001package com.android.contacts.quickcontact;
2
3import com.android.contacts.ContactsUtils;
4import com.android.contacts.R;
5import com.android.contacts.model.AccountType.DataKind;
6import com.android.contacts.util.Constants;
7import com.android.contacts.util.PhoneCapabilityTester;
8
9import android.content.ContentUris;
10import android.content.Context;
11import android.content.Intent;
12import android.content.pm.PackageManager;
13import android.database.Cursor;
14import android.graphics.drawable.Drawable;
15import android.net.Uri;
16import android.provider.ContactsContract.Data;
17import android.provider.ContactsContract.CommonDataKinds.Email;
18import android.provider.ContactsContract.CommonDataKinds.Im;
19import android.provider.ContactsContract.CommonDataKinds.Phone;
20import android.provider.ContactsContract.CommonDataKinds.SipAddress;
21import android.provider.ContactsContract.CommonDataKinds.Website;
22import android.text.TextUtils;
23import android.util.Log;
24
25/**
26 * Description of a specific {@link Data#_ID} item, with style information
27 * defined by a {@link DataKind}.
28 */
29public class DataAction implements Action {
30 private static final String TAG = "DataAction";
31
32 private final Context mContext;
33 private final DataKind mKind;
34 private final String mMimeType;
35
36 private CharSequence mHeader;
37 private CharSequence mBody;
38 private Intent mIntent;
39
40 private boolean mAlternate;
41 private Uri mDataUri;
Daniel Lehmann0f78e8b2010-11-24 17:32:03 -080042 private long mDataId;
Daniel Lehmannaf8e3862010-11-19 15:38:44 -080043 private boolean mIsPrimary;
44
45 /**
46 * Create an action from common {@link Data} elements.
47 */
48 public DataAction(Context context, String mimeType, DataKind kind,
49 long dataId, Cursor cursor) {
50 mContext = context;
51 mKind = kind;
52 mMimeType = mimeType;
53
54 // Inflate strings from cursor
55 mAlternate = Constants.MIME_SMS_ADDRESS.equals(mimeType);
56 if (mAlternate && mKind.actionAltHeader != null) {
57 mHeader = mKind.actionAltHeader.inflateUsing(context, cursor);
58 } else if (mKind.actionHeader != null) {
59 mHeader = mKind.actionHeader.inflateUsing(context, cursor);
60 }
61
62 if (getAsInt(cursor, Data.IS_SUPER_PRIMARY) != 0) {
63 mIsPrimary = true;
64 }
65
66 if (mKind.actionBody != null) {
67 mBody = mKind.actionBody.inflateUsing(context, cursor);
68 }
69
Daniel Lehmann0f78e8b2010-11-24 17:32:03 -080070 mDataId = dataId;
Daniel Lehmannaf8e3862010-11-19 15:38:44 -080071 mDataUri = ContentUris.withAppendedId(Data.CONTENT_URI, dataId);
72
73 // Handle well-known MIME-types with special care
74 if (Phone.CONTENT_ITEM_TYPE.equals(mimeType)) {
75 if (PhoneCapabilityTester.isPhone(mContext)) {
76 final String number = getAsString(cursor, Phone.NUMBER);
77 if (!TextUtils.isEmpty(number)) {
78 final Uri callUri = Uri.fromParts(Constants.SCHEME_TEL, number, null);
79 mIntent = new Intent(Intent.ACTION_CALL_PRIVILEGED, callUri);
80 }
81 }
82 } else if (SipAddress.CONTENT_ITEM_TYPE.equals(mimeType)) {
83 if (PhoneCapabilityTester.isSipPhone(mContext)) {
84 final String address = getAsString(cursor, SipAddress.SIP_ADDRESS);
85 if (!TextUtils.isEmpty(address)) {
86 final Uri callUri = Uri.fromParts(Constants.SCHEME_SIP, address, null);
87 mIntent = new Intent(Intent.ACTION_CALL_PRIVILEGED, callUri);
88 // Note that this item will get a SIP-specific variant
89 // of the "call phone" icon, rather than the standard
90 // app icon for the Phone app (which we show for
91 // regular phone numbers.) That's because the phone
92 // app explicitly specifies an android:icon attribute
93 // for the SIP-related intent-filters in its manifest.
94 }
95 }
96 } else if (Constants.MIME_SMS_ADDRESS.equals(mimeType)) {
97 if (PhoneCapabilityTester.isSmsIntentRegistered(mContext)) {
98 final String number = getAsString(cursor, Phone.NUMBER);
99 if (!TextUtils.isEmpty(number)) {
100 final Uri smsUri = Uri.fromParts(Constants.SCHEME_SMSTO, number, null);
101 mIntent = new Intent(Intent.ACTION_SENDTO, smsUri);
102 }
103 }
104 } else if (Email.CONTENT_ITEM_TYPE.equals(mimeType)) {
105 final String address = getAsString(cursor, Email.DATA);
106 if (!TextUtils.isEmpty(address)) {
107 final Uri mailUri = Uri.fromParts(Constants.SCHEME_MAILTO, address, null);
108 mIntent = new Intent(Intent.ACTION_SENDTO, mailUri);
109 }
110
111 } else if (Website.CONTENT_ITEM_TYPE.equals(mimeType)) {
112 final String url = getAsString(cursor, Website.URL);
113 if (!TextUtils.isEmpty(url)) {
114 mIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
115 }
116
117 } else if (Im.CONTENT_ITEM_TYPE.equals(mimeType)) {
118 final boolean isEmail = Email.CONTENT_ITEM_TYPE.equals(
119 getAsString(cursor, Data.MIMETYPE));
120 if (isEmail || isProtocolValid(cursor)) {
121 final int protocol = isEmail ? Im.PROTOCOL_GOOGLE_TALK :
122 getAsInt(cursor, Im.PROTOCOL);
123
124 if (isEmail) {
125 // Use Google Talk string when using Email, and clear data
126 // Uri so we don't try saving Email as primary.
127 mHeader = context.getText(R.string.chat_gtalk);
128 mDataUri = null;
129 }
130
131 String host = getAsString(cursor, Im.CUSTOM_PROTOCOL);
132 String data = getAsString(cursor,
133 isEmail ? Email.DATA : Im.DATA);
134 if (protocol != Im.PROTOCOL_CUSTOM) {
135 // Try bringing in a well-known host for specific protocols
136 host = ContactsUtils.lookupProviderNameFromId(protocol);
137 }
138
139 if (!TextUtils.isEmpty(host) && !TextUtils.isEmpty(data)) {
140 final String authority = host.toLowerCase();
141 final Uri imUri = new Uri.Builder().scheme(Constants.SCHEME_IMTO).authority(
142 authority).appendPath(data).build();
143 mIntent = new Intent(Intent.ACTION_SENDTO, imUri);
144 }
145 }
146 }
147
148 if (mIntent == null) {
149 // Otherwise fall back to default VIEW action
150 mIntent = new Intent(Intent.ACTION_VIEW, mDataUri);
151 }
152
153 // Always launch as new task, since we're like a launcher
154 mIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
155 }
156
157 /** Read {@link String} from the given {@link Cursor}. */
158 private static String getAsString(Cursor cursor, String columnName) {
159 final int index = cursor.getColumnIndex(columnName);
160 return cursor.getString(index);
161 }
162
163 /** Read {@link Integer} from the given {@link Cursor}. */
164 private static int getAsInt(Cursor cursor, String columnName) {
165 final int index = cursor.getColumnIndex(columnName);
166 return cursor.getInt(index);
167 }
168
169 private boolean isProtocolValid(Cursor cursor) {
170 final int columnIndex = cursor.getColumnIndex(Im.PROTOCOL);
171 if (cursor.isNull(columnIndex)) {
172 return false;
173 }
174 try {
175 Integer.valueOf(cursor.getString(columnIndex));
176 } catch (NumberFormatException e) {
177 return false;
178 }
179 return true;
180 }
181
182 /** {@inheritDoc} */
183 @Override
184 public CharSequence getHeader() {
185 return mHeader;
186 }
187
188 /** {@inheritDoc} */
189 @Override
190 public CharSequence getBody() {
191 return mBody;
192 }
193
194 /** {@inheritDoc} */
195 @Override
196 public String getMimeType() {
197 return mMimeType;
198 }
199
200 /** {@inheritDoc} */
201 @Override
202 public Uri getDataUri() {
203 return mDataUri;
204 }
205
206 /** {@inheritDoc} */
207 @Override
Daniel Lehmann0f78e8b2010-11-24 17:32:03 -0800208 public long getDataId() {
209 return mDataId;
210 }
211
212 /** {@inheritDoc} */
213 @Override
Daniel Lehmannaf8e3862010-11-19 15:38:44 -0800214 public Boolean isPrimary() {
215 return mIsPrimary;
216 }
217
218 /** {@inheritDoc} */
219 @Override
220 public Drawable getFallbackIcon() {
221 // Bail early if no valid resources
222 final String resPackageName = mKind.resPackageName;
223 if (resPackageName == null) return null;
224
225 final PackageManager pm = mContext.getPackageManager();
226 if (mAlternate && mKind.iconAltRes != -1) {
227 return pm.getDrawable(resPackageName, mKind.iconAltRes, null);
228 } else if (mKind.iconRes != -1) {
229 return pm.getDrawable(resPackageName, mKind.iconRes, null);
230 } else {
231 return null;
232 }
233 }
234
235 /** {@inheritDoc} */
236 @Override
237 public Intent getIntent() {
238 return mIntent;
239 }
240
241 /** {@inheritDoc} */
242 @Override
243 public boolean collapseWith(Action other) {
244 if (!shouldCollapseWith(other)) {
245 return false;
246 }
247 return true;
248 }
249
250 /** {@inheritDoc} */
251 @Override
252 public boolean shouldCollapseWith(Action t) {
253 if (t == null) {
254 return false;
255 }
256 if (!(t instanceof DataAction)) {
257 Log.e(TAG, "t must be DataAction");
258 return false;
259 }
260 DataAction other = (DataAction)t;
261 if (!ContactsUtils.areObjectsEqual(mKind, other.mKind)) {
262 return false;
263 }
264 if (!ContactsUtils.shouldCollapse(mContext, mMimeType, mBody, other.mMimeType,
265 other.mBody)) {
266 return false;
267 }
268 if (!TextUtils.equals(mMimeType, other.mMimeType)
269 || !ContactsUtils.areIntentActionEqual(mIntent, other.mIntent)
270 ) {
271 return false;
272 }
273 return true;
274 }
275}