blob: a28b1db6fdaf7d79e0a2605aff24d253f8939b3c [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;
Daniel Lehmann4cd94412010-04-08 16:44:36 -070022import com.android.contacts.util.DataStatus;
Dave Santoro39156002011-07-19 01:18:14 -070023import com.android.contacts.util.StreamItemEntry;
24import com.android.contacts.util.StreamItemPhotoEntry;
Makoto Onuki69b4a882011-07-22 10:05:10 -070025import com.google.android.collect.Lists;
Flavio Lerda37a26842011-06-27 11:36:52 +010026import com.google.common.annotations.VisibleForTesting;
Makoto Onuki6ad227f2011-08-15 13:46:59 -070027import com.google.common.collect.Maps;
Makoto Onukiaba2b832011-08-12 15:44:53 -070028import com.google.common.collect.Sets;
Daniel Lehmann4cd94412010-04-08 16:44:36 -070029
30import android.content.ContentResolver;
31import android.content.ContentUris;
Dmitri Plotnikov4d444242010-07-30 11:39:39 -070032import android.content.ContentValues;
Daniel Lehmann4cd94412010-04-08 16:44:36 -070033import android.content.Context;
34import android.content.Entity;
Dmitri Plotnikovcaf0bc72010-09-03 15:16:21 -070035import android.content.Entity.NamedContentValues;
Daniel Lehmann3ef27fb2011-08-09 14:31:29 -070036import android.content.Intent;
Jeff Hamilton3c462912010-05-15 02:20:01 -050037import android.content.Loader;
Dmitri Plotnikov02cd4912010-09-01 20:42:17 -070038import android.content.pm.PackageManager;
39import android.content.pm.PackageManager.NameNotFoundException;
Dave Santoro0a2a5db2011-06-29 00:37:06 -070040import android.content.res.AssetFileDescriptor;
Dmitri Plotnikov02cd4912010-09-01 20:42:17 -070041import android.content.res.Resources;
Daniel Lehmann4cd94412010-04-08 16:44:36 -070042import android.database.Cursor;
43import android.net.Uri;
44import android.os.AsyncTask;
Daniel Lehmann1316b132010-04-13 15:08:53 -070045import android.provider.ContactsContract;
Dmitri Plotnikov4d444242010-07-30 11:39:39 -070046import android.provider.ContactsContract.CommonDataKinds.GroupMembership;
Dmitri Plotnikov7f4f8d12010-11-10 10:22:19 -080047import android.provider.ContactsContract.CommonDataKinds.Photo;
Daniel Lehmann4cd94412010-04-08 16:44:36 -070048import android.provider.ContactsContract.Contacts;
49import android.provider.ContactsContract.Data;
Dmitri Plotnikov02cd4912010-09-01 20:42:17 -070050import android.provider.ContactsContract.Directory;
Daniel Lehmann4cd94412010-04-08 16:44:36 -070051import android.provider.ContactsContract.DisplayNameSources;
Dmitri Plotnikov2deaee12010-09-15 15:42:08 -070052import android.provider.ContactsContract.Groups;
Daniel Lehmann4cd94412010-04-08 16:44:36 -070053import android.provider.ContactsContract.RawContacts;
Dave Santoro39156002011-07-19 01:18:14 -070054import android.provider.ContactsContract.StreamItemPhotos;
Makoto Onuki69b4a882011-07-22 10:05:10 -070055import android.provider.ContactsContract.StreamItems;
Dmitri Plotnikov02cd4912010-09-01 20:42:17 -070056import android.text.TextUtils;
Daniel Lehmann4cd94412010-04-08 16:44:36 -070057import android.util.Log;
58
Dmitri Plotnikov7f4f8d12010-11-10 10:22:19 -080059import java.io.ByteArrayOutputStream;
Dave Santoro0a2a5db2011-06-29 00:37:06 -070060import java.io.FileInputStream;
Dmitri Plotnikov7f4f8d12010-11-10 10:22:19 -080061import java.io.IOException;
62import java.io.InputStream;
Daniel Lehmann4cd94412010-04-08 16:44:36 -070063import java.util.ArrayList;
Dave Santoro39156002011-07-19 01:18:14 -070064import java.util.Collections;
Daniel Lehmann4cd94412010-04-08 16:44:36 -070065import java.util.HashMap;
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
Daniel Lehmann4cd94412010-04-08 16:44:36 -070076 private Uri mLookupUri;
Dmitri Plotnikove843f912010-09-16 15:21:48 -070077 private boolean mLoadGroupMetaData;
Dave Santoro39156002011-07-19 01:18:14 -070078 private boolean mLoadStreamItems;
Makoto Onuki69b4a882011-07-22 10:05:10 -070079 private final boolean mLoadInvitableAccountTypes;
Daniel Lehmann4cd94412010-04-08 16:44:36 -070080 private Result mContact;
81 private ForceLoadContentObserver mObserver;
82 private boolean mDestroyed;
Makoto Onukiaba2b832011-08-12 15:44:53 -070083 private final Set<Long> mNotifiedRawContactIds = Sets.newHashSet();
Dmitri Plotnikove843f912010-09-16 15:21:48 -070084
Daniel Lehmanncdef2b62010-06-06 18:25:49 -070085 public interface Listener {
Daniel Lehmann4cd94412010-04-08 16:44:36 -070086 public void onContactLoaded(Result contact);
87 }
88
89 /**
90 * The result of a load operation. Contains all data necessary to display the contact.
91 */
92 public static final class Result {
93 /**
94 * Singleton instance that represents "No Contact Found"
95 */
Makoto Onuki9e7b5da2011-08-22 15:51:28 -070096 public static final Result NOT_FOUND = new Result((Exception) null);
Daniel Lehmann18f104f2010-05-07 15:41:11 -070097
Daniel Lehmann4cd94412010-04-08 16:44:36 -070098 private final Uri mLookupUri;
Daniel Lehmann4cd94412010-04-08 16:44:36 -070099 private final Uri mUri;
Dmitri Plotnikov02cd4912010-09-01 20:42:17 -0700100 private final long mDirectoryId;
101 private final String mLookupKey;
Daniel Lehmann4cd94412010-04-08 16:44:36 -0700102 private final long mId;
Daniel Lehmann4cd94412010-04-08 16:44:36 -0700103 private final long mNameRawContactId;
104 private final int mDisplayNameSource;
Daniel Lehmannd3e0cdb2010-04-19 13:45:53 -0700105 private final long mPhotoId;
Dmitri Plotnikovf9eb73f2010-10-21 11:48:56 -0700106 private final String mPhotoUri;
Daniel Lehmannd3e0cdb2010-04-19 13:45:53 -0700107 private final String mDisplayName;
Dave Santoroda5bf1c2011-05-03 10:30:34 -0700108 private final String mAltDisplayName;
Daniel Lehmannd3e0cdb2010-04-19 13:45:53 -0700109 private final String mPhoneticName;
110 private final boolean mStarred;
111 private final Integer mPresence;
112 private final ArrayList<Entity> mEntities;
Makoto Onuki870a87e2011-08-12 13:40:31 -0700113 private final ArrayList<StreamItemEntry> mStreamItems;
Daniel Lehmannd3e0cdb2010-04-19 13:45:53 -0700114 private final HashMap<Long, DataStatus> mStatuses;
Dave Santoro2b3f3c52011-07-26 17:35:42 -0700115 private final ArrayList<AccountType> mInvitableAccountTypes;
Daniel Lehmann4cd94412010-04-08 16:44:36 -0700116
Dmitri Plotnikov02cd4912010-09-01 20:42:17 -0700117 private String mDirectoryDisplayName;
118 private String mDirectoryType;
Dmitri Plotnikovcaf0bc72010-09-03 15:16:21 -0700119 private String mDirectoryAccountType;
Dmitri Plotnikov02cd4912010-09-01 20:42:17 -0700120 private String mDirectoryAccountName;
121 private int mDirectoryExportSupport;
122
Dmitri Plotnikove843f912010-09-16 15:21:48 -0700123 private ArrayList<GroupMetaData> mGroups;
Dmitri Plotnikov2deaee12010-09-15 15:42:08 -0700124
Dmitri Plotnikov7f4f8d12010-11-10 10:22:19 -0800125 private boolean mLoadingPhoto;
126 private byte[] mPhotoBinaryData;
Makoto Onuki870a87e2011-08-12 13:40:31 -0700127 private final boolean mSendToVoicemail;
128 private final String mCustomRingtone;
129 private final boolean mIsUserProfile;
Dmitri Plotnikov7f4f8d12010-11-10 10:22:19 -0800130
Makoto Onuki9e7b5da2011-08-22 15:51:28 -0700131 private final Exception mException;
132
Daniel Lehmann4cd94412010-04-08 16:44:36 -0700133 /**
Makoto Onuki9e7b5da2011-08-22 15:51:28 -0700134 * Constructor for special results, namely "no contact found" and "error".
Daniel Lehmann4cd94412010-04-08 16:44:36 -0700135 */
Makoto Onuki9e7b5da2011-08-22 15:51:28 -0700136 private Result(Exception exception) {
Daniel Lehmann4cd94412010-04-08 16:44:36 -0700137 mLookupUri = null;
Daniel Lehmann4cd94412010-04-08 16:44:36 -0700138 mUri = null;
Dmitri Plotnikov02cd4912010-09-01 20:42:17 -0700139 mDirectoryId = -1;
140 mLookupKey = null;
Daniel Lehmann4cd94412010-04-08 16:44:36 -0700141 mId = -1;
142 mEntities = null;
Dave Santoro39156002011-07-19 01:18:14 -0700143 mStreamItems = new ArrayList<StreamItemEntry>();
Daniel Lehmann4cd94412010-04-08 16:44:36 -0700144 mStatuses = null;
145 mNameRawContactId = -1;
146 mDisplayNameSource = DisplayNameSources.UNDEFINED;
Daniel Lehmannd3e0cdb2010-04-19 13:45:53 -0700147 mPhotoId = -1;
Dmitri Plotnikovf9eb73f2010-10-21 11:48:56 -0700148 mPhotoUri = null;
Daniel Lehmannd3e0cdb2010-04-19 13:45:53 -0700149 mDisplayName = null;
Dave Santoroda5bf1c2011-05-03 10:30:34 -0700150 mAltDisplayName = null;
Daniel Lehmannd3e0cdb2010-04-19 13:45:53 -0700151 mPhoneticName = null;
152 mStarred = false;
153 mPresence = null;
Makoto Onuki69b4a882011-07-22 10:05:10 -0700154 mInvitableAccountTypes = null;
Isaac Katzenelson683b57e2011-07-20 17:06:11 -0700155 mSendToVoicemail = false;
156 mCustomRingtone = null;
Isaac Katzenelsonead19c52011-07-29 18:24:53 -0700157 mIsUserProfile = false;
Makoto Onuki9e7b5da2011-08-22 15:51:28 -0700158 mException = exception;
159 }
Isaac Katzenelsonead19c52011-07-29 18:24:53 -0700160
Makoto Onuki9e7b5da2011-08-22 15:51:28 -0700161 private static Result forError(Exception exception) {
162 return new Result(exception);
Daniel Lehmann4cd94412010-04-08 16:44:36 -0700163 }
164
165 /**
166 * Constructor to call when contact was found
167 */
Dmitri Plotnikov02cd4912010-09-01 20:42:17 -0700168 private Result(Uri uri, Uri lookupUri, long directoryId, String lookupKey, long id,
Dmitri Plotnikovf9eb73f2010-10-21 11:48:56 -0700169 long nameRawContactId, int displayNameSource, long photoId, String photoUri,
Dave Santoroda5bf1c2011-05-03 10:30:34 -0700170 String displayName, String altDisplayName, String phoneticName, boolean starred,
Isaac Katzenelsonead19c52011-07-29 18:24:53 -0700171 Integer presence, boolean sendToVoicemail, String customRingtone,
172 boolean isUserProfile) {
Makoto Onuki9e7b5da2011-08-22 15:51:28 -0700173 mException = null;
Daniel Lehmann4cd94412010-04-08 16:44:36 -0700174 mLookupUri = lookupUri;
Daniel Lehmann4cd94412010-04-08 16:44:36 -0700175 mUri = uri;
Dmitri Plotnikov02cd4912010-09-01 20:42:17 -0700176 mDirectoryId = directoryId;
177 mLookupKey = lookupKey;
Daniel Lehmann4cd94412010-04-08 16:44:36 -0700178 mId = id;
179 mEntities = new ArrayList<Entity>();
Dave Santoro39156002011-07-19 01:18:14 -0700180 mStreamItems = new ArrayList<StreamItemEntry>();
Daniel Lehmann4cd94412010-04-08 16:44:36 -0700181 mStatuses = new HashMap<Long, DataStatus>();
182 mNameRawContactId = nameRawContactId;
183 mDisplayNameSource = displayNameSource;
Daniel Lehmannd3e0cdb2010-04-19 13:45:53 -0700184 mPhotoId = photoId;
Dmitri Plotnikovf9eb73f2010-10-21 11:48:56 -0700185 mPhotoUri = photoUri;
Daniel Lehmannd3e0cdb2010-04-19 13:45:53 -0700186 mDisplayName = displayName;
Dave Santoroda5bf1c2011-05-03 10:30:34 -0700187 mAltDisplayName = altDisplayName;
Daniel Lehmannd3e0cdb2010-04-19 13:45:53 -0700188 mPhoneticName = phoneticName;
189 mStarred = starred;
190 mPresence = presence;
Makoto Onuki69b4a882011-07-22 10:05:10 -0700191 mInvitableAccountTypes = Lists.newArrayList();
Isaac Katzenelson683b57e2011-07-20 17:06:11 -0700192 mSendToVoicemail = sendToVoicemail;
193 mCustomRingtone = customRingtone;
Isaac Katzenelsonead19c52011-07-29 18:24:53 -0700194 mIsUserProfile = isUserProfile;
Daniel Lehmann4cd94412010-04-08 16:44:36 -0700195 }
196
Dmitri Plotnikov7cee7742011-01-13 17:11:06 -0800197 private Result(Result from) {
Makoto Onuki9e7b5da2011-08-22 15:51:28 -0700198 mException = from.mException;
Dmitri Plotnikov7cee7742011-01-13 17:11:06 -0800199 mLookupUri = from.mLookupUri;
200 mUri = from.mUri;
201 mDirectoryId = from.mDirectoryId;
202 mLookupKey = from.mLookupKey;
203 mId = from.mId;
204 mNameRawContactId = from.mNameRawContactId;
205 mDisplayNameSource = from.mDisplayNameSource;
206 mPhotoId = from.mPhotoId;
207 mPhotoUri = from.mPhotoUri;
208 mDisplayName = from.mDisplayName;
Dave Santoroda5bf1c2011-05-03 10:30:34 -0700209 mAltDisplayName = from.mAltDisplayName;
Dmitri Plotnikov7cee7742011-01-13 17:11:06 -0800210 mPhoneticName = from.mPhoneticName;
211 mStarred = from.mStarred;
212 mPresence = from.mPresence;
213 mEntities = from.mEntities;
Dave Santoro39156002011-07-19 01:18:14 -0700214 mStreamItems = from.mStreamItems;
Dmitri Plotnikov7cee7742011-01-13 17:11:06 -0800215 mStatuses = from.mStatuses;
Makoto Onuki69b4a882011-07-22 10:05:10 -0700216 mInvitableAccountTypes = from.mInvitableAccountTypes;
Dmitri Plotnikov7cee7742011-01-13 17:11:06 -0800217
218 mDirectoryDisplayName = from.mDirectoryDisplayName;
219 mDirectoryType = from.mDirectoryType;
220 mDirectoryAccountType = from.mDirectoryAccountType;
221 mDirectoryAccountName = from.mDirectoryAccountName;
222 mDirectoryExportSupport = from.mDirectoryExportSupport;
223
224 mGroups = from.mGroups;
225
226 mLoadingPhoto = from.mLoadingPhoto;
227 mPhotoBinaryData = from.mPhotoBinaryData;
Isaac Katzenelson683b57e2011-07-20 17:06:11 -0700228 mSendToVoicemail = from.mSendToVoicemail;
229 mCustomRingtone = from.mCustomRingtone;
Isaac Katzenelsonead19c52011-07-29 18:24:53 -0700230 mIsUserProfile = from.mIsUserProfile;
Dmitri Plotnikov7cee7742011-01-13 17:11:06 -0800231 }
232
Dmitri Plotnikov02cd4912010-09-01 20:42:17 -0700233 /**
234 * @param exportSupport See {@link Directory#EXPORT_SUPPORT}.
235 */
Daniel Lehmann1ad4d1b2010-10-18 19:20:41 -0700236 private void setDirectoryMetaData(String displayName, String directoryType,
Dmitri Plotnikovcaf0bc72010-09-03 15:16:21 -0700237 String accountType, String accountName, int exportSupport) {
Dmitri Plotnikov02cd4912010-09-01 20:42:17 -0700238 mDirectoryDisplayName = displayName;
239 mDirectoryType = directoryType;
Dmitri Plotnikovcaf0bc72010-09-03 15:16:21 -0700240 mDirectoryAccountType = accountType;
Dmitri Plotnikov02cd4912010-09-01 20:42:17 -0700241 mDirectoryAccountName = accountName;
242 mDirectoryExportSupport = exportSupport;
243 }
244
Dmitri Plotnikov7f4f8d12010-11-10 10:22:19 -0800245 private void setLoadingPhoto(boolean flag) {
246 mLoadingPhoto = flag;
247 }
248
249 private void setPhotoBinaryData(byte[] photoBinaryData) {
250 mPhotoBinaryData = photoBinaryData;
251 }
252
Daniel Lehmann4cd94412010-04-08 16:44:36 -0700253 public Uri getLookupUri() {
254 return mLookupUri;
255 }
Dmitri Plotnikov7f4f8d12010-11-10 10:22:19 -0800256
Daniel Lehmann4cd94412010-04-08 16:44:36 -0700257 public String getLookupKey() {
258 return mLookupKey;
259 }
Dmitri Plotnikov7f4f8d12010-11-10 10:22:19 -0800260
Daniel Lehmann4cd94412010-04-08 16:44:36 -0700261 public Uri getUri() {
262 return mUri;
263 }
Dmitri Plotnikov7f4f8d12010-11-10 10:22:19 -0800264
Flavio Lerda37a26842011-06-27 11:36:52 +0100265 @VisibleForTesting
266 /*package*/ long getId() {
Daniel Lehmann4cd94412010-04-08 16:44:36 -0700267 return mId;
268 }
Dmitri Plotnikov7f4f8d12010-11-10 10:22:19 -0800269
Makoto Onuki9e7b5da2011-08-22 15:51:28 -0700270 /**
271 * @return true when an exception happened during loading, in which case
272 * {@link #getException} returns the actual exception object.
273 */
274 public boolean isError() {
275 return mException != null;
276 }
277
278 public Exception getException() {
279 return mException;
280 }
281
Daniel Lehmann4cd94412010-04-08 16:44:36 -0700282 public long getNameRawContactId() {
283 return mNameRawContactId;
284 }
Dmitri Plotnikov7f4f8d12010-11-10 10:22:19 -0800285
Daniel Lehmann4cd94412010-04-08 16:44:36 -0700286 public int getDisplayNameSource() {
287 return mDisplayNameSource;
288 }
Dmitri Plotnikov7f4f8d12010-11-10 10:22:19 -0800289
Daniel Lehmannd3e0cdb2010-04-19 13:45:53 -0700290 public long getPhotoId() {
291 return mPhotoId;
292 }
Dmitri Plotnikov7f4f8d12010-11-10 10:22:19 -0800293
Dmitri Plotnikovf9eb73f2010-10-21 11:48:56 -0700294 public String getPhotoUri() {
295 return mPhotoUri;
296 }
Dmitri Plotnikov7f4f8d12010-11-10 10:22:19 -0800297
Daniel Lehmannd3e0cdb2010-04-19 13:45:53 -0700298 public String getDisplayName() {
299 return mDisplayName;
300 }
Dmitri Plotnikov7f4f8d12010-11-10 10:22:19 -0800301
Dave Santoroda5bf1c2011-05-03 10:30:34 -0700302 public String getAltDisplayName() {
303 return mAltDisplayName;
304 }
305
Daniel Lehmannd3e0cdb2010-04-19 13:45:53 -0700306 public String getPhoneticName() {
307 return mPhoneticName;
308 }
Dmitri Plotnikov7f4f8d12010-11-10 10:22:19 -0800309
Daniel Lehmannd3e0cdb2010-04-19 13:45:53 -0700310 public boolean getStarred() {
311 return mStarred;
312 }
Dmitri Plotnikov7f4f8d12010-11-10 10:22:19 -0800313
Daniel Lehmannd3e0cdb2010-04-19 13:45:53 -0700314 public Integer getPresence() {
315 return mPresence;
316 }
Dmitri Plotnikov7f4f8d12010-11-10 10:22:19 -0800317
Dave Santoro2b3f3c52011-07-26 17:35:42 -0700318 public ArrayList<AccountType> getInvitableAccountTypes() {
Makoto Onuki69b4a882011-07-22 10:05:10 -0700319 return mInvitableAccountTypes;
320 }
321
Daniel Lehmannd3e0cdb2010-04-19 13:45:53 -0700322 public ArrayList<Entity> getEntities() {
323 return mEntities;
324 }
Dmitri Plotnikov7f4f8d12010-11-10 10:22:19 -0800325
Dave Santoro39156002011-07-19 01:18:14 -0700326 public ArrayList<StreamItemEntry> getStreamItems() {
327 return mStreamItems;
328 }
329
Daniel Lehmannd3e0cdb2010-04-19 13:45:53 -0700330 public HashMap<Long, DataStatus> getStatuses() {
331 return mStatuses;
332 }
Dmitri Plotnikov02cd4912010-09-01 20:42:17 -0700333
334 public long getDirectoryId() {
335 return mDirectoryId;
336 }
337
338 public boolean isDirectoryEntry() {
Dmitri Plotnikov5f72c1f2010-09-01 21:21:04 -0700339 return mDirectoryId != -1 && mDirectoryId != Directory.DEFAULT
340 && mDirectoryId != Directory.LOCAL_INVISIBLE;
Dmitri Plotnikov02cd4912010-09-01 20:42:17 -0700341 }
342
343 public int getDirectoryExportSupport() {
344 return mDirectoryExportSupport;
345 }
346
347 public String getDirectoryDisplayName() {
348 return mDirectoryDisplayName;
349 }
350
351 public String getDirectoryType() {
352 return mDirectoryType;
353 }
354
Dmitri Plotnikovcaf0bc72010-09-03 15:16:21 -0700355 public String getDirectoryAccountType() {
356 return mDirectoryAccountType;
357 }
358
Dmitri Plotnikov02cd4912010-09-01 20:42:17 -0700359 public String getDirectoryAccountName() {
360 return mDirectoryAccountName;
361 }
362
Dmitri Plotnikov7f4f8d12010-11-10 10:22:19 -0800363 public boolean isLoadingPhoto() {
364 return mLoadingPhoto;
365 }
366
367 public byte[] getPhotoBinaryData() {
368 return mPhotoBinaryData;
369 }
370
Dmitri Plotnikovcaf0bc72010-09-03 15:16:21 -0700371 public ArrayList<ContentValues> getContentValues() {
372 if (mEntities.size() != 1) {
373 throw new IllegalStateException(
374 "Cannot extract content values from an aggregated contact");
375 }
376
377 Entity entity = mEntities.get(0);
378 ArrayList<ContentValues> result = new ArrayList<ContentValues>();
379 ArrayList<NamedContentValues> subValues = entity.getSubValues();
380 if (subValues != null) {
381 int size = subValues.size();
382 for (int i = 0; i < size; i++) {
383 NamedContentValues pair = subValues.get(i);
384 if (Data.CONTENT_URI.equals(pair.uri)) {
385 result.add(pair.values);
386 }
387 }
388 }
Dmitri Plotnikov40ec3a82010-11-10 11:25:33 -0800389
390 // If the photo was loaded using the URI, create an entry for the photo
391 // binary data.
392 if (mPhotoId == 0 && mPhotoBinaryData != null) {
393 ContentValues photo = new ContentValues();
394 photo.put(Data.MIMETYPE, Photo.CONTENT_ITEM_TYPE);
395 photo.put(Photo.PHOTO, mPhotoBinaryData);
396 result.add(photo);
397 }
398
Dmitri Plotnikovcaf0bc72010-09-03 15:16:21 -0700399 return result;
400 }
Dmitri Plotnikov2deaee12010-09-15 15:42:08 -0700401
Daniel Lehmann1ad4d1b2010-10-18 19:20:41 -0700402 private void addGroupMetaData(GroupMetaData group) {
Dmitri Plotnikov2deaee12010-09-15 15:42:08 -0700403 if (mGroups == null) {
Dmitri Plotnikove843f912010-09-16 15:21:48 -0700404 mGroups = new ArrayList<GroupMetaData>();
Dmitri Plotnikov2deaee12010-09-15 15:42:08 -0700405 }
406 mGroups.add(group);
407 }
408
Dmitri Plotnikove843f912010-09-16 15:21:48 -0700409 public List<GroupMetaData> getGroupMetaData() {
Dmitri Plotnikov2deaee12010-09-15 15:42:08 -0700410 return mGroups;
411 }
Isaac Katzenelson683b57e2011-07-20 17:06:11 -0700412
413 public boolean isSendToVoicemail() {
414 return mSendToVoicemail;
415 }
416
417 public String getCustomRingtone() {
418 return mCustomRingtone;
419 }
Isaac Katzenelsonead19c52011-07-29 18:24:53 -0700420
421 public boolean isUserProfile() {
422 return mIsUserProfile;
423 }
Dmitri Plotnikov2deaee12010-09-15 15:42:08 -0700424 }
425
Dave Santoro39156002011-07-19 01:18:14 -0700426 /**
427 * Projection used for the query that loads all data for the entire contact (except for
428 * social stream items).
429 */
Dmitri Plotnikov4d444242010-07-30 11:39:39 -0700430 private static class ContactQuery {
Daniel Lehmannd3e0cdb2010-04-19 13:45:53 -0700431 final static String[] COLUMNS = new String[] {
432 Contacts.NAME_RAW_CONTACT_ID,
433 Contacts.DISPLAY_NAME_SOURCE,
434 Contacts.LOOKUP_KEY,
435 Contacts.DISPLAY_NAME,
Dave Santoroda5bf1c2011-05-03 10:30:34 -0700436 Contacts.DISPLAY_NAME_ALTERNATIVE,
Daniel Lehmannd3e0cdb2010-04-19 13:45:53 -0700437 Contacts.PHONETIC_NAME,
438 Contacts.PHOTO_ID,
439 Contacts.STARRED,
440 Contacts.CONTACT_PRESENCE,
441 Contacts.CONTACT_STATUS,
442 Contacts.CONTACT_STATUS_TIMESTAMP,
443 Contacts.CONTACT_STATUS_RES_PACKAGE,
444 Contacts.CONTACT_STATUS_LABEL,
Dmitri Plotnikov4d444242010-07-30 11:39:39 -0700445 Contacts.Entity.CONTACT_ID,
446 Contacts.Entity.RAW_CONTACT_ID,
447
448 RawContacts.ACCOUNT_NAME,
449 RawContacts.ACCOUNT_TYPE,
Dave Santoro2b3f3c52011-07-26 17:35:42 -0700450 RawContacts.DATA_SET,
451 RawContacts.ACCOUNT_TYPE_AND_DATA_SET,
Dmitri Plotnikov4d444242010-07-30 11:39:39 -0700452 RawContacts.DIRTY,
453 RawContacts.VERSION,
454 RawContacts.SOURCE_ID,
455 RawContacts.SYNC1,
456 RawContacts.SYNC2,
457 RawContacts.SYNC3,
458 RawContacts.SYNC4,
459 RawContacts.DELETED,
Dmitri Plotnikov4d444242010-07-30 11:39:39 -0700460 RawContacts.NAME_VERIFIED,
461
462 Contacts.Entity.DATA_ID,
463 Data.DATA1,
464 Data.DATA2,
465 Data.DATA3,
466 Data.DATA4,
467 Data.DATA5,
468 Data.DATA6,
469 Data.DATA7,
470 Data.DATA8,
471 Data.DATA9,
472 Data.DATA10,
473 Data.DATA11,
474 Data.DATA12,
475 Data.DATA13,
476 Data.DATA14,
477 Data.DATA15,
478 Data.SYNC1,
479 Data.SYNC2,
480 Data.SYNC3,
481 Data.SYNC4,
482 Data.DATA_VERSION,
483 Data.IS_PRIMARY,
484 Data.IS_SUPER_PRIMARY,
485 Data.MIMETYPE,
486 Data.RES_PACKAGE,
487
488 GroupMembership.GROUP_SOURCE_ID,
489
490 Data.PRESENCE,
Daniel Lehmann8fd7bb62010-08-13 20:50:31 -0700491 Data.CHAT_CAPABILITY,
Dmitri Plotnikov4d444242010-07-30 11:39:39 -0700492 Data.STATUS,
493 Data.STATUS_RES_PACKAGE,
494 Data.STATUS_ICON,
495 Data.STATUS_LABEL,
Dmitri Plotnikovf9eb73f2010-10-21 11:48:56 -0700496 Data.STATUS_TIMESTAMP,
497
498 Contacts.PHOTO_URI,
Isaac Katzenelson683b57e2011-07-20 17:06:11 -0700499 Contacts.SEND_TO_VOICEMAIL,
500 Contacts.CUSTOM_RINGTONE,
Isaac Katzenelsonead19c52011-07-29 18:24:53 -0700501 Contacts.IS_USER_PROFILE,
Daniel Lehmannd3e0cdb2010-04-19 13:45:53 -0700502 };
Dmitri Plotnikov4d444242010-07-30 11:39:39 -0700503
504 public final static int NAME_RAW_CONTACT_ID = 0;
505 public final static int DISPLAY_NAME_SOURCE = 1;
506 public final static int LOOKUP_KEY = 2;
507 public final static int DISPLAY_NAME = 3;
Dave Santoroda5bf1c2011-05-03 10:30:34 -0700508 public final static int ALT_DISPLAY_NAME = 4;
509 public final static int PHONETIC_NAME = 5;
510 public final static int PHOTO_ID = 6;
511 public final static int STARRED = 7;
512 public final static int CONTACT_PRESENCE = 8;
513 public final static int CONTACT_STATUS = 9;
514 public final static int CONTACT_STATUS_TIMESTAMP = 10;
515 public final static int CONTACT_STATUS_RES_PACKAGE = 11;
516 public final static int CONTACT_STATUS_LABEL = 12;
517 public final static int CONTACT_ID = 13;
518 public final static int RAW_CONTACT_ID = 14;
Dmitri Plotnikov4d444242010-07-30 11:39:39 -0700519
Dave Santoroda5bf1c2011-05-03 10:30:34 -0700520 public final static int ACCOUNT_NAME = 15;
521 public final static int ACCOUNT_TYPE = 16;
Dave Santoro2b3f3c52011-07-26 17:35:42 -0700522 public final static int DATA_SET = 17;
523 public final static int ACCOUNT_TYPE_AND_DATA_SET = 18;
524 public final static int DIRTY = 19;
525 public final static int VERSION = 20;
526 public final static int SOURCE_ID = 21;
527 public final static int SYNC1 = 22;
528 public final static int SYNC2 = 23;
529 public final static int SYNC3 = 24;
530 public final static int SYNC4 = 25;
531 public final static int DELETED = 26;
532 public final static int NAME_VERIFIED = 27;
Dmitri Plotnikov4d444242010-07-30 11:39:39 -0700533
Dave Santoro2b3f3c52011-07-26 17:35:42 -0700534 public final static int DATA_ID = 28;
535 public final static int DATA1 = 29;
536 public final static int DATA2 = 30;
537 public final static int DATA3 = 31;
538 public final static int DATA4 = 32;
539 public final static int DATA5 = 33;
540 public final static int DATA6 = 34;
541 public final static int DATA7 = 35;
542 public final static int DATA8 = 36;
543 public final static int DATA9 = 37;
544 public final static int DATA10 = 38;
545 public final static int DATA11 = 39;
546 public final static int DATA12 = 40;
547 public final static int DATA13 = 41;
548 public final static int DATA14 = 42;
549 public final static int DATA15 = 43;
550 public final static int DATA_SYNC1 = 44;
551 public final static int DATA_SYNC2 = 45;
552 public final static int DATA_SYNC3 = 46;
553 public final static int DATA_SYNC4 = 47;
554 public final static int DATA_VERSION = 48;
555 public final static int IS_PRIMARY = 49;
556 public final static int IS_SUPERPRIMARY = 50;
557 public final static int MIMETYPE = 51;
558 public final static int RES_PACKAGE = 52;
Dmitri Plotnikov4d444242010-07-30 11:39:39 -0700559
Dave Santoro2b3f3c52011-07-26 17:35:42 -0700560 public final static int GROUP_SOURCE_ID = 53;
Dmitri Plotnikov4d444242010-07-30 11:39:39 -0700561
Dave Santoro2b3f3c52011-07-26 17:35:42 -0700562 public final static int PRESENCE = 54;
563 public final static int CHAT_CAPABILITY = 55;
564 public final static int STATUS = 56;
565 public final static int STATUS_RES_PACKAGE = 57;
566 public final static int STATUS_ICON = 58;
567 public final static int STATUS_LABEL = 59;
568 public final static int STATUS_TIMESTAMP = 60;
Dmitri Plotnikovf9eb73f2010-10-21 11:48:56 -0700569
Dave Santoro2b3f3c52011-07-26 17:35:42 -0700570 public final static int PHOTO_URI = 61;
571 public final static int SEND_TO_VOICEMAIL = 62;
572 public final static int CUSTOM_RINGTONE = 63;
Isaac Katzenelsonead19c52011-07-29 18:24:53 -0700573 public final static int IS_USER_PROFILE = 64;
Daniel Lehmannd3e0cdb2010-04-19 13:45:53 -0700574 }
Daniel Lehmann1316b132010-04-13 15:08:53 -0700575
Dave Santoro39156002011-07-19 01:18:14 -0700576 /**
577 * Projection used for the query that loads all data for the entire contact.
578 */
Dmitri Plotnikov02cd4912010-09-01 20:42:17 -0700579 private static class DirectoryQuery {
Dmitri Plotnikov02cd4912010-09-01 20:42:17 -0700580 final static String[] COLUMNS = new String[] {
581 Directory.DISPLAY_NAME,
582 Directory.PACKAGE_NAME,
583 Directory.TYPE_RESOURCE_ID,
Dmitri Plotnikovcaf0bc72010-09-03 15:16:21 -0700584 Directory.ACCOUNT_TYPE,
Dmitri Plotnikov02cd4912010-09-01 20:42:17 -0700585 Directory.ACCOUNT_NAME,
586 Directory.EXPORT_SUPPORT,
587 };
588
589 public final static int DISPLAY_NAME = 0;
590 public final static int PACKAGE_NAME = 1;
591 public final static int TYPE_RESOURCE_ID = 2;
Dmitri Plotnikovcaf0bc72010-09-03 15:16:21 -0700592 public final static int ACCOUNT_TYPE = 3;
593 public final static int ACCOUNT_NAME = 4;
594 public final static int EXPORT_SUPPORT = 5;
Dmitri Plotnikov02cd4912010-09-01 20:42:17 -0700595 }
596
Dmitri Plotnikov2deaee12010-09-15 15:42:08 -0700597 private static class GroupQuery {
598 final static String[] COLUMNS = new String[] {
599 Groups.ACCOUNT_NAME,
600 Groups.ACCOUNT_TYPE,
Dave Santoro2b3f3c52011-07-26 17:35:42 -0700601 Groups.DATA_SET,
602 Groups.ACCOUNT_TYPE_AND_DATA_SET,
Dmitri Plotnikov2deaee12010-09-15 15:42:08 -0700603 Groups._ID,
604 Groups.TITLE,
605 Groups.AUTO_ADD,
606 Groups.FAVORITES,
607 };
608
609 public final static int ACCOUNT_NAME = 0;
610 public final static int ACCOUNT_TYPE = 1;
Dave Santoro2b3f3c52011-07-26 17:35:42 -0700611 public final static int DATA_SET = 2;
612 public final static int ACCOUNT_TYPE_AND_DATA_SET = 3;
613 public final static int ID = 4;
614 public final static int TITLE = 5;
615 public final static int AUTO_ADD = 6;
616 public final static int FAVORITES = 7;
Dmitri Plotnikov2deaee12010-09-15 15:42:08 -0700617 }
618
Daniel Lehmann18f104f2010-05-07 15:41:11 -0700619 private final class LoadContactTask extends AsyncTask<Void, Void, Result> {
Daniel Lehmann1316b132010-04-13 15:08:53 -0700620
Daniel Lehmann4cd94412010-04-08 16:44:36 -0700621 @Override
622 protected Result doInBackground(Void... args) {
Daniel Lehmann18f104f2010-05-07 15:41:11 -0700623 try {
624 final ContentResolver resolver = getContext().getContentResolver();
Daniel Lehmanncdef2b62010-06-06 18:25:49 -0700625 final Uri uriCurrentFormat = ensureIsContactUri(resolver, mLookupUri);
Dmitri Plotnikov02cd4912010-09-01 20:42:17 -0700626 Result result = loadContactEntity(resolver, uriCurrentFormat);
Dmitri Plotnikov217245c2010-09-18 13:04:50 -0700627 if (result != Result.NOT_FOUND) {
628 if (result.isDirectoryEntry()) {
629 loadDirectoryMetaData(result);
630 } else if (mLoadGroupMetaData) {
631 loadGroupMetaData(result);
632 }
Dave Santoro39156002011-07-19 01:18:14 -0700633 if (mLoadStreamItems) {
634 loadStreamItems(result);
635 }
Dmitri Plotnikov7f4f8d12010-11-10 10:22:19 -0800636 loadPhotoBinaryData(result);
Makoto Onuki870a87e2011-08-12 13:40:31 -0700637
638 // Note ME profile should never have "Add connection"
639 if (mLoadInvitableAccountTypes && !result.isUserProfile()) {
Makoto Onuki69b4a882011-07-22 10:05:10 -0700640 loadInvitableAccountTypes(result);
641 }
Dmitri Plotnikov02cd4912010-09-01 20:42:17 -0700642 }
643 return result;
Daniel Lehmann18f104f2010-05-07 15:41:11 -0700644 } catch (Exception e) {
Dmitri Plotnikov4d444242010-07-30 11:39:39 -0700645 Log.e(TAG, "Error loading the contact: " + mLookupUri, e);
Makoto Onuki9e7b5da2011-08-22 15:51:28 -0700646 return Result.forError(e);
Daniel Lehmann4cd94412010-04-08 16:44:36 -0700647 }
Daniel Lehmann4cd94412010-04-08 16:44:36 -0700648 }
649
650 /**
Daniel Lehmann1316b132010-04-13 15:08:53 -0700651 * Transforms the given Uri and returns a Lookup-Uri that represents the contact.
652 * For legacy contacts, a raw-contact lookup is performed.
Daniel Lehmanncdef2b62010-06-06 18:25:49 -0700653 * @param resolver
Daniel Lehmann1316b132010-04-13 15:08:53 -0700654 */
Daniel Lehmanncdef2b62010-06-06 18:25:49 -0700655 private Uri ensureIsContactUri(final ContentResolver resolver, final Uri uri) {
Daniel Lehmann1316b132010-04-13 15:08:53 -0700656 if (uri == null) throw new IllegalArgumentException("uri must not be null");
657
658 final String authority = uri.getAuthority();
659
Daniel Lehmanncdef2b62010-06-06 18:25:49 -0700660 // Current Style Uri?
Daniel Lehmann1316b132010-04-13 15:08:53 -0700661 if (ContactsContract.AUTHORITY.equals(authority)) {
Daniel Lehmanncdef2b62010-06-06 18:25:49 -0700662 final String type = resolver.getType(uri);
663 // Contact-Uri? Good, return it
664 if (Contacts.CONTENT_ITEM_TYPE.equals(type)) {
665 return uri;
666 }
667
668 // RawContact-Uri? Transform it to ContactUri
669 if (RawContacts.CONTENT_ITEM_TYPE.equals(type)) {
670 final long rawContactId = ContentUris.parseId(uri);
671 return RawContacts.getContactLookupUri(getContext().getContentResolver(),
672 ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId));
673 }
674
675 // Anything else? We don't know what this is
676 throw new IllegalArgumentException("uri format is unknown");
Daniel Lehmann1316b132010-04-13 15:08:53 -0700677 }
678
679 // Legacy Style? Convert to RawContact
680 final String OBSOLETE_AUTHORITY = "contacts";
681 if (OBSOLETE_AUTHORITY.equals(authority)) {
682 // Legacy Format. Convert to RawContact-Uri and then lookup the contact
683 final long rawContactId = ContentUris.parseId(uri);
Daniel Lehmanncdef2b62010-06-06 18:25:49 -0700684 return RawContacts.getContactLookupUri(resolver,
Daniel Lehmann1316b132010-04-13 15:08:53 -0700685 ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId));
686 }
687
Daniel Lehmanncdef2b62010-06-06 18:25:49 -0700688 throw new IllegalArgumentException("uri authority is unknown");
Daniel Lehmann1316b132010-04-13 15:08:53 -0700689 }
690
Dmitri Plotnikov4d444242010-07-30 11:39:39 -0700691 private Result loadContactEntity(ContentResolver resolver, Uri contactUri) {
692 Uri entityUri = Uri.withAppendedPath(contactUri, Contacts.Entity.CONTENT_DIRECTORY);
693 Cursor cursor = resolver.query(entityUri, ContactQuery.COLUMNS, null, null,
694 Contacts.Entity.RAW_CONTACT_ID);
Daniel Lehmann4cd94412010-04-08 16:44:36 -0700695 if (cursor == null) {
Dmitri Plotnikov4d444242010-07-30 11:39:39 -0700696 Log.e(TAG, "No cursor returned in loadContactEntity");
697 return Result.NOT_FOUND;
Daniel Lehmann4cd94412010-04-08 16:44:36 -0700698 }
Dmitri Plotnikov4d444242010-07-30 11:39:39 -0700699
Daniel Lehmann4cd94412010-04-08 16:44:36 -0700700 try {
701 if (!cursor.moveToFirst()) {
Dmitri Plotnikov4d444242010-07-30 11:39:39 -0700702 cursor.close();
Daniel Lehmann4cd94412010-04-08 16:44:36 -0700703 return Result.NOT_FOUND;
704 }
705
Dmitri Plotnikov4d444242010-07-30 11:39:39 -0700706 long currentRawContactId = -1;
707 Entity entity = null;
708 Result result = loadContactHeaderData(cursor, contactUri);
Daniel Lehmann4cd94412010-04-08 16:44:36 -0700709 ArrayList<Entity> entities = result.getEntities();
Dmitri Plotnikov4d444242010-07-30 11:39:39 -0700710 HashMap<Long, DataStatus> statuses = result.getStatuses();
711 for (; !cursor.isAfterLast(); cursor.moveToNext()) {
712 long rawContactId = cursor.getLong(ContactQuery.RAW_CONTACT_ID);
713 if (rawContactId != currentRawContactId) {
714 currentRawContactId = rawContactId;
715 entity = new android.content.Entity(loadRawContact(cursor));
Daniel Lehmann4cd94412010-04-08 16:44:36 -0700716 entities.add(entity);
717 }
Dmitri Plotnikov4d444242010-07-30 11:39:39 -0700718 if (!cursor.isNull(ContactQuery.DATA_ID)) {
719 ContentValues data = loadData(cursor);
720 entity.addSubValue(ContactsContract.Data.CONTENT_URI, data);
721
722 if (!cursor.isNull(ContactQuery.PRESENCE)
723 || !cursor.isNull(ContactQuery.STATUS)) {
724 final DataStatus status = new DataStatus(cursor);
725 final long dataId = cursor.getLong(ContactQuery.DATA_ID);
726 statuses.put(dataId, status);
727 }
728 }
Daniel Lehmann4cd94412010-04-08 16:44:36 -0700729 }
Dmitri Plotnikov4d444242010-07-30 11:39:39 -0700730
731 return result;
Daniel Lehmann4cd94412010-04-08 16:44:36 -0700732 } finally {
733 cursor.close();
734 }
735 }
736
Dmitri Plotnikov4d444242010-07-30 11:39:39 -0700737 /**
Dmitri Plotnikov7f4f8d12010-11-10 10:22:19 -0800738 * Looks for the photo data item in entities. If found, creates a new Bitmap instance. If
739 * not found, returns null
740 */
741 private void loadPhotoBinaryData(Result contactData) {
Dave Santoro0a2a5db2011-06-29 00:37:06 -0700742
743 // If we have a photo URI, try loading that first.
744 String photoUri = contactData.getPhotoUri();
745 if (photoUri != null) {
746 try {
747 AssetFileDescriptor fd = getContext().getContentResolver()
748 .openAssetFileDescriptor(Uri.parse(photoUri), "r");
749 byte[] buffer = new byte[16 * 1024];
750 FileInputStream fis = fd.createInputStream();
751 ByteArrayOutputStream baos = new ByteArrayOutputStream();
752 try {
753 int size;
754 while ((size = fis.read(buffer)) != -1) {
755 baos.write(buffer, 0, size);
756 }
757 contactData.setPhotoBinaryData(baos.toByteArray());
758 } finally {
759 fis.close();
760 fd.close();
761 }
762 return;
763 } catch (IOException ioe) {
764 // Just fall back to the case below.
765 }
766 }
767
768 // If we couldn't load from a file, fall back to the data blob.
Dmitri Plotnikov7f4f8d12010-11-10 10:22:19 -0800769 final long photoId = contactData.getPhotoId();
770 if (photoId <= 0) {
771 // No photo ID
772 return;
773 }
774
775 for (Entity entity : contactData.getEntities()) {
776 for (NamedContentValues subValue : entity.getSubValues()) {
777 final ContentValues entryValues = subValue.values;
778 final long dataId = entryValues.getAsLong(Data._ID);
779 if (dataId == photoId) {
780 final String mimeType = entryValues.getAsString(Data.MIMETYPE);
781 // Correct Data Id but incorrect MimeType? Don't load
782 if (!Photo.CONTENT_ITEM_TYPE.equals(mimeType)) {
783 return;
784 }
785 contactData.setPhotoBinaryData(entryValues.getAsByteArray(Photo.PHOTO));
786 break;
787 }
788 }
789 }
790 }
791
Makoto Onuki3e6991e2011-07-24 14:51:20 -0700792 /**
793 * Sets the "invitable" account types to {@link Result#mInvitableAccountTypes}.
794 *
795 * TODO Exclude the ones with no raw contacts in the database.
796 */
Makoto Onuki69b4a882011-07-22 10:05:10 -0700797 private void loadInvitableAccountTypes(Result contactData) {
Makoto Onuki6ad227f2011-08-15 13:46:59 -0700798 Map<AccountTypeWithDataSet, AccountType> allInvitables =
Makoto Onuki69b4a882011-07-22 10:05:10 -0700799 AccountTypeManager.getInstance(getContext()).getInvitableAccountTypes();
800 if (allInvitables.isEmpty()) {
801 return;
802 }
803
Makoto Onuki6ad227f2011-08-15 13:46:59 -0700804 HashMap<AccountTypeWithDataSet, AccountType> result = Maps.newHashMap(allInvitables);
Makoto Onuki69b4a882011-07-22 10:05:10 -0700805
Daniel Lehmann3ef27fb2011-08-09 14:31:29 -0700806 // Remove the ones that already have a raw contact in the current contact
Makoto Onuki69b4a882011-07-22 10:05:10 -0700807 for (Entity entity : contactData.getEntities()) {
Makoto Onuki6ad227f2011-08-15 13:46:59 -0700808 final ContentValues values = entity.getEntityValues();
809 final AccountTypeWithDataSet type = AccountTypeWithDataSet.get(
810 values.getAsString(RawContacts.ACCOUNT_TYPE),
811 values.getAsString(RawContacts.DATA_SET));
812 result.remove(type);
Makoto Onuki69b4a882011-07-22 10:05:10 -0700813 }
814
815 // Set to mInvitableAccountTypes
Dave Santoro2b3f3c52011-07-26 17:35:42 -0700816 contactData.mInvitableAccountTypes.addAll(result.values());
Makoto Onuki69b4a882011-07-22 10:05:10 -0700817 }
818
Dmitri Plotnikov7f4f8d12010-11-10 10:22:19 -0800819 /**
Dmitri Plotnikov4d444242010-07-30 11:39:39 -0700820 * Extracts Contact level columns from the cursor.
821 */
822 private Result loadContactHeaderData(final Cursor cursor, Uri contactUri) {
Dmitri Plotnikov02cd4912010-09-01 20:42:17 -0700823 final String directoryParameter =
824 contactUri.getQueryParameter(ContactsContract.DIRECTORY_PARAM_KEY);
825 final long directoryId = directoryParameter == null
826 ? Directory.DEFAULT
827 : Long.parseLong(directoryParameter);
Dmitri Plotnikov4d444242010-07-30 11:39:39 -0700828 final long contactId = cursor.getLong(ContactQuery.CONTACT_ID);
829 final String lookupKey = cursor.getString(ContactQuery.LOOKUP_KEY);
830 final long nameRawContactId = cursor.getLong(ContactQuery.NAME_RAW_CONTACT_ID);
831 final int displayNameSource = cursor.getInt(ContactQuery.DISPLAY_NAME_SOURCE);
832 final String displayName = cursor.getString(ContactQuery.DISPLAY_NAME);
Dave Santoroda5bf1c2011-05-03 10:30:34 -0700833 final String altDisplayName = cursor.getString(ContactQuery.ALT_DISPLAY_NAME);
Dmitri Plotnikov4d444242010-07-30 11:39:39 -0700834 final String phoneticName = cursor.getString(ContactQuery.PHONETIC_NAME);
835 final long photoId = cursor.getLong(ContactQuery.PHOTO_ID);
Dmitri Plotnikovf9eb73f2010-10-21 11:48:56 -0700836 final String photoUri = cursor.getString(ContactQuery.PHOTO_URI);
Dmitri Plotnikov4d444242010-07-30 11:39:39 -0700837 final boolean starred = cursor.getInt(ContactQuery.STARRED) != 0;
838 final Integer presence = cursor.isNull(ContactQuery.CONTACT_PRESENCE)
839 ? null
840 : cursor.getInt(ContactQuery.CONTACT_PRESENCE);
Isaac Katzenelson683b57e2011-07-20 17:06:11 -0700841 final boolean sendToVoicemail = cursor.getInt(ContactQuery.SEND_TO_VOICEMAIL) == 1;
842 final String customRingtone = cursor.getString(ContactQuery.CUSTOM_RINGTONE);
Isaac Katzenelsonead19c52011-07-29 18:24:53 -0700843 final boolean isUserProfile = cursor.getInt(ContactQuery.IS_USER_PROFILE) == 1;
Dmitri Plotnikov4d444242010-07-30 11:39:39 -0700844
Dmitri Plotnikov1536ea12010-10-29 11:51:05 -0700845 Uri lookupUri;
846 if (directoryId == Directory.DEFAULT || directoryId == Directory.LOCAL_INVISIBLE) {
847 lookupUri = ContentUris.withAppendedId(
Dmitri Plotnikov4d444242010-07-30 11:39:39 -0700848 Uri.withAppendedPath(Contacts.CONTENT_LOOKUP_URI, lookupKey), contactId);
Dmitri Plotnikov1536ea12010-10-29 11:51:05 -0700849 } else {
850 lookupUri = contactUri;
851 }
852
Dmitri Plotnikov02cd4912010-09-01 20:42:17 -0700853 return new Result(contactUri, lookupUri, directoryId, lookupKey, contactId,
Dmitri Plotnikovf9eb73f2010-10-21 11:48:56 -0700854 nameRawContactId, displayNameSource, photoId, photoUri, displayName,
Isaac Katzenelson683b57e2011-07-20 17:06:11 -0700855 altDisplayName, phoneticName, starred, presence, sendToVoicemail,
Isaac Katzenelsonead19c52011-07-29 18:24:53 -0700856 customRingtone, isUserProfile);
Dmitri Plotnikov4d444242010-07-30 11:39:39 -0700857 }
858
859 /**
860 * Extracts RawContact level columns from the cursor.
861 */
862 private ContentValues loadRawContact(Cursor cursor) {
863 ContentValues cv = new ContentValues();
864
865 cv.put(RawContacts._ID, cursor.getLong(ContactQuery.RAW_CONTACT_ID));
866
867 cursorColumnToContentValues(cursor, cv, ContactQuery.ACCOUNT_NAME);
868 cursorColumnToContentValues(cursor, cv, ContactQuery.ACCOUNT_TYPE);
Dave Santoro2b3f3c52011-07-26 17:35:42 -0700869 cursorColumnToContentValues(cursor, cv, ContactQuery.DATA_SET);
870 cursorColumnToContentValues(cursor, cv, ContactQuery.ACCOUNT_TYPE_AND_DATA_SET);
Dmitri Plotnikov4d444242010-07-30 11:39:39 -0700871 cursorColumnToContentValues(cursor, cv, ContactQuery.DIRTY);
872 cursorColumnToContentValues(cursor, cv, ContactQuery.VERSION);
873 cursorColumnToContentValues(cursor, cv, ContactQuery.SOURCE_ID);
874 cursorColumnToContentValues(cursor, cv, ContactQuery.SYNC1);
875 cursorColumnToContentValues(cursor, cv, ContactQuery.SYNC2);
876 cursorColumnToContentValues(cursor, cv, ContactQuery.SYNC3);
877 cursorColumnToContentValues(cursor, cv, ContactQuery.SYNC4);
878 cursorColumnToContentValues(cursor, cv, ContactQuery.DELETED);
879 cursorColumnToContentValues(cursor, cv, ContactQuery.CONTACT_ID);
880 cursorColumnToContentValues(cursor, cv, ContactQuery.STARRED);
Dmitri Plotnikov4d444242010-07-30 11:39:39 -0700881 cursorColumnToContentValues(cursor, cv, ContactQuery.NAME_VERIFIED);
882
883 return cv;
884 }
885
886 /**
887 * Extracts Data level columns from the cursor.
888 */
889 private ContentValues loadData(Cursor cursor) {
890 ContentValues cv = new ContentValues();
891
892 cv.put(Data._ID, cursor.getLong(ContactQuery.DATA_ID));
893
894 cursorColumnToContentValues(cursor, cv, ContactQuery.DATA1);
895 cursorColumnToContentValues(cursor, cv, ContactQuery.DATA2);
896 cursorColumnToContentValues(cursor, cv, ContactQuery.DATA3);
897 cursorColumnToContentValues(cursor, cv, ContactQuery.DATA4);
898 cursorColumnToContentValues(cursor, cv, ContactQuery.DATA5);
899 cursorColumnToContentValues(cursor, cv, ContactQuery.DATA6);
900 cursorColumnToContentValues(cursor, cv, ContactQuery.DATA7);
901 cursorColumnToContentValues(cursor, cv, ContactQuery.DATA8);
902 cursorColumnToContentValues(cursor, cv, ContactQuery.DATA9);
903 cursorColumnToContentValues(cursor, cv, ContactQuery.DATA10);
904 cursorColumnToContentValues(cursor, cv, ContactQuery.DATA11);
905 cursorColumnToContentValues(cursor, cv, ContactQuery.DATA12);
906 cursorColumnToContentValues(cursor, cv, ContactQuery.DATA13);
907 cursorColumnToContentValues(cursor, cv, ContactQuery.DATA14);
908 cursorColumnToContentValues(cursor, cv, ContactQuery.DATA15);
909 cursorColumnToContentValues(cursor, cv, ContactQuery.DATA_SYNC1);
910 cursorColumnToContentValues(cursor, cv, ContactQuery.DATA_SYNC2);
911 cursorColumnToContentValues(cursor, cv, ContactQuery.DATA_SYNC3);
912 cursorColumnToContentValues(cursor, cv, ContactQuery.DATA_SYNC4);
913 cursorColumnToContentValues(cursor, cv, ContactQuery.DATA_VERSION);
914 cursorColumnToContentValues(cursor, cv, ContactQuery.IS_PRIMARY);
915 cursorColumnToContentValues(cursor, cv, ContactQuery.IS_SUPERPRIMARY);
916 cursorColumnToContentValues(cursor, cv, ContactQuery.MIMETYPE);
917 cursorColumnToContentValues(cursor, cv, ContactQuery.RES_PACKAGE);
918 cursorColumnToContentValues(cursor, cv, ContactQuery.GROUP_SOURCE_ID);
Daniel Lehmann8fd7bb62010-08-13 20:50:31 -0700919 cursorColumnToContentValues(cursor, cv, ContactQuery.CHAT_CAPABILITY);
Dmitri Plotnikov4d444242010-07-30 11:39:39 -0700920
921 return cv;
922 }
923
924 private void cursorColumnToContentValues(
925 Cursor cursor, ContentValues values, int index) {
926 switch (cursor.getType(index)) {
927 case Cursor.FIELD_TYPE_NULL:
928 // don't put anything in the content values
929 break;
930 case Cursor.FIELD_TYPE_INTEGER:
931 values.put(ContactQuery.COLUMNS[index], cursor.getLong(index));
932 break;
933 case Cursor.FIELD_TYPE_STRING:
934 values.put(ContactQuery.COLUMNS[index], cursor.getString(index));
935 break;
936 case Cursor.FIELD_TYPE_BLOB:
937 values.put(ContactQuery.COLUMNS[index], cursor.getBlob(index));
938 break;
939 default:
940 throw new IllegalStateException("Invalid or unhandled data type");
941 }
942 }
943
Dmitri Plotnikov02cd4912010-09-01 20:42:17 -0700944 private void loadDirectoryMetaData(Result result) {
945 long directoryId = result.getDirectoryId();
946
947 Cursor cursor = getContext().getContentResolver().query(
948 ContentUris.withAppendedId(Directory.CONTENT_URI, directoryId),
949 DirectoryQuery.COLUMNS, null, null, null);
950 if (cursor == null) {
951 return;
952 }
953 try {
954 if (cursor.moveToFirst()) {
955 final String displayName = cursor.getString(DirectoryQuery.DISPLAY_NAME);
956 final String packageName = cursor.getString(DirectoryQuery.PACKAGE_NAME);
957 final int typeResourceId = cursor.getInt(DirectoryQuery.TYPE_RESOURCE_ID);
Dmitri Plotnikovcaf0bc72010-09-03 15:16:21 -0700958 final String accountType = cursor.getString(DirectoryQuery.ACCOUNT_TYPE);
Dmitri Plotnikov02cd4912010-09-01 20:42:17 -0700959 final String accountName = cursor.getString(DirectoryQuery.ACCOUNT_NAME);
960 final int exportSupport = cursor.getInt(DirectoryQuery.EXPORT_SUPPORT);
961 String directoryType = null;
962 if (!TextUtils.isEmpty(packageName)) {
963 PackageManager pm = getContext().getPackageManager();
964 try {
965 Resources resources = pm.getResourcesForApplication(packageName);
966 directoryType = resources.getString(typeResourceId);
967 } catch (NameNotFoundException e) {
968 Log.w(TAG, "Contact directory resource not found: "
969 + packageName + "." + typeResourceId);
970 }
971 }
972
973 result.setDirectoryMetaData(
Dmitri Plotnikovcaf0bc72010-09-03 15:16:21 -0700974 displayName, directoryType, accountType, accountName, exportSupport);
Dmitri Plotnikov02cd4912010-09-01 20:42:17 -0700975 }
976 } finally {
977 cursor.close();
978 }
979 }
980
Dmitri Plotnikov2deaee12010-09-15 15:42:08 -0700981 /**
982 * Loads groups meta-data for all groups associated with all constituent raw contacts'
983 * accounts.
984 */
985 private void loadGroupMetaData(Result result) {
986 StringBuilder selection = new StringBuilder();
987 ArrayList<String> selectionArgs = new ArrayList<String>();
988 for (Entity entity : result.mEntities) {
989 ContentValues values = entity.getEntityValues();
990 String accountName = values.getAsString(RawContacts.ACCOUNT_NAME);
991 String accountType = values.getAsString(RawContacts.ACCOUNT_TYPE);
Dave Santoro2b3f3c52011-07-26 17:35:42 -0700992 String dataSet = values.getAsString(RawContacts.DATA_SET);
Dmitri Plotnikov2deaee12010-09-15 15:42:08 -0700993 if (accountName != null && accountType != null) {
994 if (selection.length() != 0) {
995 selection.append(" OR ");
996 }
997 selection.append(
Dave Santoro2b3f3c52011-07-26 17:35:42 -0700998 "(" + Groups.ACCOUNT_NAME + "=? AND " + Groups.ACCOUNT_TYPE + "=?");
Dmitri Plotnikov2deaee12010-09-15 15:42:08 -0700999 selectionArgs.add(accountName);
1000 selectionArgs.add(accountType);
Dave Santoro2b3f3c52011-07-26 17:35:42 -07001001
1002 if (dataSet != null) {
1003 selection.append(" AND " + Groups.DATA_SET + "=?");
1004 selectionArgs.add(dataSet);
1005 } else {
1006 selection.append(" AND " + Groups.DATA_SET + " IS NULL");
1007 }
1008 selection.append(")");
Dmitri Plotnikov2deaee12010-09-15 15:42:08 -07001009 }
1010 }
1011 Cursor cursor = getContext().getContentResolver().query(Groups.CONTENT_URI,
1012 GroupQuery.COLUMNS, selection.toString(), selectionArgs.toArray(new String[0]),
1013 null);
1014 try {
1015 while (cursor.moveToNext()) {
1016 final String accountName = cursor.getString(GroupQuery.ACCOUNT_NAME);
1017 final String accountType = cursor.getString(GroupQuery.ACCOUNT_TYPE);
Dave Santoro2b3f3c52011-07-26 17:35:42 -07001018 final String dataSet = cursor.getString(GroupQuery.DATA_SET);
Dmitri Plotnikov2deaee12010-09-15 15:42:08 -07001019 final long groupId = cursor.getLong(GroupQuery.ID);
1020 final String title = cursor.getString(GroupQuery.TITLE);
1021 final boolean defaultGroup = cursor.isNull(GroupQuery.AUTO_ADD)
1022 ? false
1023 : cursor.getInt(GroupQuery.AUTO_ADD) != 0;
1024 final boolean favorites = cursor.isNull(GroupQuery.FAVORITES)
1025 ? false
1026 : cursor.getInt(GroupQuery.FAVORITES) != 0;
1027
Dmitri Plotnikove843f912010-09-16 15:21:48 -07001028 result.addGroupMetaData(new GroupMetaData(
Dave Santoro2b3f3c52011-07-26 17:35:42 -07001029 accountName, accountType, dataSet, groupId, title, defaultGroup,
1030 favorites));
Dmitri Plotnikov2deaee12010-09-15 15:42:08 -07001031 }
1032 } finally {
1033 cursor.close();
1034 }
1035 }
1036
Dave Santoro39156002011-07-19 01:18:14 -07001037 /**
1038 * Loads all stream items and stream item photos belonging to this contact.
1039 */
1040 private void loadStreamItems(Result result) {
1041 Cursor cursor = getContext().getContentResolver().query(
1042 Contacts.CONTENT_LOOKUP_URI.buildUpon()
1043 .appendPath(result.getLookupKey())
1044 .appendPath(Contacts.StreamItems.CONTENT_DIRECTORY).build(),
1045 null, null, null, null);
1046 Map<Long, StreamItemEntry> streamItemsById = new HashMap<Long, StreamItemEntry>();
1047 ArrayList<StreamItemEntry> streamItems = new ArrayList<StreamItemEntry>();
1048 try {
1049 while (cursor.moveToNext()) {
1050 StreamItemEntry streamItem = new StreamItemEntry(cursor);
1051 streamItemsById.put(streamItem.getId(), streamItem);
1052 streamItems.add(streamItem);
1053 }
1054 } finally {
1055 cursor.close();
1056 }
1057
1058 // Now retrieve any photo records associated with the stream items.
1059 String[] streamItemIdArr = new String[streamItems.size()];
1060 StringBuilder streamItemPhotoSelection = new StringBuilder();
1061 if (!streamItems.isEmpty()) {
1062 streamItemPhotoSelection.append(StreamItemPhotos.STREAM_ITEM_ID + " IN (");
1063 for (int i = 0; i < streamItems.size(); i++) {
1064 if (i > 0) {
1065 streamItemPhotoSelection.append(",");
1066 }
1067 streamItemPhotoSelection.append("?");
1068 streamItemIdArr[i] = String.valueOf(streamItems.get(i).getId());
1069 }
1070 streamItemPhotoSelection.append(")");
1071 cursor = getContext().getContentResolver().query(StreamItems.CONTENT_PHOTO_URI,
1072 null, streamItemPhotoSelection.toString(), streamItemIdArr,
1073 StreamItemPhotos.STREAM_ITEM_ID);
1074 try {
1075 while (cursor.moveToNext()) {
1076 long streamItemId = cursor.getLong(
1077 cursor.getColumnIndex(StreamItemPhotos.STREAM_ITEM_ID));
1078 StreamItemEntry streamItem = streamItemsById.get(streamItemId);
1079 streamItem.addPhoto(new StreamItemPhotoEntry(cursor));
1080 }
1081 } finally {
1082 cursor.close();
1083 }
1084 }
1085
1086 // Set the sorted stream items on the result.
1087 Collections.sort(streamItems);
1088 result.mStreamItems.addAll(streamItems);
1089 }
1090
Daniel Lehmann4cd94412010-04-08 16:44:36 -07001091 @Override
1092 protected void onPostExecute(Result result) {
Dmitri Plotnikovc3f2a522010-11-17 18:36:17 -08001093 unregisterObserver();
1094
Daniel Lehmann1316b132010-04-13 15:08:53 -07001095 // The creator isn't interested in any further updates
Dmitri Plotnikovc3f2a522010-11-17 18:36:17 -08001096 if (mDestroyed || result == null) {
Daniel Lehmann4cd94412010-04-08 16:44:36 -07001097 return;
1098 }
1099
1100 mContact = result;
Daniel Lehmann18f104f2010-05-07 15:41:11 -07001101
Makoto Onuki9e7b5da2011-08-22 15:51:28 -07001102 if (!result.isError() && result != Result.NOT_FOUND) {
Dmitri Plotnikovc3f2a522010-11-17 18:36:17 -08001103 mLookupUri = result.getLookupUri();
1104
1105 if (!result.isDirectoryEntry()) {
1106 Log.i(TAG, "Registering content observer for " + mLookupUri);
1107 if (mObserver == null) {
1108 mObserver = new ForceLoadContentObserver();
1109 }
1110 getContext().getContentResolver().registerContentObserver(
1111 mLookupUri, true, mObserver);
Daniel Lehmann18f104f2010-05-07 15:41:11 -07001112 }
Dmitri Plotnikov7f4f8d12010-11-10 10:22:19 -08001113
1114 if (mContact.getPhotoBinaryData() == null && mContact.getPhotoUri() != null) {
1115 mContact.setLoadingPhoto(true);
1116 new AsyncPhotoLoader().execute(mContact.getPhotoUri());
1117 }
Daniel Lehmann3ef27fb2011-08-09 14:31:29 -07001118
1119 // inform the source of the data that this contact is being looked at
1120 postViewNotificationToSyncAdapter();
Daniel Lehmann4cd94412010-04-08 16:44:36 -07001121 }
Dmitri Plotnikovc3f2a522010-11-17 18:36:17 -08001122
1123 deliverResult(mContact);
Daniel Lehmann4cd94412010-04-08 16:44:36 -07001124 }
1125 }
1126
Daniel Lehmann3ef27fb2011-08-09 14:31:29 -07001127 /**
1128 * Posts a message to the contributing sync adapters that have opted-in, notifying them
1129 * that the contact has just been loaded
1130 */
1131 private void postViewNotificationToSyncAdapter() {
1132 Context context = getContext();
1133 for (Entity entity : mContact.getEntities()) {
1134 final ContentValues entityValues = entity.getEntityValues();
Makoto Onukiaba2b832011-08-12 15:44:53 -07001135 final long rawContactId = entityValues.getAsLong(RawContacts.Entity._ID);
1136 if (mNotifiedRawContactIds.contains(rawContactId)) {
1137 continue; // Already notified for this raw contact.
1138 }
1139 mNotifiedRawContactIds.add(rawContactId);
Daniel Lehmann3ef27fb2011-08-09 14:31:29 -07001140 final String type = entityValues.getAsString(RawContacts.ACCOUNT_TYPE);
1141 final String dataSet = entityValues.getAsString(RawContacts.DATA_SET);
Flavio Lerda59a887e2011-08-14 18:13:17 +01001142 final AccountType accountType = AccountTypeManager.getInstance(context).getAccountType(
Daniel Lehmann3ef27fb2011-08-09 14:31:29 -07001143 type, dataSet);
1144 final String serviceName = accountType.getViewContactNotifyServiceClassName();
1145 final String resPackageName = accountType.resPackageName;
1146 if (!TextUtils.isEmpty(serviceName) && !TextUtils.isEmpty(resPackageName)) {
Daniel Lehmann3ef27fb2011-08-09 14:31:29 -07001147 final Uri uri = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId);
1148 final Intent intent = new Intent();
1149 intent.setClassName(resPackageName, serviceName);
1150 intent.setAction(Intent.ACTION_VIEW);
1151 intent.setDataAndType(uri, RawContacts.CONTENT_ITEM_TYPE);
1152 try {
1153 context.startService(intent);
1154 } catch (Exception e) {
1155 Log.e(TAG, "Error sending message to source-app", e);
1156 }
1157 }
1158 }
1159 }
1160
Dmitri Plotnikov7f4f8d12010-11-10 10:22:19 -08001161 private class AsyncPhotoLoader extends AsyncTask<String, Void, byte[]> {
1162
1163 private static final int BUFFER_SIZE = 1024*16;
1164
1165 @Override
1166 protected byte[] doInBackground(String... params) {
1167 Uri uri = Uri.parse(params[0]);
1168 byte[] data = null;
1169 try {
1170 InputStream is = getContext().getContentResolver().openInputStream(uri);
1171 if (is != null) {
1172 ByteArrayOutputStream baos = new ByteArrayOutputStream();
1173 try {
1174 byte[] mBuffer = new byte[BUFFER_SIZE];
1175
1176 int size;
1177 while ((size = is.read(mBuffer)) != -1) {
1178 baos.write(mBuffer, 0, size);
1179 }
1180 data = baos.toByteArray();
1181 } finally {
1182 is.close();
1183 }
1184 } else {
1185 Log.v(TAG, "Cannot load photo " + uri);
1186 }
1187 } catch (IOException e) {
1188 Log.e(TAG, "Cannot load photo " + uri, e);
1189 }
1190
1191 return data;
1192 }
1193
1194 @Override
1195 protected void onPostExecute(byte[] data) {
Dmitri Plotnikovc3f2a522010-11-17 18:36:17 -08001196 if (mContact != null) {
Dmitri Plotnikov7cee7742011-01-13 17:11:06 -08001197 mContact = new Result(mContact);
Dmitri Plotnikovc3f2a522010-11-17 18:36:17 -08001198 mContact.setPhotoBinaryData(data);
1199 mContact.setLoadingPhoto(false);
1200 deliverResult(mContact);
1201 }
Dmitri Plotnikov7f4f8d12010-11-10 10:22:19 -08001202 }
1203 }
1204
Daniel Lehmann3a120772010-06-21 16:21:35 -07001205 private void unregisterObserver() {
1206 if (mObserver != null) {
1207 getContext().getContentResolver().unregisterContentObserver(mObserver);
1208 mObserver = null;
1209 }
1210 }
1211
Daniel Lehmanncdef2b62010-06-06 18:25:49 -07001212 public ContactLoader(Context context, Uri lookupUri) {
Makoto Onuki69b4a882011-07-22 10:05:10 -07001213 this(context, lookupUri, false, false, false);
Dmitri Plotnikove843f912010-09-16 15:21:48 -07001214 }
1215
Dave Santoro39156002011-07-19 01:18:14 -07001216 public ContactLoader(Context context, Uri lookupUri, boolean loadGroupMetaData,
Makoto Onuki69b4a882011-07-22 10:05:10 -07001217 boolean loadStreamItems, boolean loadInvitableAccountTypes) {
Daniel Lehmann74a2dc52010-04-15 16:52:33 -07001218 super(context);
Daniel Lehmann4cd94412010-04-08 16:44:36 -07001219 mLookupUri = lookupUri;
Dmitri Plotnikove843f912010-09-16 15:21:48 -07001220 mLoadGroupMetaData = loadGroupMetaData;
Dave Santoro39156002011-07-19 01:18:14 -07001221 mLoadStreamItems = loadStreamItems;
Makoto Onuki69b4a882011-07-22 10:05:10 -07001222 mLoadInvitableAccountTypes = loadInvitableAccountTypes;
Daniel Lehmann4cd94412010-04-08 16:44:36 -07001223 }
1224
Dmitri Plotnikov5a30d9a2010-11-23 14:59:50 -08001225 public Uri getLookupUri() {
1226 return mLookupUri;
1227 }
1228
Daniel Lehmann4cd94412010-04-08 16:44:36 -07001229 @Override
Dianne Hackbornc04fc272010-12-20 23:13:10 -08001230 protected void onStartLoading() {
Daniel Lehmann4cd94412010-04-08 16:44:36 -07001231 if (mContact != null) {
Daniel Lehmanncbcc4492010-04-12 18:03:54 -07001232 deliverResult(mContact);
Dmitri Plotnikov97e90c62011-01-03 11:58:13 -08001233 }
1234
1235 if (takeContentChanged() || mContact == null) {
Daniel Lehmann4cd94412010-04-08 16:44:36 -07001236 forceLoad();
1237 }
1238 }
1239
1240 @Override
Dianne Hackbornc04fc272010-12-20 23:13:10 -08001241 protected void onForceLoad() {
Daniel Lehmann18f104f2010-05-07 15:41:11 -07001242 final LoadContactTask task = new LoadContactTask();
Daniel Lehmann74a2dc52010-04-15 16:52:33 -07001243 task.execute((Void[])null);
Daniel Lehmann4cd94412010-04-08 16:44:36 -07001244 }
1245
1246 @Override
Dianne Hackbornc04fc272010-12-20 23:13:10 -08001247 protected void onReset() {
Dianne Hackborn4ef95cc2010-12-16 00:44:33 -08001248 unregisterObserver();
1249 mContact = null;
1250 mDestroyed = true;
1251 }
Daniel Lehmann4cd94412010-04-08 16:44:36 -07001252}