blob: 685bd7dc8ae18b270c301f92ebb7f566e93162a2 [file] [log] [blame]
Daniel Lehmann4cd94412010-04-08 16:44:36 -07001/*
Daniel Lehmannef3f8f02010-07-26 18:55:25 -07002 * Copyright (C) 2010 The Android Open Source Project
Daniel Lehmann4cd94412010-04-08 16:44:36 -07003 *
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
Dmitri Plotnikov18ffaa22010-12-03 14:28:00 -080017package com.android.contacts;
Daniel Lehmann4cd94412010-04-08 16:44:36 -070018
Makoto Onuki69b4a882011-07-22 10:05:10 -070019import com.android.contacts.model.AccountType;
20import com.android.contacts.model.AccountTypeManager;
Makoto Onuki6ad227f2011-08-15 13:46:59 -070021import com.android.contacts.model.AccountTypeWithDataSet;
Katherine Kuan6cd5b0a2011-09-16 11:46:01 -070022import com.android.contacts.util.ContactLoaderUtils;
Daniel Lehmann4cd94412010-04-08 16:44:36 -070023import com.android.contacts.util.DataStatus;
Dave Santoro39156002011-07-19 01:18:14 -070024import com.android.contacts.util.StreamItemEntry;
25import com.android.contacts.util.StreamItemPhotoEntry;
Makoto Onuki69b4a882011-07-22 10:05:10 -070026import com.google.android.collect.Lists;
Flavio Lerda37a26842011-06-27 11:36:52 +010027import com.google.common.annotations.VisibleForTesting;
Makoto Onuki6ad227f2011-08-15 13:46:59 -070028import com.google.common.collect.Maps;
Makoto Onukiaba2b832011-08-12 15:44:53 -070029import com.google.common.collect.Sets;
Daniel Lehmann4cd94412010-04-08 16:44:36 -070030
31import android.content.ContentResolver;
32import android.content.ContentUris;
Dmitri Plotnikov4d444242010-07-30 11:39:39 -070033import android.content.ContentValues;
Daniel Lehmann4cd94412010-04-08 16:44:36 -070034import android.content.Context;
35import android.content.Entity;
Dmitri Plotnikovcaf0bc72010-09-03 15:16:21 -070036import android.content.Entity.NamedContentValues;
Daniel Lehmann3ef27fb2011-08-09 14:31:29 -070037import android.content.Intent;
Jeff Hamilton3c462912010-05-15 02:20:01 -050038import android.content.Loader;
Dmitri Plotnikov02cd4912010-09-01 20:42:17 -070039import android.content.pm.PackageManager;
40import android.content.pm.PackageManager.NameNotFoundException;
Dave Santoro0a2a5db2011-06-29 00:37:06 -070041import android.content.res.AssetFileDescriptor;
Dmitri Plotnikov02cd4912010-09-01 20:42:17 -070042import android.content.res.Resources;
Daniel Lehmann4cd94412010-04-08 16:44:36 -070043import android.database.Cursor;
44import android.net.Uri;
45import android.os.AsyncTask;
Daniel Lehmann1316b132010-04-13 15:08:53 -070046import android.provider.ContactsContract;
Dmitri Plotnikov4d444242010-07-30 11:39:39 -070047import android.provider.ContactsContract.CommonDataKinds.GroupMembership;
Dmitri Plotnikov7f4f8d12010-11-10 10:22:19 -080048import android.provider.ContactsContract.CommonDataKinds.Photo;
Daniel Lehmann4cd94412010-04-08 16:44:36 -070049import android.provider.ContactsContract.Contacts;
50import android.provider.ContactsContract.Data;
Dmitri Plotnikov02cd4912010-09-01 20:42:17 -070051import android.provider.ContactsContract.Directory;
Daniel Lehmann4cd94412010-04-08 16:44:36 -070052import android.provider.ContactsContract.DisplayNameSources;
Dmitri Plotnikov2deaee12010-09-15 15:42:08 -070053import android.provider.ContactsContract.Groups;
Daniel Lehmann4cd94412010-04-08 16:44:36 -070054import android.provider.ContactsContract.RawContacts;
Dave Santoro39156002011-07-19 01:18:14 -070055import android.provider.ContactsContract.StreamItemPhotos;
Makoto Onuki69b4a882011-07-22 10:05:10 -070056import android.provider.ContactsContract.StreamItems;
Dmitri Plotnikov02cd4912010-09-01 20:42:17 -070057import android.text.TextUtils;
Daniel Lehmann4cd94412010-04-08 16:44:36 -070058import android.util.Log;
Daniel Lehmann18958a22012-02-28 17:45:25 -080059import android.util.LongSparseArray;
Daniel Lehmann4cd94412010-04-08 16:44:36 -070060
Dmitri Plotnikov7f4f8d12010-11-10 10:22:19 -080061import java.io.ByteArrayOutputStream;
Dave Santoro0a2a5db2011-06-29 00:37:06 -070062import java.io.FileInputStream;
Dmitri Plotnikov7f4f8d12010-11-10 10:22:19 -080063import java.io.IOException;
Daniel Lehmann4cd94412010-04-08 16:44:36 -070064import java.util.ArrayList;
Dave Santoro39156002011-07-19 01:18:14 -070065import java.util.Collections;
Dmitri Plotnikovcaf0bc72010-09-03 15:16:21 -070066import java.util.List;
Dave Santoro39156002011-07-19 01:18:14 -070067import java.util.Map;
Makoto Onukiaba2b832011-08-12 15:44:53 -070068import java.util.Set;
Daniel Lehmann4cd94412010-04-08 16:44:36 -070069
70/**
71 * Loads a single Contact and all it constituent RawContacts.
72 */
Daniel Lehmanncdef2b62010-06-06 18:25:49 -070073public class ContactLoader extends Loader<ContactLoader.Result> {
Daniel Lehmann18f104f2010-05-07 15:41:11 -070074 private static final String TAG = "ContactLoader";
75
Makoto Onukida9cdc12012-02-27 16:11:50 -080076 private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
77
Daniel Lehmann685157e2011-08-29 21:07:01 -070078 private final Uri mRequestedUri;
Makoto Onuki2621c5b2011-10-03 12:56:16 -070079 private Uri mLookupUri;
Dmitri Plotnikove843f912010-09-16 15:21:48 -070080 private boolean mLoadGroupMetaData;
Dave Santoro39156002011-07-19 01:18:14 -070081 private boolean mLoadStreamItems;
Makoto Onuki69b4a882011-07-22 10:05:10 -070082 private final boolean mLoadInvitableAccountTypes;
Daniel Lehmann4cd94412010-04-08 16:44:36 -070083 private Result mContact;
84 private ForceLoadContentObserver mObserver;
85 private boolean mDestroyed;
Makoto Onukiaba2b832011-08-12 15:44:53 -070086 private final Set<Long> mNotifiedRawContactIds = Sets.newHashSet();
Dmitri Plotnikove843f912010-09-16 15:21:48 -070087
Daniel Lehmanncdef2b62010-06-06 18:25:49 -070088 public interface Listener {
Daniel Lehmann4cd94412010-04-08 16:44:36 -070089 public void onContactLoaded(Result contact);
90 }
91
92 /**
93 * The result of a load operation. Contains all data necessary to display the contact.
94 */
95 public static final class Result {
Makoto Onuki2621c5b2011-10-03 12:56:16 -070096 private enum Status {
97 /** Contact is successfully loaded */
98 LOADED,
99 /** There was an error loading the contact */
100 ERROR,
101 /** Contact is not found */
102 NOT_FOUND,
103 }
Daniel Lehmann18f104f2010-05-07 15:41:11 -0700104
Daniel Lehmann685157e2011-08-29 21:07:01 -0700105 private final Uri mRequestedUri;
Daniel Lehmann4cd94412010-04-08 16:44:36 -0700106 private final Uri mLookupUri;
Daniel Lehmann4cd94412010-04-08 16:44:36 -0700107 private final Uri mUri;
Dmitri Plotnikov02cd4912010-09-01 20:42:17 -0700108 private final long mDirectoryId;
109 private final String mLookupKey;
Daniel Lehmann4cd94412010-04-08 16:44:36 -0700110 private final long mId;
Daniel Lehmann4cd94412010-04-08 16:44:36 -0700111 private final long mNameRawContactId;
112 private final int mDisplayNameSource;
Daniel Lehmannd3e0cdb2010-04-19 13:45:53 -0700113 private final long mPhotoId;
Dmitri Plotnikovf9eb73f2010-10-21 11:48:56 -0700114 private final String mPhotoUri;
Daniel Lehmannd3e0cdb2010-04-19 13:45:53 -0700115 private final String mDisplayName;
Dave Santoroda5bf1c2011-05-03 10:30:34 -0700116 private final String mAltDisplayName;
Daniel Lehmannd3e0cdb2010-04-19 13:45:53 -0700117 private final String mPhoneticName;
118 private final boolean mStarred;
119 private final Integer mPresence;
120 private final ArrayList<Entity> mEntities;
Makoto Onuki870a87e2011-08-12 13:40:31 -0700121 private final ArrayList<StreamItemEntry> mStreamItems;
Daniel Lehmann18958a22012-02-28 17:45:25 -0800122 private final LongSparseArray<DataStatus> mStatuses;
Dave Santoro2b3f3c52011-07-26 17:35:42 -0700123 private final ArrayList<AccountType> mInvitableAccountTypes;
Daniel Lehmann4cd94412010-04-08 16:44:36 -0700124
Dmitri Plotnikov02cd4912010-09-01 20:42:17 -0700125 private String mDirectoryDisplayName;
126 private String mDirectoryType;
Dmitri Plotnikovcaf0bc72010-09-03 15:16:21 -0700127 private String mDirectoryAccountType;
Dmitri Plotnikov02cd4912010-09-01 20:42:17 -0700128 private String mDirectoryAccountName;
129 private int mDirectoryExportSupport;
130
Dmitri Plotnikove843f912010-09-16 15:21:48 -0700131 private ArrayList<GroupMetaData> mGroups;
Dmitri Plotnikov2deaee12010-09-15 15:42:08 -0700132
Dmitri Plotnikov7f4f8d12010-11-10 10:22:19 -0800133 private byte[] mPhotoBinaryData;
Makoto Onuki870a87e2011-08-12 13:40:31 -0700134 private final boolean mSendToVoicemail;
135 private final String mCustomRingtone;
136 private final boolean mIsUserProfile;
Dmitri Plotnikov7f4f8d12010-11-10 10:22:19 -0800137
Makoto Onuki2621c5b2011-10-03 12:56:16 -0700138 private final Status mStatus;
Makoto Onuki9e7b5da2011-08-22 15:51:28 -0700139 private final Exception mException;
140
Daniel Lehmann4cd94412010-04-08 16:44:36 -0700141 /**
Makoto Onuki9e7b5da2011-08-22 15:51:28 -0700142 * Constructor for special results, namely "no contact found" and "error".
Daniel Lehmann4cd94412010-04-08 16:44:36 -0700143 */
Makoto Onuki2621c5b2011-10-03 12:56:16 -0700144 private Result(Uri requestedUri, Status status, Exception exception) {
145 if (status == Status.ERROR && exception == null) {
146 throw new IllegalArgumentException("ERROR result must have exception");
147 }
148 mStatus = status;
149 mException = exception;
150 mRequestedUri = requestedUri;
Daniel Lehmann4cd94412010-04-08 16:44:36 -0700151 mLookupUri = null;
Daniel Lehmann4cd94412010-04-08 16:44:36 -0700152 mUri = null;
Dmitri Plotnikov02cd4912010-09-01 20:42:17 -0700153 mDirectoryId = -1;
154 mLookupKey = null;
Daniel Lehmann4cd94412010-04-08 16:44:36 -0700155 mId = -1;
156 mEntities = null;
Dave Santoro39156002011-07-19 01:18:14 -0700157 mStreamItems = new ArrayList<StreamItemEntry>();
Daniel Lehmann4cd94412010-04-08 16:44:36 -0700158 mStatuses = null;
159 mNameRawContactId = -1;
160 mDisplayNameSource = DisplayNameSources.UNDEFINED;
Daniel Lehmannd3e0cdb2010-04-19 13:45:53 -0700161 mPhotoId = -1;
Dmitri Plotnikovf9eb73f2010-10-21 11:48:56 -0700162 mPhotoUri = null;
Daniel Lehmannd3e0cdb2010-04-19 13:45:53 -0700163 mDisplayName = null;
Dave Santoroda5bf1c2011-05-03 10:30:34 -0700164 mAltDisplayName = null;
Daniel Lehmannd3e0cdb2010-04-19 13:45:53 -0700165 mPhoneticName = null;
166 mStarred = false;
167 mPresence = null;
Makoto Onuki69b4a882011-07-22 10:05:10 -0700168 mInvitableAccountTypes = null;
Isaac Katzenelson683b57e2011-07-20 17:06:11 -0700169 mSendToVoicemail = false;
170 mCustomRingtone = null;
Isaac Katzenelsonead19c52011-07-29 18:24:53 -0700171 mIsUserProfile = false;
Makoto Onuki9e7b5da2011-08-22 15:51:28 -0700172 }
Isaac Katzenelsonead19c52011-07-29 18:24:53 -0700173
Makoto Onuki2621c5b2011-10-03 12:56:16 -0700174 private static Result forError(Uri requestedUri, Exception exception) {
175 return new Result(requestedUri, Status.ERROR, exception);
176 }
177
178 private static Result forNotFound(Uri requestedUri) {
179 return new Result(requestedUri, Status.NOT_FOUND, null);
Daniel Lehmann4cd94412010-04-08 16:44:36 -0700180 }
181
182 /**
183 * Constructor to call when contact was found
184 */
Daniel Lehmann685157e2011-08-29 21:07:01 -0700185 private Result(Uri requestedUri, Uri uri, Uri lookupUri, long directoryId, String lookupKey,
186 long id, long nameRawContactId, int displayNameSource, long photoId,
187 String photoUri, String displayName, String altDisplayName, String phoneticName,
188 boolean starred, Integer presence, boolean sendToVoicemail, String customRingtone,
Isaac Katzenelsonead19c52011-07-29 18:24:53 -0700189 boolean isUserProfile) {
Makoto Onuki2621c5b2011-10-03 12:56:16 -0700190 mStatus = Status.LOADED;
Makoto Onuki9e7b5da2011-08-22 15:51:28 -0700191 mException = null;
Daniel Lehmann685157e2011-08-29 21:07:01 -0700192 mRequestedUri = requestedUri;
Daniel Lehmann4cd94412010-04-08 16:44:36 -0700193 mLookupUri = lookupUri;
Daniel Lehmann4cd94412010-04-08 16:44:36 -0700194 mUri = uri;
Dmitri Plotnikov02cd4912010-09-01 20:42:17 -0700195 mDirectoryId = directoryId;
196 mLookupKey = lookupKey;
Daniel Lehmann4cd94412010-04-08 16:44:36 -0700197 mId = id;
198 mEntities = new ArrayList<Entity>();
Dave Santoro39156002011-07-19 01:18:14 -0700199 mStreamItems = new ArrayList<StreamItemEntry>();
Daniel Lehmann18958a22012-02-28 17:45:25 -0800200 mStatuses = new LongSparseArray<DataStatus>();
Daniel Lehmann4cd94412010-04-08 16:44:36 -0700201 mNameRawContactId = nameRawContactId;
202 mDisplayNameSource = displayNameSource;
Daniel Lehmannd3e0cdb2010-04-19 13:45:53 -0700203 mPhotoId = photoId;
Dmitri Plotnikovf9eb73f2010-10-21 11:48:56 -0700204 mPhotoUri = photoUri;
Daniel Lehmannd3e0cdb2010-04-19 13:45:53 -0700205 mDisplayName = displayName;
Dave Santoroda5bf1c2011-05-03 10:30:34 -0700206 mAltDisplayName = altDisplayName;
Daniel Lehmannd3e0cdb2010-04-19 13:45:53 -0700207 mPhoneticName = phoneticName;
208 mStarred = starred;
209 mPresence = presence;
Makoto Onuki69b4a882011-07-22 10:05:10 -0700210 mInvitableAccountTypes = Lists.newArrayList();
Isaac Katzenelson683b57e2011-07-20 17:06:11 -0700211 mSendToVoicemail = sendToVoicemail;
212 mCustomRingtone = customRingtone;
Isaac Katzenelsonead19c52011-07-29 18:24:53 -0700213 mIsUserProfile = isUserProfile;
Daniel Lehmann4cd94412010-04-08 16:44:36 -0700214 }
215
Dmitri Plotnikov7cee7742011-01-13 17:11:06 -0800216 private Result(Result from) {
Makoto Onuki2621c5b2011-10-03 12:56:16 -0700217 mStatus = from.mStatus;
Makoto Onuki9e7b5da2011-08-22 15:51:28 -0700218 mException = from.mException;
Daniel Lehmann685157e2011-08-29 21:07:01 -0700219 mRequestedUri = from.mRequestedUri;
Dmitri Plotnikov7cee7742011-01-13 17:11:06 -0800220 mLookupUri = from.mLookupUri;
221 mUri = from.mUri;
222 mDirectoryId = from.mDirectoryId;
223 mLookupKey = from.mLookupKey;
224 mId = from.mId;
225 mNameRawContactId = from.mNameRawContactId;
226 mDisplayNameSource = from.mDisplayNameSource;
227 mPhotoId = from.mPhotoId;
228 mPhotoUri = from.mPhotoUri;
229 mDisplayName = from.mDisplayName;
Dave Santoroda5bf1c2011-05-03 10:30:34 -0700230 mAltDisplayName = from.mAltDisplayName;
Dmitri Plotnikov7cee7742011-01-13 17:11:06 -0800231 mPhoneticName = from.mPhoneticName;
232 mStarred = from.mStarred;
233 mPresence = from.mPresence;
234 mEntities = from.mEntities;
Dave Santoro39156002011-07-19 01:18:14 -0700235 mStreamItems = from.mStreamItems;
Dmitri Plotnikov7cee7742011-01-13 17:11:06 -0800236 mStatuses = from.mStatuses;
Makoto Onuki69b4a882011-07-22 10:05:10 -0700237 mInvitableAccountTypes = from.mInvitableAccountTypes;
Dmitri Plotnikov7cee7742011-01-13 17:11:06 -0800238
239 mDirectoryDisplayName = from.mDirectoryDisplayName;
240 mDirectoryType = from.mDirectoryType;
241 mDirectoryAccountType = from.mDirectoryAccountType;
242 mDirectoryAccountName = from.mDirectoryAccountName;
243 mDirectoryExportSupport = from.mDirectoryExportSupport;
244
245 mGroups = from.mGroups;
246
Dmitri Plotnikov7cee7742011-01-13 17:11:06 -0800247 mPhotoBinaryData = from.mPhotoBinaryData;
Isaac Katzenelson683b57e2011-07-20 17:06:11 -0700248 mSendToVoicemail = from.mSendToVoicemail;
249 mCustomRingtone = from.mCustomRingtone;
Isaac Katzenelsonead19c52011-07-29 18:24:53 -0700250 mIsUserProfile = from.mIsUserProfile;
Dmitri Plotnikov7cee7742011-01-13 17:11:06 -0800251 }
252
Dmitri Plotnikov02cd4912010-09-01 20:42:17 -0700253 /**
254 * @param exportSupport See {@link Directory#EXPORT_SUPPORT}.
255 */
Daniel Lehmann1ad4d1b2010-10-18 19:20:41 -0700256 private void setDirectoryMetaData(String displayName, String directoryType,
Dmitri Plotnikovcaf0bc72010-09-03 15:16:21 -0700257 String accountType, String accountName, int exportSupport) {
Dmitri Plotnikov02cd4912010-09-01 20:42:17 -0700258 mDirectoryDisplayName = displayName;
259 mDirectoryType = directoryType;
Dmitri Plotnikovcaf0bc72010-09-03 15:16:21 -0700260 mDirectoryAccountType = accountType;
Dmitri Plotnikov02cd4912010-09-01 20:42:17 -0700261 mDirectoryAccountName = accountName;
262 mDirectoryExportSupport = exportSupport;
263 }
264
Dmitri Plotnikov7f4f8d12010-11-10 10:22:19 -0800265 private void setPhotoBinaryData(byte[] photoBinaryData) {
266 mPhotoBinaryData = photoBinaryData;
267 }
268
Daniel Lehmann685157e2011-08-29 21:07:01 -0700269 /**
270 * Returns the URI for the contact that contains both the lookup key and the ID. This is
271 * the best URI to reference a contact.
272 * For directory contacts, this is the same a the URI as returned by {@link #getUri()}
273 */
Daniel Lehmann4cd94412010-04-08 16:44:36 -0700274 public Uri getLookupUri() {
275 return mLookupUri;
276 }
Dmitri Plotnikov7f4f8d12010-11-10 10:22:19 -0800277
Daniel Lehmann4cd94412010-04-08 16:44:36 -0700278 public String getLookupKey() {
279 return mLookupKey;
280 }
Dmitri Plotnikov7f4f8d12010-11-10 10:22:19 -0800281
Daniel Lehmann685157e2011-08-29 21:07:01 -0700282 /**
283 * Returns the contact Uri that was passed to the provider to make the query. This is
284 * the same as the requested Uri, unless the requested Uri doesn't specify a Contact:
285 * If it either references a Raw-Contact or a Person (a pre-Eclair style Uri), this Uri will
286 * always reference the full aggregate contact.
287 */
Daniel Lehmann4cd94412010-04-08 16:44:36 -0700288 public Uri getUri() {
289 return mUri;
290 }
Dmitri Plotnikov7f4f8d12010-11-10 10:22:19 -0800291
Daniel Lehmann685157e2011-08-29 21:07:01 -0700292 /**
293 * Returns the URI for which this {@link ContactLoader) was initially requested.
294 */
295 public Uri getRequestedUri() {
296 return mRequestedUri;
297 }
298
Dave Santoro6fa73842011-09-28 14:37:06 -0700299 /**
300 * Returns the contact ID.
301 */
Makoto Onuki98306102011-11-28 15:16:58 -0800302 @VisibleForTesting
303 /* package */ long getId() {
Daniel Lehmann4cd94412010-04-08 16:44:36 -0700304 return mId;
305 }
Dmitri Plotnikov7f4f8d12010-11-10 10:22:19 -0800306
Makoto Onuki9e7b5da2011-08-22 15:51:28 -0700307 /**
308 * @return true when an exception happened during loading, in which case
309 * {@link #getException} returns the actual exception object.
Makoto Onuki2621c5b2011-10-03 12:56:16 -0700310 * Note {@link #isNotFound()} and {@link #isError()} are mutually exclusive; If
311 * {@link #isError()} is {@code true}, {@link #isNotFound()} is always {@code false},
312 * and vice versa.
Makoto Onuki9e7b5da2011-08-22 15:51:28 -0700313 */
314 public boolean isError() {
Makoto Onuki2621c5b2011-10-03 12:56:16 -0700315 return mStatus == Status.ERROR;
Makoto Onuki9e7b5da2011-08-22 15:51:28 -0700316 }
317
318 public Exception getException() {
319 return mException;
320 }
321
Makoto Onuki2621c5b2011-10-03 12:56:16 -0700322 /**
323 * @return true when the specified contact is not found.
324 * Note {@link #isNotFound()} and {@link #isError()} are mutually exclusive; If
325 * {@link #isError()} is {@code true}, {@link #isNotFound()} is always {@code false},
326 * and vice versa.
327 */
328 public boolean isNotFound() {
329 return mStatus == Status.NOT_FOUND;
330 }
331
332 /**
333 * @return true if the specified contact is successfully loaded.
334 * i.e. neither {@link #isError()} nor {@link #isNotFound()}.
335 */
336 public boolean isLoaded() {
337 return mStatus == Status.LOADED;
338 }
339
Daniel Lehmann4cd94412010-04-08 16:44:36 -0700340 public long getNameRawContactId() {
341 return mNameRawContactId;
342 }
Dmitri Plotnikov7f4f8d12010-11-10 10:22:19 -0800343
Daniel Lehmann4cd94412010-04-08 16:44:36 -0700344 public int getDisplayNameSource() {
345 return mDisplayNameSource;
346 }
Dmitri Plotnikov7f4f8d12010-11-10 10:22:19 -0800347
Daniel Lehmannd3e0cdb2010-04-19 13:45:53 -0700348 public long getPhotoId() {
349 return mPhotoId;
350 }
Dmitri Plotnikov7f4f8d12010-11-10 10:22:19 -0800351
Dmitri Plotnikovf9eb73f2010-10-21 11:48:56 -0700352 public String getPhotoUri() {
353 return mPhotoUri;
354 }
Dmitri Plotnikov7f4f8d12010-11-10 10:22:19 -0800355
Daniel Lehmannd3e0cdb2010-04-19 13:45:53 -0700356 public String getDisplayName() {
357 return mDisplayName;
358 }
Dmitri Plotnikov7f4f8d12010-11-10 10:22:19 -0800359
Dave Santoroda5bf1c2011-05-03 10:30:34 -0700360 public String getAltDisplayName() {
361 return mAltDisplayName;
362 }
363
Daniel Lehmannd3e0cdb2010-04-19 13:45:53 -0700364 public String getPhoneticName() {
365 return mPhoneticName;
366 }
Dmitri Plotnikov7f4f8d12010-11-10 10:22:19 -0800367
Daniel Lehmannd3e0cdb2010-04-19 13:45:53 -0700368 public boolean getStarred() {
369 return mStarred;
370 }
Dmitri Plotnikov7f4f8d12010-11-10 10:22:19 -0800371
Daniel Lehmannd3e0cdb2010-04-19 13:45:53 -0700372 public Integer getPresence() {
373 return mPresence;
374 }
Dmitri Plotnikov7f4f8d12010-11-10 10:22:19 -0800375
Dave Santoro2b3f3c52011-07-26 17:35:42 -0700376 public ArrayList<AccountType> getInvitableAccountTypes() {
Makoto Onuki69b4a882011-07-22 10:05:10 -0700377 return mInvitableAccountTypes;
378 }
379
Daniel Lehmannd3e0cdb2010-04-19 13:45:53 -0700380 public ArrayList<Entity> getEntities() {
381 return mEntities;
382 }
Dmitri Plotnikov7f4f8d12010-11-10 10:22:19 -0800383
Dave Santoro39156002011-07-19 01:18:14 -0700384 public ArrayList<StreamItemEntry> getStreamItems() {
385 return mStreamItems;
386 }
387
Daniel Lehmann18958a22012-02-28 17:45:25 -0800388 public LongSparseArray<DataStatus> getStatuses() {
Daniel Lehmannd3e0cdb2010-04-19 13:45:53 -0700389 return mStatuses;
390 }
Dmitri Plotnikov02cd4912010-09-01 20:42:17 -0700391
392 public long getDirectoryId() {
393 return mDirectoryId;
394 }
395
396 public boolean isDirectoryEntry() {
Dmitri Plotnikov5f72c1f2010-09-01 21:21:04 -0700397 return mDirectoryId != -1 && mDirectoryId != Directory.DEFAULT
398 && mDirectoryId != Directory.LOCAL_INVISIBLE;
Dmitri Plotnikov02cd4912010-09-01 20:42:17 -0700399 }
400
401 public int getDirectoryExportSupport() {
402 return mDirectoryExportSupport;
403 }
404
405 public String getDirectoryDisplayName() {
406 return mDirectoryDisplayName;
407 }
408
409 public String getDirectoryType() {
410 return mDirectoryType;
411 }
412
Dmitri Plotnikovcaf0bc72010-09-03 15:16:21 -0700413 public String getDirectoryAccountType() {
414 return mDirectoryAccountType;
415 }
416
Dmitri Plotnikov02cd4912010-09-01 20:42:17 -0700417 public String getDirectoryAccountName() {
418 return mDirectoryAccountName;
419 }
420
Dmitri Plotnikov7f4f8d12010-11-10 10:22:19 -0800421 public byte[] getPhotoBinaryData() {
422 return mPhotoBinaryData;
423 }
424
Dmitri Plotnikovcaf0bc72010-09-03 15:16:21 -0700425 public ArrayList<ContentValues> getContentValues() {
426 if (mEntities.size() != 1) {
427 throw new IllegalStateException(
428 "Cannot extract content values from an aggregated contact");
429 }
430
431 Entity entity = mEntities.get(0);
432 ArrayList<ContentValues> result = new ArrayList<ContentValues>();
433 ArrayList<NamedContentValues> subValues = entity.getSubValues();
434 if (subValues != null) {
435 int size = subValues.size();
436 for (int i = 0; i < size; i++) {
437 NamedContentValues pair = subValues.get(i);
438 if (Data.CONTENT_URI.equals(pair.uri)) {
439 result.add(pair.values);
440 }
441 }
442 }
Dmitri Plotnikov40ec3a82010-11-10 11:25:33 -0800443
444 // If the photo was loaded using the URI, create an entry for the photo
445 // binary data.
446 if (mPhotoId == 0 && mPhotoBinaryData != null) {
447 ContentValues photo = new ContentValues();
448 photo.put(Data.MIMETYPE, Photo.CONTENT_ITEM_TYPE);
449 photo.put(Photo.PHOTO, mPhotoBinaryData);
450 result.add(photo);
451 }
452
Dmitri Plotnikovcaf0bc72010-09-03 15:16:21 -0700453 return result;
454 }
Dmitri Plotnikov2deaee12010-09-15 15:42:08 -0700455
Daniel Lehmann1ad4d1b2010-10-18 19:20:41 -0700456 private void addGroupMetaData(GroupMetaData group) {
Dmitri Plotnikov2deaee12010-09-15 15:42:08 -0700457 if (mGroups == null) {
Dmitri Plotnikove843f912010-09-16 15:21:48 -0700458 mGroups = new ArrayList<GroupMetaData>();
Dmitri Plotnikov2deaee12010-09-15 15:42:08 -0700459 }
460 mGroups.add(group);
461 }
462
Dmitri Plotnikove843f912010-09-16 15:21:48 -0700463 public List<GroupMetaData> getGroupMetaData() {
Dmitri Plotnikov2deaee12010-09-15 15:42:08 -0700464 return mGroups;
465 }
Isaac Katzenelson683b57e2011-07-20 17:06:11 -0700466
467 public boolean isSendToVoicemail() {
468 return mSendToVoicemail;
469 }
470
471 public String getCustomRingtone() {
472 return mCustomRingtone;
473 }
Isaac Katzenelsonead19c52011-07-29 18:24:53 -0700474
475 public boolean isUserProfile() {
476 return mIsUserProfile;
477 }
Dmitri Plotnikov2deaee12010-09-15 15:42:08 -0700478 }
479
Dave Santoro39156002011-07-19 01:18:14 -0700480 /**
481 * Projection used for the query that loads all data for the entire contact (except for
482 * social stream items).
483 */
Dmitri Plotnikov4d444242010-07-30 11:39:39 -0700484 private static class ContactQuery {
Daniel Lehmannd3e0cdb2010-04-19 13:45:53 -0700485 final static String[] COLUMNS = new String[] {
486 Contacts.NAME_RAW_CONTACT_ID,
487 Contacts.DISPLAY_NAME_SOURCE,
488 Contacts.LOOKUP_KEY,
489 Contacts.DISPLAY_NAME,
Dave Santoroda5bf1c2011-05-03 10:30:34 -0700490 Contacts.DISPLAY_NAME_ALTERNATIVE,
Daniel Lehmannd3e0cdb2010-04-19 13:45:53 -0700491 Contacts.PHONETIC_NAME,
492 Contacts.PHOTO_ID,
493 Contacts.STARRED,
494 Contacts.CONTACT_PRESENCE,
495 Contacts.CONTACT_STATUS,
496 Contacts.CONTACT_STATUS_TIMESTAMP,
497 Contacts.CONTACT_STATUS_RES_PACKAGE,
498 Contacts.CONTACT_STATUS_LABEL,
Dmitri Plotnikov4d444242010-07-30 11:39:39 -0700499 Contacts.Entity.CONTACT_ID,
500 Contacts.Entity.RAW_CONTACT_ID,
501
502 RawContacts.ACCOUNT_NAME,
503 RawContacts.ACCOUNT_TYPE,
Dave Santoro2b3f3c52011-07-26 17:35:42 -0700504 RawContacts.DATA_SET,
505 RawContacts.ACCOUNT_TYPE_AND_DATA_SET,
Dmitri Plotnikov4d444242010-07-30 11:39:39 -0700506 RawContacts.DIRTY,
507 RawContacts.VERSION,
508 RawContacts.SOURCE_ID,
509 RawContacts.SYNC1,
510 RawContacts.SYNC2,
511 RawContacts.SYNC3,
512 RawContacts.SYNC4,
513 RawContacts.DELETED,
Dmitri Plotnikov4d444242010-07-30 11:39:39 -0700514 RawContacts.NAME_VERIFIED,
515
516 Contacts.Entity.DATA_ID,
517 Data.DATA1,
518 Data.DATA2,
519 Data.DATA3,
520 Data.DATA4,
521 Data.DATA5,
522 Data.DATA6,
523 Data.DATA7,
524 Data.DATA8,
525 Data.DATA9,
526 Data.DATA10,
527 Data.DATA11,
528 Data.DATA12,
529 Data.DATA13,
530 Data.DATA14,
531 Data.DATA15,
532 Data.SYNC1,
533 Data.SYNC2,
534 Data.SYNC3,
535 Data.SYNC4,
536 Data.DATA_VERSION,
537 Data.IS_PRIMARY,
538 Data.IS_SUPER_PRIMARY,
539 Data.MIMETYPE,
540 Data.RES_PACKAGE,
541
542 GroupMembership.GROUP_SOURCE_ID,
543
544 Data.PRESENCE,
Daniel Lehmann8fd7bb62010-08-13 20:50:31 -0700545 Data.CHAT_CAPABILITY,
Dmitri Plotnikov4d444242010-07-30 11:39:39 -0700546 Data.STATUS,
547 Data.STATUS_RES_PACKAGE,
548 Data.STATUS_ICON,
549 Data.STATUS_LABEL,
Dmitri Plotnikovf9eb73f2010-10-21 11:48:56 -0700550 Data.STATUS_TIMESTAMP,
551
552 Contacts.PHOTO_URI,
Isaac Katzenelson683b57e2011-07-20 17:06:11 -0700553 Contacts.SEND_TO_VOICEMAIL,
554 Contacts.CUSTOM_RINGTONE,
Isaac Katzenelsonead19c52011-07-29 18:24:53 -0700555 Contacts.IS_USER_PROFILE,
Daniel Lehmannd3e0cdb2010-04-19 13:45:53 -0700556 };
Dmitri Plotnikov4d444242010-07-30 11:39:39 -0700557
558 public final static int NAME_RAW_CONTACT_ID = 0;
559 public final static int DISPLAY_NAME_SOURCE = 1;
560 public final static int LOOKUP_KEY = 2;
561 public final static int DISPLAY_NAME = 3;
Dave Santoroda5bf1c2011-05-03 10:30:34 -0700562 public final static int ALT_DISPLAY_NAME = 4;
563 public final static int PHONETIC_NAME = 5;
564 public final static int PHOTO_ID = 6;
565 public final static int STARRED = 7;
566 public final static int CONTACT_PRESENCE = 8;
567 public final static int CONTACT_STATUS = 9;
568 public final static int CONTACT_STATUS_TIMESTAMP = 10;
569 public final static int CONTACT_STATUS_RES_PACKAGE = 11;
570 public final static int CONTACT_STATUS_LABEL = 12;
571 public final static int CONTACT_ID = 13;
572 public final static int RAW_CONTACT_ID = 14;
Dmitri Plotnikov4d444242010-07-30 11:39:39 -0700573
Dave Santoroda5bf1c2011-05-03 10:30:34 -0700574 public final static int ACCOUNT_NAME = 15;
575 public final static int ACCOUNT_TYPE = 16;
Dave Santoro2b3f3c52011-07-26 17:35:42 -0700576 public final static int DATA_SET = 17;
577 public final static int ACCOUNT_TYPE_AND_DATA_SET = 18;
578 public final static int DIRTY = 19;
579 public final static int VERSION = 20;
580 public final static int SOURCE_ID = 21;
581 public final static int SYNC1 = 22;
582 public final static int SYNC2 = 23;
583 public final static int SYNC3 = 24;
584 public final static int SYNC4 = 25;
585 public final static int DELETED = 26;
586 public final static int NAME_VERIFIED = 27;
Dmitri Plotnikov4d444242010-07-30 11:39:39 -0700587
Dave Santoro2b3f3c52011-07-26 17:35:42 -0700588 public final static int DATA_ID = 28;
589 public final static int DATA1 = 29;
590 public final static int DATA2 = 30;
591 public final static int DATA3 = 31;
592 public final static int DATA4 = 32;
593 public final static int DATA5 = 33;
594 public final static int DATA6 = 34;
595 public final static int DATA7 = 35;
596 public final static int DATA8 = 36;
597 public final static int DATA9 = 37;
598 public final static int DATA10 = 38;
599 public final static int DATA11 = 39;
600 public final static int DATA12 = 40;
601 public final static int DATA13 = 41;
602 public final static int DATA14 = 42;
603 public final static int DATA15 = 43;
604 public final static int DATA_SYNC1 = 44;
605 public final static int DATA_SYNC2 = 45;
606 public final static int DATA_SYNC3 = 46;
607 public final static int DATA_SYNC4 = 47;
608 public final static int DATA_VERSION = 48;
609 public final static int IS_PRIMARY = 49;
610 public final static int IS_SUPERPRIMARY = 50;
611 public final static int MIMETYPE = 51;
612 public final static int RES_PACKAGE = 52;
Dmitri Plotnikov4d444242010-07-30 11:39:39 -0700613
Dave Santoro2b3f3c52011-07-26 17:35:42 -0700614 public final static int GROUP_SOURCE_ID = 53;
Dmitri Plotnikov4d444242010-07-30 11:39:39 -0700615
Dave Santoro2b3f3c52011-07-26 17:35:42 -0700616 public final static int PRESENCE = 54;
617 public final static int CHAT_CAPABILITY = 55;
618 public final static int STATUS = 56;
619 public final static int STATUS_RES_PACKAGE = 57;
620 public final static int STATUS_ICON = 58;
621 public final static int STATUS_LABEL = 59;
622 public final static int STATUS_TIMESTAMP = 60;
Dmitri Plotnikovf9eb73f2010-10-21 11:48:56 -0700623
Dave Santoro2b3f3c52011-07-26 17:35:42 -0700624 public final static int PHOTO_URI = 61;
625 public final static int SEND_TO_VOICEMAIL = 62;
626 public final static int CUSTOM_RINGTONE = 63;
Isaac Katzenelsonead19c52011-07-29 18:24:53 -0700627 public final static int IS_USER_PROFILE = 64;
Daniel Lehmannd3e0cdb2010-04-19 13:45:53 -0700628 }
Daniel Lehmann1316b132010-04-13 15:08:53 -0700629
Dave Santoro39156002011-07-19 01:18:14 -0700630 /**
631 * Projection used for the query that loads all data for the entire contact.
632 */
Dmitri Plotnikov02cd4912010-09-01 20:42:17 -0700633 private static class DirectoryQuery {
Dmitri Plotnikov02cd4912010-09-01 20:42:17 -0700634 final static String[] COLUMNS = new String[] {
635 Directory.DISPLAY_NAME,
636 Directory.PACKAGE_NAME,
637 Directory.TYPE_RESOURCE_ID,
Dmitri Plotnikovcaf0bc72010-09-03 15:16:21 -0700638 Directory.ACCOUNT_TYPE,
Dmitri Plotnikov02cd4912010-09-01 20:42:17 -0700639 Directory.ACCOUNT_NAME,
640 Directory.EXPORT_SUPPORT,
641 };
642
643 public final static int DISPLAY_NAME = 0;
644 public final static int PACKAGE_NAME = 1;
645 public final static int TYPE_RESOURCE_ID = 2;
Dmitri Plotnikovcaf0bc72010-09-03 15:16:21 -0700646 public final static int ACCOUNT_TYPE = 3;
647 public final static int ACCOUNT_NAME = 4;
648 public final static int EXPORT_SUPPORT = 5;
Dmitri Plotnikov02cd4912010-09-01 20:42:17 -0700649 }
650
Dmitri Plotnikov2deaee12010-09-15 15:42:08 -0700651 private static class GroupQuery {
652 final static String[] COLUMNS = new String[] {
653 Groups.ACCOUNT_NAME,
654 Groups.ACCOUNT_TYPE,
Dave Santoro2b3f3c52011-07-26 17:35:42 -0700655 Groups.DATA_SET,
656 Groups.ACCOUNT_TYPE_AND_DATA_SET,
Dmitri Plotnikov2deaee12010-09-15 15:42:08 -0700657 Groups._ID,
658 Groups.TITLE,
659 Groups.AUTO_ADD,
660 Groups.FAVORITES,
661 };
662
663 public final static int ACCOUNT_NAME = 0;
664 public final static int ACCOUNT_TYPE = 1;
Dave Santoro2b3f3c52011-07-26 17:35:42 -0700665 public final static int DATA_SET = 2;
666 public final static int ACCOUNT_TYPE_AND_DATA_SET = 3;
667 public final static int ID = 4;
668 public final static int TITLE = 5;
669 public final static int AUTO_ADD = 6;
670 public final static int FAVORITES = 7;
Dmitri Plotnikov2deaee12010-09-15 15:42:08 -0700671 }
672
Daniel Lehmann18f104f2010-05-07 15:41:11 -0700673 private final class LoadContactTask extends AsyncTask<Void, Void, Result> {
Daniel Lehmann1316b132010-04-13 15:08:53 -0700674
Daniel Lehmann4cd94412010-04-08 16:44:36 -0700675 @Override
676 protected Result doInBackground(Void... args) {
Daniel Lehmann18f104f2010-05-07 15:41:11 -0700677 try {
678 final ContentResolver resolver = getContext().getContentResolver();
Katherine Kuan6cd5b0a2011-09-16 11:46:01 -0700679 final Uri uriCurrentFormat = ContactLoaderUtils.ensureIsContactUri(
680 resolver, mLookupUri);
Dmitri Plotnikov02cd4912010-09-01 20:42:17 -0700681 Result result = loadContactEntity(resolver, uriCurrentFormat);
Makoto Onuki2621c5b2011-10-03 12:56:16 -0700682 if (!result.isNotFound()) {
Dmitri Plotnikov217245c2010-09-18 13:04:50 -0700683 if (result.isDirectoryEntry()) {
684 loadDirectoryMetaData(result);
685 } else if (mLoadGroupMetaData) {
686 loadGroupMetaData(result);
687 }
Dave Santoro39156002011-07-19 01:18:14 -0700688 if (mLoadStreamItems) {
689 loadStreamItems(result);
690 }
Dmitri Plotnikov7f4f8d12010-11-10 10:22:19 -0800691 loadPhotoBinaryData(result);
Makoto Onuki870a87e2011-08-12 13:40:31 -0700692
693 // Note ME profile should never have "Add connection"
694 if (mLoadInvitableAccountTypes && !result.isUserProfile()) {
Makoto Onuki69b4a882011-07-22 10:05:10 -0700695 loadInvitableAccountTypes(result);
696 }
Dmitri Plotnikov02cd4912010-09-01 20:42:17 -0700697 }
698 return result;
Daniel Lehmann18f104f2010-05-07 15:41:11 -0700699 } catch (Exception e) {
Dmitri Plotnikov4d444242010-07-30 11:39:39 -0700700 Log.e(TAG, "Error loading the contact: " + mLookupUri, e);
Makoto Onuki2621c5b2011-10-03 12:56:16 -0700701 return Result.forError(mRequestedUri, e);
Daniel Lehmann4cd94412010-04-08 16:44:36 -0700702 }
Daniel Lehmann4cd94412010-04-08 16:44:36 -0700703 }
704
Dmitri Plotnikov4d444242010-07-30 11:39:39 -0700705 private Result loadContactEntity(ContentResolver resolver, Uri contactUri) {
706 Uri entityUri = Uri.withAppendedPath(contactUri, Contacts.Entity.CONTENT_DIRECTORY);
707 Cursor cursor = resolver.query(entityUri, ContactQuery.COLUMNS, null, null,
708 Contacts.Entity.RAW_CONTACT_ID);
Daniel Lehmann4cd94412010-04-08 16:44:36 -0700709 if (cursor == null) {
Dmitri Plotnikov4d444242010-07-30 11:39:39 -0700710 Log.e(TAG, "No cursor returned in loadContactEntity");
Makoto Onuki2621c5b2011-10-03 12:56:16 -0700711 return Result.forNotFound(mRequestedUri);
Daniel Lehmann4cd94412010-04-08 16:44:36 -0700712 }
Dmitri Plotnikov4d444242010-07-30 11:39:39 -0700713
Daniel Lehmann4cd94412010-04-08 16:44:36 -0700714 try {
715 if (!cursor.moveToFirst()) {
Dmitri Plotnikov4d444242010-07-30 11:39:39 -0700716 cursor.close();
Makoto Onuki2621c5b2011-10-03 12:56:16 -0700717 return Result.forNotFound(mRequestedUri);
Daniel Lehmann4cd94412010-04-08 16:44:36 -0700718 }
719
Dmitri Plotnikov4d444242010-07-30 11:39:39 -0700720 long currentRawContactId = -1;
721 Entity entity = null;
722 Result result = loadContactHeaderData(cursor, contactUri);
Daniel Lehmann4cd94412010-04-08 16:44:36 -0700723 ArrayList<Entity> entities = result.getEntities();
Daniel Lehmann18958a22012-02-28 17:45:25 -0800724 LongSparseArray<DataStatus> statuses = result.getStatuses();
Dmitri Plotnikov4d444242010-07-30 11:39:39 -0700725 for (; !cursor.isAfterLast(); cursor.moveToNext()) {
726 long rawContactId = cursor.getLong(ContactQuery.RAW_CONTACT_ID);
727 if (rawContactId != currentRawContactId) {
728 currentRawContactId = rawContactId;
729 entity = new android.content.Entity(loadRawContact(cursor));
Daniel Lehmann4cd94412010-04-08 16:44:36 -0700730 entities.add(entity);
731 }
Dmitri Plotnikov4d444242010-07-30 11:39:39 -0700732 if (!cursor.isNull(ContactQuery.DATA_ID)) {
733 ContentValues data = loadData(cursor);
734 entity.addSubValue(ContactsContract.Data.CONTENT_URI, data);
735
736 if (!cursor.isNull(ContactQuery.PRESENCE)
737 || !cursor.isNull(ContactQuery.STATUS)) {
738 final DataStatus status = new DataStatus(cursor);
739 final long dataId = cursor.getLong(ContactQuery.DATA_ID);
740 statuses.put(dataId, status);
741 }
742 }
Daniel Lehmann4cd94412010-04-08 16:44:36 -0700743 }
Dmitri Plotnikov4d444242010-07-30 11:39:39 -0700744
745 return result;
Daniel Lehmann4cd94412010-04-08 16:44:36 -0700746 } finally {
747 cursor.close();
748 }
749 }
750
Dmitri Plotnikov4d444242010-07-30 11:39:39 -0700751 /**
Dmitri Plotnikov7f4f8d12010-11-10 10:22:19 -0800752 * Looks for the photo data item in entities. If found, creates a new Bitmap instance. If
753 * not found, returns null
754 */
755 private void loadPhotoBinaryData(Result contactData) {
Dave Santoro0a2a5db2011-06-29 00:37:06 -0700756
757 // If we have a photo URI, try loading that first.
758 String photoUri = contactData.getPhotoUri();
759 if (photoUri != null) {
760 try {
761 AssetFileDescriptor fd = getContext().getContentResolver()
762 .openAssetFileDescriptor(Uri.parse(photoUri), "r");
763 byte[] buffer = new byte[16 * 1024];
764 FileInputStream fis = fd.createInputStream();
765 ByteArrayOutputStream baos = new ByteArrayOutputStream();
766 try {
767 int size;
768 while ((size = fis.read(buffer)) != -1) {
769 baos.write(buffer, 0, size);
770 }
771 contactData.setPhotoBinaryData(baos.toByteArray());
772 } finally {
773 fis.close();
774 fd.close();
775 }
776 return;
777 } catch (IOException ioe) {
778 // Just fall back to the case below.
779 }
780 }
781
782 // If we couldn't load from a file, fall back to the data blob.
Dmitri Plotnikov7f4f8d12010-11-10 10:22:19 -0800783 final long photoId = contactData.getPhotoId();
784 if (photoId <= 0) {
785 // No photo ID
786 return;
787 }
788
789 for (Entity entity : contactData.getEntities()) {
790 for (NamedContentValues subValue : entity.getSubValues()) {
791 final ContentValues entryValues = subValue.values;
792 final long dataId = entryValues.getAsLong(Data._ID);
793 if (dataId == photoId) {
794 final String mimeType = entryValues.getAsString(Data.MIMETYPE);
795 // Correct Data Id but incorrect MimeType? Don't load
796 if (!Photo.CONTENT_ITEM_TYPE.equals(mimeType)) {
797 return;
798 }
799 contactData.setPhotoBinaryData(entryValues.getAsByteArray(Photo.PHOTO));
800 break;
801 }
802 }
803 }
804 }
805
Makoto Onuki3e6991e2011-07-24 14:51:20 -0700806 /**
807 * Sets the "invitable" account types to {@link Result#mInvitableAccountTypes}.
Makoto Onuki3e6991e2011-07-24 14:51:20 -0700808 */
Makoto Onuki69b4a882011-07-22 10:05:10 -0700809 private void loadInvitableAccountTypes(Result contactData) {
Katherine Kuan08bcf712011-10-09 13:43:53 -0700810 Map<AccountTypeWithDataSet, AccountType> invitables =
811 AccountTypeManager.getInstance(getContext()).getUsableInvitableAccountTypes();
812 if (invitables.isEmpty()) {
Makoto Onuki69b4a882011-07-22 10:05:10 -0700813 return;
814 }
815
Daniel Lehmann18958a22012-02-28 17:45:25 -0800816 Map<AccountTypeWithDataSet, AccountType> result = Maps.newHashMap(invitables);
Makoto Onuki69b4a882011-07-22 10:05:10 -0700817
Daniel Lehmann3ef27fb2011-08-09 14:31:29 -0700818 // Remove the ones that already have a raw contact in the current contact
Makoto Onuki69b4a882011-07-22 10:05:10 -0700819 for (Entity entity : contactData.getEntities()) {
Makoto Onuki6ad227f2011-08-15 13:46:59 -0700820 final ContentValues values = entity.getEntityValues();
821 final AccountTypeWithDataSet type = AccountTypeWithDataSet.get(
822 values.getAsString(RawContacts.ACCOUNT_TYPE),
823 values.getAsString(RawContacts.DATA_SET));
824 result.remove(type);
Makoto Onuki69b4a882011-07-22 10:05:10 -0700825 }
826
827 // Set to mInvitableAccountTypes
Dave Santoro2b3f3c52011-07-26 17:35:42 -0700828 contactData.mInvitableAccountTypes.addAll(result.values());
Makoto Onuki69b4a882011-07-22 10:05:10 -0700829 }
830
Dmitri Plotnikov7f4f8d12010-11-10 10:22:19 -0800831 /**
Dmitri Plotnikov4d444242010-07-30 11:39:39 -0700832 * Extracts Contact level columns from the cursor.
833 */
834 private Result loadContactHeaderData(final Cursor cursor, Uri contactUri) {
Dmitri Plotnikov02cd4912010-09-01 20:42:17 -0700835 final String directoryParameter =
836 contactUri.getQueryParameter(ContactsContract.DIRECTORY_PARAM_KEY);
837 final long directoryId = directoryParameter == null
838 ? Directory.DEFAULT
839 : Long.parseLong(directoryParameter);
Dmitri Plotnikov4d444242010-07-30 11:39:39 -0700840 final long contactId = cursor.getLong(ContactQuery.CONTACT_ID);
841 final String lookupKey = cursor.getString(ContactQuery.LOOKUP_KEY);
842 final long nameRawContactId = cursor.getLong(ContactQuery.NAME_RAW_CONTACT_ID);
843 final int displayNameSource = cursor.getInt(ContactQuery.DISPLAY_NAME_SOURCE);
844 final String displayName = cursor.getString(ContactQuery.DISPLAY_NAME);
Dave Santoroda5bf1c2011-05-03 10:30:34 -0700845 final String altDisplayName = cursor.getString(ContactQuery.ALT_DISPLAY_NAME);
Dmitri Plotnikov4d444242010-07-30 11:39:39 -0700846 final String phoneticName = cursor.getString(ContactQuery.PHONETIC_NAME);
847 final long photoId = cursor.getLong(ContactQuery.PHOTO_ID);
Dmitri Plotnikovf9eb73f2010-10-21 11:48:56 -0700848 final String photoUri = cursor.getString(ContactQuery.PHOTO_URI);
Dmitri Plotnikov4d444242010-07-30 11:39:39 -0700849 final boolean starred = cursor.getInt(ContactQuery.STARRED) != 0;
850 final Integer presence = cursor.isNull(ContactQuery.CONTACT_PRESENCE)
851 ? null
852 : cursor.getInt(ContactQuery.CONTACT_PRESENCE);
Isaac Katzenelson683b57e2011-07-20 17:06:11 -0700853 final boolean sendToVoicemail = cursor.getInt(ContactQuery.SEND_TO_VOICEMAIL) == 1;
854 final String customRingtone = cursor.getString(ContactQuery.CUSTOM_RINGTONE);
Isaac Katzenelsonead19c52011-07-29 18:24:53 -0700855 final boolean isUserProfile = cursor.getInt(ContactQuery.IS_USER_PROFILE) == 1;
Dmitri Plotnikov4d444242010-07-30 11:39:39 -0700856
Dmitri Plotnikov1536ea12010-10-29 11:51:05 -0700857 Uri lookupUri;
858 if (directoryId == Directory.DEFAULT || directoryId == Directory.LOCAL_INVISIBLE) {
859 lookupUri = ContentUris.withAppendedId(
Dmitri Plotnikov4d444242010-07-30 11:39:39 -0700860 Uri.withAppendedPath(Contacts.CONTENT_LOOKUP_URI, lookupKey), contactId);
Dmitri Plotnikov1536ea12010-10-29 11:51:05 -0700861 } else {
862 lookupUri = contactUri;
863 }
864
Daniel Lehmann685157e2011-08-29 21:07:01 -0700865 return new Result(mRequestedUri, contactUri, lookupUri, directoryId, lookupKey,
866 contactId, nameRawContactId, displayNameSource, photoId, photoUri, displayName,
Isaac Katzenelson683b57e2011-07-20 17:06:11 -0700867 altDisplayName, phoneticName, starred, presence, sendToVoicemail,
Isaac Katzenelsonead19c52011-07-29 18:24:53 -0700868 customRingtone, isUserProfile);
Dmitri Plotnikov4d444242010-07-30 11:39:39 -0700869 }
870
871 /**
872 * Extracts RawContact level columns from the cursor.
873 */
874 private ContentValues loadRawContact(Cursor cursor) {
875 ContentValues cv = new ContentValues();
876
877 cv.put(RawContacts._ID, cursor.getLong(ContactQuery.RAW_CONTACT_ID));
878
879 cursorColumnToContentValues(cursor, cv, ContactQuery.ACCOUNT_NAME);
880 cursorColumnToContentValues(cursor, cv, ContactQuery.ACCOUNT_TYPE);
Dave Santoro2b3f3c52011-07-26 17:35:42 -0700881 cursorColumnToContentValues(cursor, cv, ContactQuery.DATA_SET);
882 cursorColumnToContentValues(cursor, cv, ContactQuery.ACCOUNT_TYPE_AND_DATA_SET);
Dmitri Plotnikov4d444242010-07-30 11:39:39 -0700883 cursorColumnToContentValues(cursor, cv, ContactQuery.DIRTY);
884 cursorColumnToContentValues(cursor, cv, ContactQuery.VERSION);
885 cursorColumnToContentValues(cursor, cv, ContactQuery.SOURCE_ID);
886 cursorColumnToContentValues(cursor, cv, ContactQuery.SYNC1);
887 cursorColumnToContentValues(cursor, cv, ContactQuery.SYNC2);
888 cursorColumnToContentValues(cursor, cv, ContactQuery.SYNC3);
889 cursorColumnToContentValues(cursor, cv, ContactQuery.SYNC4);
890 cursorColumnToContentValues(cursor, cv, ContactQuery.DELETED);
891 cursorColumnToContentValues(cursor, cv, ContactQuery.CONTACT_ID);
892 cursorColumnToContentValues(cursor, cv, ContactQuery.STARRED);
Dmitri Plotnikov4d444242010-07-30 11:39:39 -0700893 cursorColumnToContentValues(cursor, cv, ContactQuery.NAME_VERIFIED);
894
895 return cv;
896 }
897
898 /**
899 * Extracts Data level columns from the cursor.
900 */
901 private ContentValues loadData(Cursor cursor) {
902 ContentValues cv = new ContentValues();
903
904 cv.put(Data._ID, cursor.getLong(ContactQuery.DATA_ID));
905
906 cursorColumnToContentValues(cursor, cv, ContactQuery.DATA1);
907 cursorColumnToContentValues(cursor, cv, ContactQuery.DATA2);
908 cursorColumnToContentValues(cursor, cv, ContactQuery.DATA3);
909 cursorColumnToContentValues(cursor, cv, ContactQuery.DATA4);
910 cursorColumnToContentValues(cursor, cv, ContactQuery.DATA5);
911 cursorColumnToContentValues(cursor, cv, ContactQuery.DATA6);
912 cursorColumnToContentValues(cursor, cv, ContactQuery.DATA7);
913 cursorColumnToContentValues(cursor, cv, ContactQuery.DATA8);
914 cursorColumnToContentValues(cursor, cv, ContactQuery.DATA9);
915 cursorColumnToContentValues(cursor, cv, ContactQuery.DATA10);
916 cursorColumnToContentValues(cursor, cv, ContactQuery.DATA11);
917 cursorColumnToContentValues(cursor, cv, ContactQuery.DATA12);
918 cursorColumnToContentValues(cursor, cv, ContactQuery.DATA13);
919 cursorColumnToContentValues(cursor, cv, ContactQuery.DATA14);
920 cursorColumnToContentValues(cursor, cv, ContactQuery.DATA15);
921 cursorColumnToContentValues(cursor, cv, ContactQuery.DATA_SYNC1);
922 cursorColumnToContentValues(cursor, cv, ContactQuery.DATA_SYNC2);
923 cursorColumnToContentValues(cursor, cv, ContactQuery.DATA_SYNC3);
924 cursorColumnToContentValues(cursor, cv, ContactQuery.DATA_SYNC4);
925 cursorColumnToContentValues(cursor, cv, ContactQuery.DATA_VERSION);
926 cursorColumnToContentValues(cursor, cv, ContactQuery.IS_PRIMARY);
927 cursorColumnToContentValues(cursor, cv, ContactQuery.IS_SUPERPRIMARY);
928 cursorColumnToContentValues(cursor, cv, ContactQuery.MIMETYPE);
929 cursorColumnToContentValues(cursor, cv, ContactQuery.RES_PACKAGE);
930 cursorColumnToContentValues(cursor, cv, ContactQuery.GROUP_SOURCE_ID);
Daniel Lehmann8fd7bb62010-08-13 20:50:31 -0700931 cursorColumnToContentValues(cursor, cv, ContactQuery.CHAT_CAPABILITY);
Dmitri Plotnikov4d444242010-07-30 11:39:39 -0700932
933 return cv;
934 }
935
936 private void cursorColumnToContentValues(
937 Cursor cursor, ContentValues values, int index) {
938 switch (cursor.getType(index)) {
939 case Cursor.FIELD_TYPE_NULL:
940 // don't put anything in the content values
941 break;
942 case Cursor.FIELD_TYPE_INTEGER:
943 values.put(ContactQuery.COLUMNS[index], cursor.getLong(index));
944 break;
945 case Cursor.FIELD_TYPE_STRING:
946 values.put(ContactQuery.COLUMNS[index], cursor.getString(index));
947 break;
948 case Cursor.FIELD_TYPE_BLOB:
949 values.put(ContactQuery.COLUMNS[index], cursor.getBlob(index));
950 break;
951 default:
952 throw new IllegalStateException("Invalid or unhandled data type");
953 }
954 }
955
Dmitri Plotnikov02cd4912010-09-01 20:42:17 -0700956 private void loadDirectoryMetaData(Result result) {
957 long directoryId = result.getDirectoryId();
958
959 Cursor cursor = getContext().getContentResolver().query(
960 ContentUris.withAppendedId(Directory.CONTENT_URI, directoryId),
961 DirectoryQuery.COLUMNS, null, null, null);
962 if (cursor == null) {
963 return;
964 }
965 try {
966 if (cursor.moveToFirst()) {
967 final String displayName = cursor.getString(DirectoryQuery.DISPLAY_NAME);
968 final String packageName = cursor.getString(DirectoryQuery.PACKAGE_NAME);
969 final int typeResourceId = cursor.getInt(DirectoryQuery.TYPE_RESOURCE_ID);
Dmitri Plotnikovcaf0bc72010-09-03 15:16:21 -0700970 final String accountType = cursor.getString(DirectoryQuery.ACCOUNT_TYPE);
Dmitri Plotnikov02cd4912010-09-01 20:42:17 -0700971 final String accountName = cursor.getString(DirectoryQuery.ACCOUNT_NAME);
972 final int exportSupport = cursor.getInt(DirectoryQuery.EXPORT_SUPPORT);
973 String directoryType = null;
974 if (!TextUtils.isEmpty(packageName)) {
975 PackageManager pm = getContext().getPackageManager();
976 try {
977 Resources resources = pm.getResourcesForApplication(packageName);
978 directoryType = resources.getString(typeResourceId);
979 } catch (NameNotFoundException e) {
980 Log.w(TAG, "Contact directory resource not found: "
981 + packageName + "." + typeResourceId);
982 }
983 }
984
985 result.setDirectoryMetaData(
Dmitri Plotnikovcaf0bc72010-09-03 15:16:21 -0700986 displayName, directoryType, accountType, accountName, exportSupport);
Dmitri Plotnikov02cd4912010-09-01 20:42:17 -0700987 }
988 } finally {
989 cursor.close();
990 }
991 }
992
Dmitri Plotnikov2deaee12010-09-15 15:42:08 -0700993 /**
994 * Loads groups meta-data for all groups associated with all constituent raw contacts'
995 * accounts.
996 */
997 private void loadGroupMetaData(Result result) {
998 StringBuilder selection = new StringBuilder();
999 ArrayList<String> selectionArgs = new ArrayList<String>();
1000 for (Entity entity : result.mEntities) {
1001 ContentValues values = entity.getEntityValues();
1002 String accountName = values.getAsString(RawContacts.ACCOUNT_NAME);
1003 String accountType = values.getAsString(RawContacts.ACCOUNT_TYPE);
Dave Santoro2b3f3c52011-07-26 17:35:42 -07001004 String dataSet = values.getAsString(RawContacts.DATA_SET);
Dmitri Plotnikov2deaee12010-09-15 15:42:08 -07001005 if (accountName != null && accountType != null) {
1006 if (selection.length() != 0) {
1007 selection.append(" OR ");
1008 }
1009 selection.append(
Dave Santoro2b3f3c52011-07-26 17:35:42 -07001010 "(" + Groups.ACCOUNT_NAME + "=? AND " + Groups.ACCOUNT_TYPE + "=?");
Dmitri Plotnikov2deaee12010-09-15 15:42:08 -07001011 selectionArgs.add(accountName);
1012 selectionArgs.add(accountType);
Dave Santoro2b3f3c52011-07-26 17:35:42 -07001013
1014 if (dataSet != null) {
1015 selection.append(" AND " + Groups.DATA_SET + "=?");
1016 selectionArgs.add(dataSet);
1017 } else {
1018 selection.append(" AND " + Groups.DATA_SET + " IS NULL");
1019 }
1020 selection.append(")");
Dmitri Plotnikov2deaee12010-09-15 15:42:08 -07001021 }
1022 }
1023 Cursor cursor = getContext().getContentResolver().query(Groups.CONTENT_URI,
1024 GroupQuery.COLUMNS, selection.toString(), selectionArgs.toArray(new String[0]),
1025 null);
1026 try {
1027 while (cursor.moveToNext()) {
1028 final String accountName = cursor.getString(GroupQuery.ACCOUNT_NAME);
1029 final String accountType = cursor.getString(GroupQuery.ACCOUNT_TYPE);
Dave Santoro2b3f3c52011-07-26 17:35:42 -07001030 final String dataSet = cursor.getString(GroupQuery.DATA_SET);
Dmitri Plotnikov2deaee12010-09-15 15:42:08 -07001031 final long groupId = cursor.getLong(GroupQuery.ID);
1032 final String title = cursor.getString(GroupQuery.TITLE);
1033 final boolean defaultGroup = cursor.isNull(GroupQuery.AUTO_ADD)
1034 ? false
1035 : cursor.getInt(GroupQuery.AUTO_ADD) != 0;
1036 final boolean favorites = cursor.isNull(GroupQuery.FAVORITES)
1037 ? false
1038 : cursor.getInt(GroupQuery.FAVORITES) != 0;
1039
Dmitri Plotnikove843f912010-09-16 15:21:48 -07001040 result.addGroupMetaData(new GroupMetaData(
Dave Santoro2b3f3c52011-07-26 17:35:42 -07001041 accountName, accountType, dataSet, groupId, title, defaultGroup,
1042 favorites));
Dmitri Plotnikov2deaee12010-09-15 15:42:08 -07001043 }
1044 } finally {
1045 cursor.close();
1046 }
1047 }
1048
Dave Santoro39156002011-07-19 01:18:14 -07001049 /**
1050 * Loads all stream items and stream item photos belonging to this contact.
1051 */
1052 private void loadStreamItems(Result result) {
1053 Cursor cursor = getContext().getContentResolver().query(
1054 Contacts.CONTENT_LOOKUP_URI.buildUpon()
1055 .appendPath(result.getLookupKey())
1056 .appendPath(Contacts.StreamItems.CONTENT_DIRECTORY).build(),
1057 null, null, null, null);
Daniel Lehmann18958a22012-02-28 17:45:25 -08001058 LongSparseArray<StreamItemEntry> streamItemsById =
1059 new LongSparseArray<StreamItemEntry>();
Dave Santoro39156002011-07-19 01:18:14 -07001060 ArrayList<StreamItemEntry> streamItems = new ArrayList<StreamItemEntry>();
1061 try {
1062 while (cursor.moveToNext()) {
1063 StreamItemEntry streamItem = new StreamItemEntry(cursor);
1064 streamItemsById.put(streamItem.getId(), streamItem);
1065 streamItems.add(streamItem);
1066 }
1067 } finally {
1068 cursor.close();
1069 }
1070
Makoto Onukida9cdc12012-02-27 16:11:50 -08001071 // Pre-decode all HTMLs
1072 final long start = System.currentTimeMillis();
1073 for (StreamItemEntry streamItem : streamItems) {
1074 streamItem.decodeHtml(getContext());
1075 }
1076 final long end = System.currentTimeMillis();
1077 if (DEBUG) {
1078 Log.d(TAG, "Decoded HTML for " + streamItems.size() + " items, took "
1079 + (end - start) + " ms");
1080 }
1081
Dave Santoro39156002011-07-19 01:18:14 -07001082 // Now retrieve any photo records associated with the stream items.
Dave Santoro39156002011-07-19 01:18:14 -07001083 if (!streamItems.isEmpty()) {
Dave Santoroa4400d52011-09-02 16:14:53 -07001084 if (result.isUserProfile()) {
1085 // If the stream items we're loading are for the profile, we can't bulk-load the
1086 // stream items with a custom selection.
1087 for (StreamItemEntry entry : streamItems) {
1088 Cursor siCursor = getContext().getContentResolver().query(
1089 Uri.withAppendedPath(
1090 ContentUris.withAppendedId(
1091 StreamItems.CONTENT_URI, entry.getId()),
1092 StreamItems.StreamItemPhotos.CONTENT_DIRECTORY),
1093 null, null, null, null);
1094 try {
1095 while (siCursor.moveToNext()) {
1096 entry.addPhoto(new StreamItemPhotoEntry(siCursor));
1097 }
1098 } finally {
1099 siCursor.close();
1100 }
Dave Santoro39156002011-07-19 01:18:14 -07001101 }
Dave Santoroa4400d52011-09-02 16:14:53 -07001102 } else {
1103 String[] streamItemIdArr = new String[streamItems.size()];
1104 StringBuilder streamItemPhotoSelection = new StringBuilder();
1105 streamItemPhotoSelection.append(StreamItemPhotos.STREAM_ITEM_ID + " IN (");
1106 for (int i = 0; i < streamItems.size(); i++) {
1107 if (i > 0) {
1108 streamItemPhotoSelection.append(",");
1109 }
1110 streamItemPhotoSelection.append("?");
1111 streamItemIdArr[i] = String.valueOf(streamItems.get(i).getId());
Dave Santoro39156002011-07-19 01:18:14 -07001112 }
Dave Santoroa4400d52011-09-02 16:14:53 -07001113 streamItemPhotoSelection.append(")");
1114 Cursor sipCursor = getContext().getContentResolver().query(
1115 StreamItems.CONTENT_PHOTO_URI,
1116 null, streamItemPhotoSelection.toString(), streamItemIdArr,
1117 StreamItemPhotos.STREAM_ITEM_ID);
1118 try {
1119 while (sipCursor.moveToNext()) {
1120 long streamItemId = sipCursor.getLong(
1121 sipCursor.getColumnIndex(StreamItemPhotos.STREAM_ITEM_ID));
1122 StreamItemEntry streamItem = streamItemsById.get(streamItemId);
1123 streamItem.addPhoto(new StreamItemPhotoEntry(sipCursor));
1124 }
1125 } finally {
1126 sipCursor.close();
1127 }
Dave Santoro39156002011-07-19 01:18:14 -07001128 }
1129 }
1130
1131 // Set the sorted stream items on the result.
1132 Collections.sort(streamItems);
1133 result.mStreamItems.addAll(streamItems);
1134 }
1135
Daniel Lehmann4cd94412010-04-08 16:44:36 -07001136 @Override
1137 protected void onPostExecute(Result result) {
Dmitri Plotnikovc3f2a522010-11-17 18:36:17 -08001138 unregisterObserver();
1139
Daniel Lehmann1316b132010-04-13 15:08:53 -07001140 // The creator isn't interested in any further updates
Dmitri Plotnikovc3f2a522010-11-17 18:36:17 -08001141 if (mDestroyed || result == null) {
Daniel Lehmann4cd94412010-04-08 16:44:36 -07001142 return;
1143 }
1144
1145 mContact = result;
Daniel Lehmann18f104f2010-05-07 15:41:11 -07001146
Makoto Onuki2621c5b2011-10-03 12:56:16 -07001147 if (result.isLoaded()) {
Dmitri Plotnikovc3f2a522010-11-17 18:36:17 -08001148 mLookupUri = result.getLookupUri();
1149
1150 if (!result.isDirectoryEntry()) {
1151 Log.i(TAG, "Registering content observer for " + mLookupUri);
1152 if (mObserver == null) {
1153 mObserver = new ForceLoadContentObserver();
1154 }
1155 getContext().getContentResolver().registerContentObserver(
1156 mLookupUri, true, mObserver);
Daniel Lehmann18f104f2010-05-07 15:41:11 -07001157 }
Dmitri Plotnikov7f4f8d12010-11-10 10:22:19 -08001158
Daniel Lehmann3ef27fb2011-08-09 14:31:29 -07001159 // inform the source of the data that this contact is being looked at
1160 postViewNotificationToSyncAdapter();
Daniel Lehmann4cd94412010-04-08 16:44:36 -07001161 }
Dmitri Plotnikovc3f2a522010-11-17 18:36:17 -08001162
1163 deliverResult(mContact);
Daniel Lehmann4cd94412010-04-08 16:44:36 -07001164 }
1165 }
1166
Daniel Lehmann3ef27fb2011-08-09 14:31:29 -07001167 /**
1168 * Posts a message to the contributing sync adapters that have opted-in, notifying them
1169 * that the contact has just been loaded
1170 */
1171 private void postViewNotificationToSyncAdapter() {
1172 Context context = getContext();
1173 for (Entity entity : mContact.getEntities()) {
1174 final ContentValues entityValues = entity.getEntityValues();
Makoto Onukiaba2b832011-08-12 15:44:53 -07001175 final long rawContactId = entityValues.getAsLong(RawContacts.Entity._ID);
1176 if (mNotifiedRawContactIds.contains(rawContactId)) {
1177 continue; // Already notified for this raw contact.
1178 }
1179 mNotifiedRawContactIds.add(rawContactId);
Daniel Lehmann3ef27fb2011-08-09 14:31:29 -07001180 final String type = entityValues.getAsString(RawContacts.ACCOUNT_TYPE);
1181 final String dataSet = entityValues.getAsString(RawContacts.DATA_SET);
Flavio Lerda59a887e2011-08-14 18:13:17 +01001182 final AccountType accountType = AccountTypeManager.getInstance(context).getAccountType(
Daniel Lehmann3ef27fb2011-08-09 14:31:29 -07001183 type, dataSet);
1184 final String serviceName = accountType.getViewContactNotifyServiceClassName();
1185 final String resPackageName = accountType.resPackageName;
1186 if (!TextUtils.isEmpty(serviceName) && !TextUtils.isEmpty(resPackageName)) {
Daniel Lehmann3ef27fb2011-08-09 14:31:29 -07001187 final Uri uri = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId);
1188 final Intent intent = new Intent();
1189 intent.setClassName(resPackageName, serviceName);
1190 intent.setAction(Intent.ACTION_VIEW);
1191 intent.setDataAndType(uri, RawContacts.CONTENT_ITEM_TYPE);
1192 try {
1193 context.startService(intent);
1194 } catch (Exception e) {
1195 Log.e(TAG, "Error sending message to source-app", e);
1196 }
1197 }
1198 }
1199 }
1200
Daniel Lehmann3a120772010-06-21 16:21:35 -07001201 private void unregisterObserver() {
1202 if (mObserver != null) {
1203 getContext().getContentResolver().unregisterContentObserver(mObserver);
1204 mObserver = null;
1205 }
1206 }
1207
Daniel Lehmanncdef2b62010-06-06 18:25:49 -07001208 public ContactLoader(Context context, Uri lookupUri) {
Makoto Onuki69b4a882011-07-22 10:05:10 -07001209 this(context, lookupUri, false, false, false);
Dmitri Plotnikove843f912010-09-16 15:21:48 -07001210 }
1211
Dave Santoro39156002011-07-19 01:18:14 -07001212 public ContactLoader(Context context, Uri lookupUri, boolean loadGroupMetaData,
Makoto Onuki69b4a882011-07-22 10:05:10 -07001213 boolean loadStreamItems, boolean loadInvitableAccountTypes) {
Daniel Lehmann74a2dc52010-04-15 16:52:33 -07001214 super(context);
Daniel Lehmann4cd94412010-04-08 16:44:36 -07001215 mLookupUri = lookupUri;
Daniel Lehmann685157e2011-08-29 21:07:01 -07001216 mRequestedUri = lookupUri;
Dmitri Plotnikove843f912010-09-16 15:21:48 -07001217 mLoadGroupMetaData = loadGroupMetaData;
Dave Santoro39156002011-07-19 01:18:14 -07001218 mLoadStreamItems = loadStreamItems;
Makoto Onuki69b4a882011-07-22 10:05:10 -07001219 mLoadInvitableAccountTypes = loadInvitableAccountTypes;
Daniel Lehmann4cd94412010-04-08 16:44:36 -07001220 }
1221
Daniel Lehmann2a45e352012-02-13 15:03:58 -08001222 /**
1223 * Sets whether to load stream items. Will trigger a reload if the value has changed.
1224 * At the moment, this is only used for debugging purposes
1225 */
1226 public void setLoadStreamItems(boolean value) {
1227 if (mLoadStreamItems != value) {
1228 mLoadStreamItems = value;
1229 onContentChanged();
1230 }
1231 }
1232
1233 public boolean getLoadStreamItems() {
1234 return mLoadStreamItems;
1235 }
1236
Dmitri Plotnikov5a30d9a2010-11-23 14:59:50 -08001237 public Uri getLookupUri() {
1238 return mLookupUri;
1239 }
1240
Daniel Lehmann4cd94412010-04-08 16:44:36 -07001241 @Override
Dianne Hackbornc04fc272010-12-20 23:13:10 -08001242 protected void onStartLoading() {
Daniel Lehmann4cd94412010-04-08 16:44:36 -07001243 if (mContact != null) {
Daniel Lehmanncbcc4492010-04-12 18:03:54 -07001244 deliverResult(mContact);
Dmitri Plotnikov97e90c62011-01-03 11:58:13 -08001245 }
1246
1247 if (takeContentChanged() || mContact == null) {
Daniel Lehmann4cd94412010-04-08 16:44:36 -07001248 forceLoad();
1249 }
1250 }
1251
1252 @Override
Dianne Hackbornc04fc272010-12-20 23:13:10 -08001253 protected void onForceLoad() {
Daniel Lehmann18f104f2010-05-07 15:41:11 -07001254 final LoadContactTask task = new LoadContactTask();
Makoto Onuki73c341f2011-08-29 09:31:44 -07001255 task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[])null);
Daniel Lehmann4cd94412010-04-08 16:44:36 -07001256 }
1257
1258 @Override
Dianne Hackbornc04fc272010-12-20 23:13:10 -08001259 protected void onReset() {
Dianne Hackborn4ef95cc2010-12-16 00:44:33 -08001260 unregisterObserver();
1261 mContact = null;
1262 mDestroyed = true;
1263 }
Daniel Lehmann4cd94412010-04-08 16:44:36 -07001264}