Refactoring: Changed ContactLoader to be an AsyncTaskLoader
Change-Id: Iaa587907b2933aa084974e181f24121bc57b4cfb
diff --git a/src/com/android/contacts/ContactLoader.java b/src/com/android/contacts/ContactLoader.java
index 685bd7d..e85f5f5 100644
--- a/src/com/android/contacts/ContactLoader.java
+++ b/src/com/android/contacts/ContactLoader.java
@@ -28,6 +28,7 @@
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
+import android.content.AsyncTaskLoader;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.ContentValues;
@@ -35,14 +36,12 @@
import android.content.Entity;
import android.content.Entity.NamedContentValues;
import android.content.Intent;
-import android.content.Loader;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.AssetFileDescriptor;
import android.content.res.Resources;
import android.database.Cursor;
import android.net.Uri;
-import android.os.AsyncTask;
import android.provider.ContactsContract;
import android.provider.ContactsContract.CommonDataKinds.GroupMembership;
import android.provider.ContactsContract.CommonDataKinds.Photo;
@@ -70,7 +69,7 @@
/**
* Loads a single Contact and all it constituent RawContacts.
*/
-public class ContactLoader extends Loader<ContactLoader.Result> {
+public class ContactLoader extends AsyncTaskLoader<ContactLoader.Result> {
private static final String TAG = "ContactLoader";
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
@@ -82,13 +81,26 @@
private final boolean mLoadInvitableAccountTypes;
private Result mContact;
private ForceLoadContentObserver mObserver;
- private boolean mDestroyed;
private final Set<Long> mNotifiedRawContactIds = Sets.newHashSet();
public interface Listener {
public void onContactLoaded(Result contact);
}
+ public ContactLoader(Context context, Uri lookupUri) {
+ this(context, lookupUri, false, false, false);
+ }
+
+ public ContactLoader(Context context, Uri lookupUri, boolean loadGroupMetaData,
+ boolean loadStreamItems, boolean loadInvitableAccountTypes) {
+ super(context);
+ mLookupUri = lookupUri;
+ mRequestedUri = lookupUri;
+ mLoadGroupMetaData = loadGroupMetaData;
+ mLoadStreamItems = loadStreamItems;
+ mLoadInvitableAccountTypes = loadInvitableAccountTypes;
+ }
+
/**
* The result of a load operation. Contains all data necessary to display the contact.
*/
@@ -670,498 +682,495 @@
public final static int FAVORITES = 7;
}
- private final class LoadContactTask extends AsyncTask<Void, Void, Result> {
-
- @Override
- protected Result doInBackground(Void... args) {
- try {
- final ContentResolver resolver = getContext().getContentResolver();
- final Uri uriCurrentFormat = ContactLoaderUtils.ensureIsContactUri(
- resolver, mLookupUri);
- Result result = loadContactEntity(resolver, uriCurrentFormat);
- if (!result.isNotFound()) {
- if (result.isDirectoryEntry()) {
- loadDirectoryMetaData(result);
- } else if (mLoadGroupMetaData) {
- loadGroupMetaData(result);
- }
- if (mLoadStreamItems) {
- loadStreamItems(result);
- }
- loadPhotoBinaryData(result);
-
- // Note ME profile should never have "Add connection"
- if (mLoadInvitableAccountTypes && !result.isUserProfile()) {
- loadInvitableAccountTypes(result);
- }
+ @Override
+ public Result loadInBackground() {
+ try {
+ final ContentResolver resolver = getContext().getContentResolver();
+ final Uri uriCurrentFormat = ContactLoaderUtils.ensureIsContactUri(
+ resolver, mLookupUri);
+ Result result = loadContactEntity(resolver, uriCurrentFormat);
+ if (!result.isNotFound()) {
+ if (result.isDirectoryEntry()) {
+ loadDirectoryMetaData(result);
+ } else if (mLoadGroupMetaData) {
+ loadGroupMetaData(result);
}
- return result;
- } catch (Exception e) {
- Log.e(TAG, "Error loading the contact: " + mLookupUri, e);
- return Result.forError(mRequestedUri, e);
+ if (mLoadStreamItems) {
+ loadStreamItems(result);
+ }
+ loadPhotoBinaryData(result);
+
+ // Note ME profile should never have "Add connection"
+ if (mLoadInvitableAccountTypes && !result.isUserProfile()) {
+ loadInvitableAccountTypes(result);
+ }
}
+ return result;
+ } catch (Exception e) {
+ Log.e(TAG, "Error loading the contact: " + mLookupUri, e);
+ return Result.forError(mRequestedUri, e);
+ }
+ }
+
+ private Result loadContactEntity(ContentResolver resolver, Uri contactUri) {
+ Uri entityUri = Uri.withAppendedPath(contactUri, Contacts.Entity.CONTENT_DIRECTORY);
+ Cursor cursor = resolver.query(entityUri, ContactQuery.COLUMNS, null, null,
+ Contacts.Entity.RAW_CONTACT_ID);
+ if (cursor == null) {
+ Log.e(TAG, "No cursor returned in loadContactEntity");
+ return Result.forNotFound(mRequestedUri);
}
- private Result loadContactEntity(ContentResolver resolver, Uri contactUri) {
- Uri entityUri = Uri.withAppendedPath(contactUri, Contacts.Entity.CONTENT_DIRECTORY);
- Cursor cursor = resolver.query(entityUri, ContactQuery.COLUMNS, null, null,
- Contacts.Entity.RAW_CONTACT_ID);
- if (cursor == null) {
- Log.e(TAG, "No cursor returned in loadContactEntity");
+ try {
+ if (!cursor.moveToFirst()) {
+ cursor.close();
return Result.forNotFound(mRequestedUri);
}
- try {
- if (!cursor.moveToFirst()) {
- cursor.close();
- return Result.forNotFound(mRequestedUri);
+ long currentRawContactId = -1;
+ Entity entity = null;
+ Result result = loadContactHeaderData(cursor, contactUri);
+ ArrayList<Entity> entities = result.getEntities();
+ LongSparseArray<DataStatus> statuses = result.getStatuses();
+ for (; !cursor.isAfterLast(); cursor.moveToNext()) {
+ long rawContactId = cursor.getLong(ContactQuery.RAW_CONTACT_ID);
+ if (rawContactId != currentRawContactId) {
+ currentRawContactId = rawContactId;
+ entity = new android.content.Entity(loadRawContact(cursor));
+ entities.add(entity);
}
+ if (!cursor.isNull(ContactQuery.DATA_ID)) {
+ ContentValues data = loadData(cursor);
+ entity.addSubValue(ContactsContract.Data.CONTENT_URI, data);
- long currentRawContactId = -1;
- Entity entity = null;
- Result result = loadContactHeaderData(cursor, contactUri);
- ArrayList<Entity> entities = result.getEntities();
- LongSparseArray<DataStatus> statuses = result.getStatuses();
- for (; !cursor.isAfterLast(); cursor.moveToNext()) {
- long rawContactId = cursor.getLong(ContactQuery.RAW_CONTACT_ID);
- if (rawContactId != currentRawContactId) {
- currentRawContactId = rawContactId;
- entity = new android.content.Entity(loadRawContact(cursor));
- entities.add(entity);
- }
- if (!cursor.isNull(ContactQuery.DATA_ID)) {
- ContentValues data = loadData(cursor);
- entity.addSubValue(ContactsContract.Data.CONTENT_URI, data);
-
- if (!cursor.isNull(ContactQuery.PRESENCE)
- || !cursor.isNull(ContactQuery.STATUS)) {
- final DataStatus status = new DataStatus(cursor);
- final long dataId = cursor.getLong(ContactQuery.DATA_ID);
- statuses.put(dataId, status);
- }
+ if (!cursor.isNull(ContactQuery.PRESENCE)
+ || !cursor.isNull(ContactQuery.STATUS)) {
+ final DataStatus status = new DataStatus(cursor);
+ final long dataId = cursor.getLong(ContactQuery.DATA_ID);
+ statuses.put(dataId, status);
}
}
-
- return result;
- } finally {
- cursor.close();
}
+
+ return result;
+ } finally {
+ cursor.close();
}
+ }
- /**
- * Looks for the photo data item in entities. If found, creates a new Bitmap instance. If
- * not found, returns null
- */
- private void loadPhotoBinaryData(Result contactData) {
+ /**
+ * Looks for the photo data item in entities. If found, creates a new Bitmap instance. If
+ * not found, returns null
+ */
+ private void loadPhotoBinaryData(Result contactData) {
- // If we have a photo URI, try loading that first.
- String photoUri = contactData.getPhotoUri();
- if (photoUri != null) {
+ // If we have a photo URI, try loading that first.
+ String photoUri = contactData.getPhotoUri();
+ if (photoUri != null) {
+ try {
+ AssetFileDescriptor fd = getContext().getContentResolver()
+ .openAssetFileDescriptor(Uri.parse(photoUri), "r");
+ byte[] buffer = new byte[16 * 1024];
+ FileInputStream fis = fd.createInputStream();
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
try {
- AssetFileDescriptor fd = getContext().getContentResolver()
- .openAssetFileDescriptor(Uri.parse(photoUri), "r");
- byte[] buffer = new byte[16 * 1024];
- FileInputStream fis = fd.createInputStream();
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ int size;
+ while ((size = fis.read(buffer)) != -1) {
+ baos.write(buffer, 0, size);
+ }
+ contactData.setPhotoBinaryData(baos.toByteArray());
+ } finally {
+ fis.close();
+ fd.close();
+ }
+ return;
+ } catch (IOException ioe) {
+ // Just fall back to the case below.
+ }
+ }
+
+ // If we couldn't load from a file, fall back to the data blob.
+ final long photoId = contactData.getPhotoId();
+ if (photoId <= 0) {
+ // No photo ID
+ return;
+ }
+
+ for (Entity entity : contactData.getEntities()) {
+ for (NamedContentValues subValue : entity.getSubValues()) {
+ final ContentValues entryValues = subValue.values;
+ final long dataId = entryValues.getAsLong(Data._ID);
+ if (dataId == photoId) {
+ final String mimeType = entryValues.getAsString(Data.MIMETYPE);
+ // Correct Data Id but incorrect MimeType? Don't load
+ if (!Photo.CONTENT_ITEM_TYPE.equals(mimeType)) {
+ return;
+ }
+ contactData.setPhotoBinaryData(entryValues.getAsByteArray(Photo.PHOTO));
+ break;
+ }
+ }
+ }
+ }
+
+ /**
+ * Sets the "invitable" account types to {@link Result#mInvitableAccountTypes}.
+ */
+ private void loadInvitableAccountTypes(Result contactData) {
+ Map<AccountTypeWithDataSet, AccountType> invitables =
+ AccountTypeManager.getInstance(getContext()).getUsableInvitableAccountTypes();
+ if (invitables.isEmpty()) {
+ return;
+ }
+
+ Map<AccountTypeWithDataSet, AccountType> result = Maps.newHashMap(invitables);
+
+ // Remove the ones that already have a raw contact in the current contact
+ for (Entity entity : contactData.getEntities()) {
+ final ContentValues values = entity.getEntityValues();
+ final AccountTypeWithDataSet type = AccountTypeWithDataSet.get(
+ values.getAsString(RawContacts.ACCOUNT_TYPE),
+ values.getAsString(RawContacts.DATA_SET));
+ result.remove(type);
+ }
+
+ // Set to mInvitableAccountTypes
+ contactData.mInvitableAccountTypes.addAll(result.values());
+ }
+
+ /**
+ * Extracts Contact level columns from the cursor.
+ */
+ private Result loadContactHeaderData(final Cursor cursor, Uri contactUri) {
+ final String directoryParameter =
+ contactUri.getQueryParameter(ContactsContract.DIRECTORY_PARAM_KEY);
+ final long directoryId = directoryParameter == null
+ ? Directory.DEFAULT
+ : Long.parseLong(directoryParameter);
+ final long contactId = cursor.getLong(ContactQuery.CONTACT_ID);
+ final String lookupKey = cursor.getString(ContactQuery.LOOKUP_KEY);
+ final long nameRawContactId = cursor.getLong(ContactQuery.NAME_RAW_CONTACT_ID);
+ final int displayNameSource = cursor.getInt(ContactQuery.DISPLAY_NAME_SOURCE);
+ final String displayName = cursor.getString(ContactQuery.DISPLAY_NAME);
+ final String altDisplayName = cursor.getString(ContactQuery.ALT_DISPLAY_NAME);
+ final String phoneticName = cursor.getString(ContactQuery.PHONETIC_NAME);
+ final long photoId = cursor.getLong(ContactQuery.PHOTO_ID);
+ final String photoUri = cursor.getString(ContactQuery.PHOTO_URI);
+ final boolean starred = cursor.getInt(ContactQuery.STARRED) != 0;
+ final Integer presence = cursor.isNull(ContactQuery.CONTACT_PRESENCE)
+ ? null
+ : cursor.getInt(ContactQuery.CONTACT_PRESENCE);
+ final boolean sendToVoicemail = cursor.getInt(ContactQuery.SEND_TO_VOICEMAIL) == 1;
+ final String customRingtone = cursor.getString(ContactQuery.CUSTOM_RINGTONE);
+ final boolean isUserProfile = cursor.getInt(ContactQuery.IS_USER_PROFILE) == 1;
+
+ Uri lookupUri;
+ if (directoryId == Directory.DEFAULT || directoryId == Directory.LOCAL_INVISIBLE) {
+ lookupUri = ContentUris.withAppendedId(
+ Uri.withAppendedPath(Contacts.CONTENT_LOOKUP_URI, lookupKey), contactId);
+ } else {
+ lookupUri = contactUri;
+ }
+
+ return new Result(mRequestedUri, contactUri, lookupUri, directoryId, lookupKey,
+ contactId, nameRawContactId, displayNameSource, photoId, photoUri, displayName,
+ altDisplayName, phoneticName, starred, presence, sendToVoicemail,
+ customRingtone, isUserProfile);
+ }
+
+ /**
+ * Extracts RawContact level columns from the cursor.
+ */
+ private ContentValues loadRawContact(Cursor cursor) {
+ ContentValues cv = new ContentValues();
+
+ cv.put(RawContacts._ID, cursor.getLong(ContactQuery.RAW_CONTACT_ID));
+
+ cursorColumnToContentValues(cursor, cv, ContactQuery.ACCOUNT_NAME);
+ cursorColumnToContentValues(cursor, cv, ContactQuery.ACCOUNT_TYPE);
+ cursorColumnToContentValues(cursor, cv, ContactQuery.DATA_SET);
+ cursorColumnToContentValues(cursor, cv, ContactQuery.ACCOUNT_TYPE_AND_DATA_SET);
+ cursorColumnToContentValues(cursor, cv, ContactQuery.DIRTY);
+ cursorColumnToContentValues(cursor, cv, ContactQuery.VERSION);
+ cursorColumnToContentValues(cursor, cv, ContactQuery.SOURCE_ID);
+ cursorColumnToContentValues(cursor, cv, ContactQuery.SYNC1);
+ cursorColumnToContentValues(cursor, cv, ContactQuery.SYNC2);
+ cursorColumnToContentValues(cursor, cv, ContactQuery.SYNC3);
+ cursorColumnToContentValues(cursor, cv, ContactQuery.SYNC4);
+ cursorColumnToContentValues(cursor, cv, ContactQuery.DELETED);
+ cursorColumnToContentValues(cursor, cv, ContactQuery.CONTACT_ID);
+ cursorColumnToContentValues(cursor, cv, ContactQuery.STARRED);
+ cursorColumnToContentValues(cursor, cv, ContactQuery.NAME_VERIFIED);
+
+ return cv;
+ }
+
+ /**
+ * Extracts Data level columns from the cursor.
+ */
+ private ContentValues loadData(Cursor cursor) {
+ ContentValues cv = new ContentValues();
+
+ cv.put(Data._ID, cursor.getLong(ContactQuery.DATA_ID));
+
+ cursorColumnToContentValues(cursor, cv, ContactQuery.DATA1);
+ cursorColumnToContentValues(cursor, cv, ContactQuery.DATA2);
+ cursorColumnToContentValues(cursor, cv, ContactQuery.DATA3);
+ cursorColumnToContentValues(cursor, cv, ContactQuery.DATA4);
+ cursorColumnToContentValues(cursor, cv, ContactQuery.DATA5);
+ cursorColumnToContentValues(cursor, cv, ContactQuery.DATA6);
+ cursorColumnToContentValues(cursor, cv, ContactQuery.DATA7);
+ cursorColumnToContentValues(cursor, cv, ContactQuery.DATA8);
+ cursorColumnToContentValues(cursor, cv, ContactQuery.DATA9);
+ cursorColumnToContentValues(cursor, cv, ContactQuery.DATA10);
+ cursorColumnToContentValues(cursor, cv, ContactQuery.DATA11);
+ cursorColumnToContentValues(cursor, cv, ContactQuery.DATA12);
+ cursorColumnToContentValues(cursor, cv, ContactQuery.DATA13);
+ cursorColumnToContentValues(cursor, cv, ContactQuery.DATA14);
+ cursorColumnToContentValues(cursor, cv, ContactQuery.DATA15);
+ cursorColumnToContentValues(cursor, cv, ContactQuery.DATA_SYNC1);
+ cursorColumnToContentValues(cursor, cv, ContactQuery.DATA_SYNC2);
+ cursorColumnToContentValues(cursor, cv, ContactQuery.DATA_SYNC3);
+ cursorColumnToContentValues(cursor, cv, ContactQuery.DATA_SYNC4);
+ cursorColumnToContentValues(cursor, cv, ContactQuery.DATA_VERSION);
+ cursorColumnToContentValues(cursor, cv, ContactQuery.IS_PRIMARY);
+ cursorColumnToContentValues(cursor, cv, ContactQuery.IS_SUPERPRIMARY);
+ cursorColumnToContentValues(cursor, cv, ContactQuery.MIMETYPE);
+ cursorColumnToContentValues(cursor, cv, ContactQuery.RES_PACKAGE);
+ cursorColumnToContentValues(cursor, cv, ContactQuery.GROUP_SOURCE_ID);
+ cursorColumnToContentValues(cursor, cv, ContactQuery.CHAT_CAPABILITY);
+
+ return cv;
+ }
+
+ private void cursorColumnToContentValues(
+ Cursor cursor, ContentValues values, int index) {
+ switch (cursor.getType(index)) {
+ case Cursor.FIELD_TYPE_NULL:
+ // don't put anything in the content values
+ break;
+ case Cursor.FIELD_TYPE_INTEGER:
+ values.put(ContactQuery.COLUMNS[index], cursor.getLong(index));
+ break;
+ case Cursor.FIELD_TYPE_STRING:
+ values.put(ContactQuery.COLUMNS[index], cursor.getString(index));
+ break;
+ case Cursor.FIELD_TYPE_BLOB:
+ values.put(ContactQuery.COLUMNS[index], cursor.getBlob(index));
+ break;
+ default:
+ throw new IllegalStateException("Invalid or unhandled data type");
+ }
+ }
+
+ private void loadDirectoryMetaData(Result result) {
+ long directoryId = result.getDirectoryId();
+
+ Cursor cursor = getContext().getContentResolver().query(
+ ContentUris.withAppendedId(Directory.CONTENT_URI, directoryId),
+ DirectoryQuery.COLUMNS, null, null, null);
+ if (cursor == null) {
+ return;
+ }
+ try {
+ if (cursor.moveToFirst()) {
+ final String displayName = cursor.getString(DirectoryQuery.DISPLAY_NAME);
+ final String packageName = cursor.getString(DirectoryQuery.PACKAGE_NAME);
+ final int typeResourceId = cursor.getInt(DirectoryQuery.TYPE_RESOURCE_ID);
+ final String accountType = cursor.getString(DirectoryQuery.ACCOUNT_TYPE);
+ final String accountName = cursor.getString(DirectoryQuery.ACCOUNT_NAME);
+ final int exportSupport = cursor.getInt(DirectoryQuery.EXPORT_SUPPORT);
+ String directoryType = null;
+ if (!TextUtils.isEmpty(packageName)) {
+ PackageManager pm = getContext().getPackageManager();
try {
- int size;
- while ((size = fis.read(buffer)) != -1) {
- baos.write(buffer, 0, size);
- }
- contactData.setPhotoBinaryData(baos.toByteArray());
- } finally {
- fis.close();
- fd.close();
- }
- return;
- } catch (IOException ioe) {
- // Just fall back to the case below.
- }
- }
-
- // If we couldn't load from a file, fall back to the data blob.
- final long photoId = contactData.getPhotoId();
- if (photoId <= 0) {
- // No photo ID
- return;
- }
-
- for (Entity entity : contactData.getEntities()) {
- for (NamedContentValues subValue : entity.getSubValues()) {
- final ContentValues entryValues = subValue.values;
- final long dataId = entryValues.getAsLong(Data._ID);
- if (dataId == photoId) {
- final String mimeType = entryValues.getAsString(Data.MIMETYPE);
- // Correct Data Id but incorrect MimeType? Don't load
- if (!Photo.CONTENT_ITEM_TYPE.equals(mimeType)) {
- return;
- }
- contactData.setPhotoBinaryData(entryValues.getAsByteArray(Photo.PHOTO));
- break;
+ Resources resources = pm.getResourcesForApplication(packageName);
+ directoryType = resources.getString(typeResourceId);
+ } catch (NameNotFoundException e) {
+ Log.w(TAG, "Contact directory resource not found: "
+ + packageName + "." + typeResourceId);
}
}
+
+ result.setDirectoryMetaData(
+ displayName, directoryType, accountType, accountName, exportSupport);
}
+ } finally {
+ cursor.close();
}
+ }
- /**
- * Sets the "invitable" account types to {@link Result#mInvitableAccountTypes}.
- */
- private void loadInvitableAccountTypes(Result contactData) {
- Map<AccountTypeWithDataSet, AccountType> invitables =
- AccountTypeManager.getInstance(getContext()).getUsableInvitableAccountTypes();
- if (invitables.isEmpty()) {
- return;
- }
-
- Map<AccountTypeWithDataSet, AccountType> result = Maps.newHashMap(invitables);
-
- // Remove the ones that already have a raw contact in the current contact
- for (Entity entity : contactData.getEntities()) {
- final ContentValues values = entity.getEntityValues();
- final AccountTypeWithDataSet type = AccountTypeWithDataSet.get(
- values.getAsString(RawContacts.ACCOUNT_TYPE),
- values.getAsString(RawContacts.DATA_SET));
- result.remove(type);
- }
-
- // Set to mInvitableAccountTypes
- contactData.mInvitableAccountTypes.addAll(result.values());
- }
-
- /**
- * Extracts Contact level columns from the cursor.
- */
- private Result loadContactHeaderData(final Cursor cursor, Uri contactUri) {
- final String directoryParameter =
- contactUri.getQueryParameter(ContactsContract.DIRECTORY_PARAM_KEY);
- final long directoryId = directoryParameter == null
- ? Directory.DEFAULT
- : Long.parseLong(directoryParameter);
- final long contactId = cursor.getLong(ContactQuery.CONTACT_ID);
- final String lookupKey = cursor.getString(ContactQuery.LOOKUP_KEY);
- final long nameRawContactId = cursor.getLong(ContactQuery.NAME_RAW_CONTACT_ID);
- final int displayNameSource = cursor.getInt(ContactQuery.DISPLAY_NAME_SOURCE);
- final String displayName = cursor.getString(ContactQuery.DISPLAY_NAME);
- final String altDisplayName = cursor.getString(ContactQuery.ALT_DISPLAY_NAME);
- final String phoneticName = cursor.getString(ContactQuery.PHONETIC_NAME);
- final long photoId = cursor.getLong(ContactQuery.PHOTO_ID);
- final String photoUri = cursor.getString(ContactQuery.PHOTO_URI);
- final boolean starred = cursor.getInt(ContactQuery.STARRED) != 0;
- final Integer presence = cursor.isNull(ContactQuery.CONTACT_PRESENCE)
- ? null
- : cursor.getInt(ContactQuery.CONTACT_PRESENCE);
- final boolean sendToVoicemail = cursor.getInt(ContactQuery.SEND_TO_VOICEMAIL) == 1;
- final String customRingtone = cursor.getString(ContactQuery.CUSTOM_RINGTONE);
- final boolean isUserProfile = cursor.getInt(ContactQuery.IS_USER_PROFILE) == 1;
-
- Uri lookupUri;
- if (directoryId == Directory.DEFAULT || directoryId == Directory.LOCAL_INVISIBLE) {
- lookupUri = ContentUris.withAppendedId(
- Uri.withAppendedPath(Contacts.CONTENT_LOOKUP_URI, lookupKey), contactId);
- } else {
- lookupUri = contactUri;
- }
-
- return new Result(mRequestedUri, contactUri, lookupUri, directoryId, lookupKey,
- contactId, nameRawContactId, displayNameSource, photoId, photoUri, displayName,
- altDisplayName, phoneticName, starred, presence, sendToVoicemail,
- customRingtone, isUserProfile);
- }
-
- /**
- * Extracts RawContact level columns from the cursor.
- */
- private ContentValues loadRawContact(Cursor cursor) {
- ContentValues cv = new ContentValues();
-
- cv.put(RawContacts._ID, cursor.getLong(ContactQuery.RAW_CONTACT_ID));
-
- cursorColumnToContentValues(cursor, cv, ContactQuery.ACCOUNT_NAME);
- cursorColumnToContentValues(cursor, cv, ContactQuery.ACCOUNT_TYPE);
- cursorColumnToContentValues(cursor, cv, ContactQuery.DATA_SET);
- cursorColumnToContentValues(cursor, cv, ContactQuery.ACCOUNT_TYPE_AND_DATA_SET);
- cursorColumnToContentValues(cursor, cv, ContactQuery.DIRTY);
- cursorColumnToContentValues(cursor, cv, ContactQuery.VERSION);
- cursorColumnToContentValues(cursor, cv, ContactQuery.SOURCE_ID);
- cursorColumnToContentValues(cursor, cv, ContactQuery.SYNC1);
- cursorColumnToContentValues(cursor, cv, ContactQuery.SYNC2);
- cursorColumnToContentValues(cursor, cv, ContactQuery.SYNC3);
- cursorColumnToContentValues(cursor, cv, ContactQuery.SYNC4);
- cursorColumnToContentValues(cursor, cv, ContactQuery.DELETED);
- cursorColumnToContentValues(cursor, cv, ContactQuery.CONTACT_ID);
- cursorColumnToContentValues(cursor, cv, ContactQuery.STARRED);
- cursorColumnToContentValues(cursor, cv, ContactQuery.NAME_VERIFIED);
-
- return cv;
- }
-
- /**
- * Extracts Data level columns from the cursor.
- */
- private ContentValues loadData(Cursor cursor) {
- ContentValues cv = new ContentValues();
-
- cv.put(Data._ID, cursor.getLong(ContactQuery.DATA_ID));
-
- cursorColumnToContentValues(cursor, cv, ContactQuery.DATA1);
- cursorColumnToContentValues(cursor, cv, ContactQuery.DATA2);
- cursorColumnToContentValues(cursor, cv, ContactQuery.DATA3);
- cursorColumnToContentValues(cursor, cv, ContactQuery.DATA4);
- cursorColumnToContentValues(cursor, cv, ContactQuery.DATA5);
- cursorColumnToContentValues(cursor, cv, ContactQuery.DATA6);
- cursorColumnToContentValues(cursor, cv, ContactQuery.DATA7);
- cursorColumnToContentValues(cursor, cv, ContactQuery.DATA8);
- cursorColumnToContentValues(cursor, cv, ContactQuery.DATA9);
- cursorColumnToContentValues(cursor, cv, ContactQuery.DATA10);
- cursorColumnToContentValues(cursor, cv, ContactQuery.DATA11);
- cursorColumnToContentValues(cursor, cv, ContactQuery.DATA12);
- cursorColumnToContentValues(cursor, cv, ContactQuery.DATA13);
- cursorColumnToContentValues(cursor, cv, ContactQuery.DATA14);
- cursorColumnToContentValues(cursor, cv, ContactQuery.DATA15);
- cursorColumnToContentValues(cursor, cv, ContactQuery.DATA_SYNC1);
- cursorColumnToContentValues(cursor, cv, ContactQuery.DATA_SYNC2);
- cursorColumnToContentValues(cursor, cv, ContactQuery.DATA_SYNC3);
- cursorColumnToContentValues(cursor, cv, ContactQuery.DATA_SYNC4);
- cursorColumnToContentValues(cursor, cv, ContactQuery.DATA_VERSION);
- cursorColumnToContentValues(cursor, cv, ContactQuery.IS_PRIMARY);
- cursorColumnToContentValues(cursor, cv, ContactQuery.IS_SUPERPRIMARY);
- cursorColumnToContentValues(cursor, cv, ContactQuery.MIMETYPE);
- cursorColumnToContentValues(cursor, cv, ContactQuery.RES_PACKAGE);
- cursorColumnToContentValues(cursor, cv, ContactQuery.GROUP_SOURCE_ID);
- cursorColumnToContentValues(cursor, cv, ContactQuery.CHAT_CAPABILITY);
-
- return cv;
- }
-
- private void cursorColumnToContentValues(
- Cursor cursor, ContentValues values, int index) {
- switch (cursor.getType(index)) {
- case Cursor.FIELD_TYPE_NULL:
- // don't put anything in the content values
- break;
- case Cursor.FIELD_TYPE_INTEGER:
- values.put(ContactQuery.COLUMNS[index], cursor.getLong(index));
- break;
- case Cursor.FIELD_TYPE_STRING:
- values.put(ContactQuery.COLUMNS[index], cursor.getString(index));
- break;
- case Cursor.FIELD_TYPE_BLOB:
- values.put(ContactQuery.COLUMNS[index], cursor.getBlob(index));
- break;
- default:
- throw new IllegalStateException("Invalid or unhandled data type");
- }
- }
-
- private void loadDirectoryMetaData(Result result) {
- long directoryId = result.getDirectoryId();
-
- Cursor cursor = getContext().getContentResolver().query(
- ContentUris.withAppendedId(Directory.CONTENT_URI, directoryId),
- DirectoryQuery.COLUMNS, null, null, null);
- if (cursor == null) {
- return;
- }
- try {
- if (cursor.moveToFirst()) {
- final String displayName = cursor.getString(DirectoryQuery.DISPLAY_NAME);
- final String packageName = cursor.getString(DirectoryQuery.PACKAGE_NAME);
- final int typeResourceId = cursor.getInt(DirectoryQuery.TYPE_RESOURCE_ID);
- final String accountType = cursor.getString(DirectoryQuery.ACCOUNT_TYPE);
- final String accountName = cursor.getString(DirectoryQuery.ACCOUNT_NAME);
- final int exportSupport = cursor.getInt(DirectoryQuery.EXPORT_SUPPORT);
- String directoryType = null;
- if (!TextUtils.isEmpty(packageName)) {
- PackageManager pm = getContext().getPackageManager();
- try {
- Resources resources = pm.getResourcesForApplication(packageName);
- directoryType = resources.getString(typeResourceId);
- } catch (NameNotFoundException e) {
- Log.w(TAG, "Contact directory resource not found: "
- + packageName + "." + typeResourceId);
- }
- }
-
- result.setDirectoryMetaData(
- displayName, directoryType, accountType, accountName, exportSupport);
+ /**
+ * Loads groups meta-data for all groups associated with all constituent raw contacts'
+ * accounts.
+ */
+ private void loadGroupMetaData(Result result) {
+ StringBuilder selection = new StringBuilder();
+ ArrayList<String> selectionArgs = new ArrayList<String>();
+ for (Entity entity : result.mEntities) {
+ ContentValues values = entity.getEntityValues();
+ String accountName = values.getAsString(RawContacts.ACCOUNT_NAME);
+ String accountType = values.getAsString(RawContacts.ACCOUNT_TYPE);
+ String dataSet = values.getAsString(RawContacts.DATA_SET);
+ if (accountName != null && accountType != null) {
+ if (selection.length() != 0) {
+ selection.append(" OR ");
}
- } finally {
- cursor.close();
- }
- }
+ selection.append(
+ "(" + Groups.ACCOUNT_NAME + "=? AND " + Groups.ACCOUNT_TYPE + "=?");
+ selectionArgs.add(accountName);
+ selectionArgs.add(accountType);
- /**
- * Loads groups meta-data for all groups associated with all constituent raw contacts'
- * accounts.
- */
- private void loadGroupMetaData(Result result) {
- StringBuilder selection = new StringBuilder();
- ArrayList<String> selectionArgs = new ArrayList<String>();
- for (Entity entity : result.mEntities) {
- ContentValues values = entity.getEntityValues();
- String accountName = values.getAsString(RawContacts.ACCOUNT_NAME);
- String accountType = values.getAsString(RawContacts.ACCOUNT_TYPE);
- String dataSet = values.getAsString(RawContacts.DATA_SET);
- if (accountName != null && accountType != null) {
- if (selection.length() != 0) {
- selection.append(" OR ");
- }
- selection.append(
- "(" + Groups.ACCOUNT_NAME + "=? AND " + Groups.ACCOUNT_TYPE + "=?");
- selectionArgs.add(accountName);
- selectionArgs.add(accountType);
-
- if (dataSet != null) {
- selection.append(" AND " + Groups.DATA_SET + "=?");
- selectionArgs.add(dataSet);
- } else {
- selection.append(" AND " + Groups.DATA_SET + " IS NULL");
- }
- selection.append(")");
- }
- }
- Cursor cursor = getContext().getContentResolver().query(Groups.CONTENT_URI,
- GroupQuery.COLUMNS, selection.toString(), selectionArgs.toArray(new String[0]),
- null);
- try {
- while (cursor.moveToNext()) {
- final String accountName = cursor.getString(GroupQuery.ACCOUNT_NAME);
- final String accountType = cursor.getString(GroupQuery.ACCOUNT_TYPE);
- final String dataSet = cursor.getString(GroupQuery.DATA_SET);
- final long groupId = cursor.getLong(GroupQuery.ID);
- final String title = cursor.getString(GroupQuery.TITLE);
- final boolean defaultGroup = cursor.isNull(GroupQuery.AUTO_ADD)
- ? false
- : cursor.getInt(GroupQuery.AUTO_ADD) != 0;
- final boolean favorites = cursor.isNull(GroupQuery.FAVORITES)
- ? false
- : cursor.getInt(GroupQuery.FAVORITES) != 0;
-
- result.addGroupMetaData(new GroupMetaData(
- accountName, accountType, dataSet, groupId, title, defaultGroup,
- favorites));
- }
- } finally {
- cursor.close();
- }
- }
-
- /**
- * Loads all stream items and stream item photos belonging to this contact.
- */
- private void loadStreamItems(Result result) {
- Cursor cursor = getContext().getContentResolver().query(
- Contacts.CONTENT_LOOKUP_URI.buildUpon()
- .appendPath(result.getLookupKey())
- .appendPath(Contacts.StreamItems.CONTENT_DIRECTORY).build(),
- null, null, null, null);
- LongSparseArray<StreamItemEntry> streamItemsById =
- new LongSparseArray<StreamItemEntry>();
- ArrayList<StreamItemEntry> streamItems = new ArrayList<StreamItemEntry>();
- try {
- while (cursor.moveToNext()) {
- StreamItemEntry streamItem = new StreamItemEntry(cursor);
- streamItemsById.put(streamItem.getId(), streamItem);
- streamItems.add(streamItem);
- }
- } finally {
- cursor.close();
- }
-
- // Pre-decode all HTMLs
- final long start = System.currentTimeMillis();
- for (StreamItemEntry streamItem : streamItems) {
- streamItem.decodeHtml(getContext());
- }
- final long end = System.currentTimeMillis();
- if (DEBUG) {
- Log.d(TAG, "Decoded HTML for " + streamItems.size() + " items, took "
- + (end - start) + " ms");
- }
-
- // Now retrieve any photo records associated with the stream items.
- if (!streamItems.isEmpty()) {
- if (result.isUserProfile()) {
- // If the stream items we're loading are for the profile, we can't bulk-load the
- // stream items with a custom selection.
- for (StreamItemEntry entry : streamItems) {
- Cursor siCursor = getContext().getContentResolver().query(
- Uri.withAppendedPath(
- ContentUris.withAppendedId(
- StreamItems.CONTENT_URI, entry.getId()),
- StreamItems.StreamItemPhotos.CONTENT_DIRECTORY),
- null, null, null, null);
- try {
- while (siCursor.moveToNext()) {
- entry.addPhoto(new StreamItemPhotoEntry(siCursor));
- }
- } finally {
- siCursor.close();
- }
- }
+ if (dataSet != null) {
+ selection.append(" AND " + Groups.DATA_SET + "=?");
+ selectionArgs.add(dataSet);
} else {
- String[] streamItemIdArr = new String[streamItems.size()];
- StringBuilder streamItemPhotoSelection = new StringBuilder();
- streamItemPhotoSelection.append(StreamItemPhotos.STREAM_ITEM_ID + " IN (");
- for (int i = 0; i < streamItems.size(); i++) {
- if (i > 0) {
- streamItemPhotoSelection.append(",");
- }
- streamItemPhotoSelection.append("?");
- streamItemIdArr[i] = String.valueOf(streamItems.get(i).getId());
- }
- streamItemPhotoSelection.append(")");
- Cursor sipCursor = getContext().getContentResolver().query(
- StreamItems.CONTENT_PHOTO_URI,
- null, streamItemPhotoSelection.toString(), streamItemIdArr,
- StreamItemPhotos.STREAM_ITEM_ID);
+ selection.append(" AND " + Groups.DATA_SET + " IS NULL");
+ }
+ selection.append(")");
+ }
+ }
+ Cursor cursor = getContext().getContentResolver().query(Groups.CONTENT_URI,
+ GroupQuery.COLUMNS, selection.toString(), selectionArgs.toArray(new String[0]),
+ null);
+ try {
+ while (cursor.moveToNext()) {
+ final String accountName = cursor.getString(GroupQuery.ACCOUNT_NAME);
+ final String accountType = cursor.getString(GroupQuery.ACCOUNT_TYPE);
+ final String dataSet = cursor.getString(GroupQuery.DATA_SET);
+ final long groupId = cursor.getLong(GroupQuery.ID);
+ final String title = cursor.getString(GroupQuery.TITLE);
+ final boolean defaultGroup = cursor.isNull(GroupQuery.AUTO_ADD)
+ ? false
+ : cursor.getInt(GroupQuery.AUTO_ADD) != 0;
+ final boolean favorites = cursor.isNull(GroupQuery.FAVORITES)
+ ? false
+ : cursor.getInt(GroupQuery.FAVORITES) != 0;
+
+ result.addGroupMetaData(new GroupMetaData(
+ accountName, accountType, dataSet, groupId, title, defaultGroup,
+ favorites));
+ }
+ } finally {
+ cursor.close();
+ }
+ }
+
+ /**
+ * Loads all stream items and stream item photos belonging to this contact.
+ */
+ private void loadStreamItems(Result result) {
+ Cursor cursor = getContext().getContentResolver().query(
+ Contacts.CONTENT_LOOKUP_URI.buildUpon()
+ .appendPath(result.getLookupKey())
+ .appendPath(Contacts.StreamItems.CONTENT_DIRECTORY).build(),
+ null, null, null, null);
+ LongSparseArray<StreamItemEntry> streamItemsById =
+ new LongSparseArray<StreamItemEntry>();
+ ArrayList<StreamItemEntry> streamItems = new ArrayList<StreamItemEntry>();
+ try {
+ while (cursor.moveToNext()) {
+ StreamItemEntry streamItem = new StreamItemEntry(cursor);
+ streamItemsById.put(streamItem.getId(), streamItem);
+ streamItems.add(streamItem);
+ }
+ } finally {
+ cursor.close();
+ }
+
+ // Pre-decode all HTMLs
+ final long start = System.currentTimeMillis();
+ for (StreamItemEntry streamItem : streamItems) {
+ streamItem.decodeHtml(getContext());
+ }
+ final long end = System.currentTimeMillis();
+ if (DEBUG) {
+ Log.d(TAG, "Decoded HTML for " + streamItems.size() + " items, took "
+ + (end - start) + " ms");
+ }
+
+ // Now retrieve any photo records associated with the stream items.
+ if (!streamItems.isEmpty()) {
+ if (result.isUserProfile()) {
+ // If the stream items we're loading are for the profile, we can't bulk-load the
+ // stream items with a custom selection.
+ for (StreamItemEntry entry : streamItems) {
+ Cursor siCursor = getContext().getContentResolver().query(
+ Uri.withAppendedPath(
+ ContentUris.withAppendedId(
+ StreamItems.CONTENT_URI, entry.getId()),
+ StreamItems.StreamItemPhotos.CONTENT_DIRECTORY),
+ null, null, null, null);
try {
- while (sipCursor.moveToNext()) {
- long streamItemId = sipCursor.getLong(
- sipCursor.getColumnIndex(StreamItemPhotos.STREAM_ITEM_ID));
- StreamItemEntry streamItem = streamItemsById.get(streamItemId);
- streamItem.addPhoto(new StreamItemPhotoEntry(sipCursor));
+ while (siCursor.moveToNext()) {
+ entry.addPhoto(new StreamItemPhotoEntry(siCursor));
}
} finally {
- sipCursor.close();
+ siCursor.close();
}
}
- }
-
- // Set the sorted stream items on the result.
- Collections.sort(streamItems);
- result.mStreamItems.addAll(streamItems);
- }
-
- @Override
- protected void onPostExecute(Result result) {
- unregisterObserver();
-
- // The creator isn't interested in any further updates
- if (mDestroyed || result == null) {
- return;
- }
-
- mContact = result;
-
- if (result.isLoaded()) {
- mLookupUri = result.getLookupUri();
-
- if (!result.isDirectoryEntry()) {
- Log.i(TAG, "Registering content observer for " + mLookupUri);
- if (mObserver == null) {
- mObserver = new ForceLoadContentObserver();
+ } else {
+ String[] streamItemIdArr = new String[streamItems.size()];
+ StringBuilder streamItemPhotoSelection = new StringBuilder();
+ streamItemPhotoSelection.append(StreamItemPhotos.STREAM_ITEM_ID + " IN (");
+ for (int i = 0; i < streamItems.size(); i++) {
+ if (i > 0) {
+ streamItemPhotoSelection.append(",");
}
- getContext().getContentResolver().registerContentObserver(
- mLookupUri, true, mObserver);
+ streamItemPhotoSelection.append("?");
+ streamItemIdArr[i] = String.valueOf(streamItems.get(i).getId());
}
+ streamItemPhotoSelection.append(")");
+ Cursor sipCursor = getContext().getContentResolver().query(
+ StreamItems.CONTENT_PHOTO_URI,
+ null, streamItemPhotoSelection.toString(), streamItemIdArr,
+ StreamItemPhotos.STREAM_ITEM_ID);
+ try {
+ while (sipCursor.moveToNext()) {
+ long streamItemId = sipCursor.getLong(
+ sipCursor.getColumnIndex(StreamItemPhotos.STREAM_ITEM_ID));
+ StreamItemEntry streamItem = streamItemsById.get(streamItemId);
+ streamItem.addPhoto(new StreamItemPhotoEntry(sipCursor));
+ }
+ } finally {
+ sipCursor.close();
+ }
+ }
+ }
- // inform the source of the data that this contact is being looked at
- postViewNotificationToSyncAdapter();
+ // Set the sorted stream items on the result.
+ Collections.sort(streamItems);
+ result.mStreamItems.addAll(streamItems);
+ }
+
+ @Override
+ public void deliverResult(Result result) {
+ unregisterObserver();
+
+ // The creator isn't interested in any further updates
+ if (isReset() || result == null) {
+ return;
+ }
+
+ mContact = result;
+
+ if (result.isLoaded()) {
+ mLookupUri = result.getLookupUri();
+
+ if (!result.isDirectoryEntry()) {
+ Log.i(TAG, "Registering content observer for " + mLookupUri);
+ if (mObserver == null) {
+ mObserver = new ForceLoadContentObserver();
+ }
+ getContext().getContentResolver().registerContentObserver(
+ mLookupUri, true, mObserver);
}
- deliverResult(mContact);
+ // inform the source of the data that this contact is being looked at
+ postViewNotificationToSyncAdapter();
}
+
+ super.deliverResult(mContact);
}
/**
@@ -1205,20 +1214,6 @@
}
}
- public ContactLoader(Context context, Uri lookupUri) {
- this(context, lookupUri, false, false, false);
- }
-
- public ContactLoader(Context context, Uri lookupUri, boolean loadGroupMetaData,
- boolean loadStreamItems, boolean loadInvitableAccountTypes) {
- super(context);
- mLookupUri = lookupUri;
- mRequestedUri = lookupUri;
- mLoadGroupMetaData = loadGroupMetaData;
- mLoadStreamItems = loadStreamItems;
- mLoadInvitableAccountTypes = loadInvitableAccountTypes;
- }
-
/**
* Sets whether to load stream items. Will trigger a reload if the value has changed.
* At the moment, this is only used for debugging purposes
@@ -1250,15 +1245,15 @@
}
@Override
- protected void onForceLoad() {
- final LoadContactTask task = new LoadContactTask();
- task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[])null);
+ protected void onStopLoading() {
+ cancelLoad();
}
@Override
protected void onReset() {
+ super.onReset();
+ cancelLoad();
unregisterObserver();
mContact = null;
- mDestroyed = true;
}
}