1863e7a55dc45cd1210e4d07e5847f48dfe301876Jeff Hamilton 2863e7a55dc45cd1210e4d07e5847f48dfe301876Jeff Hamiltonpackage com.android.loaderapp.model; 3863e7a55dc45cd1210e4d07e5847f48dfe301876Jeff Hamilton 4863e7a55dc45cd1210e4d07e5847f48dfe301876Jeff Hamiltonimport com.android.loaderapp.util.DataStatus; 5863e7a55dc45cd1210e4d07e5847f48dfe301876Jeff Hamiltonimport com.google.android.collect.Lists; 6863e7a55dc45cd1210e4d07e5847f48dfe301876Jeff Hamiltonimport com.google.android.collect.Maps; 7863e7a55dc45cd1210e4d07e5847f48dfe301876Jeff Hamilton 8f6ffbae39b62c54c0a96914beaacfca213658a4fJeff Hamiltonimport android.content.AsyncTaskLoader; 9863e7a55dc45cd1210e4d07e5847f48dfe301876Jeff Hamiltonimport android.content.ContentResolver; 10863e7a55dc45cd1210e4d07e5847f48dfe301876Jeff Hamiltonimport android.content.ContentUris; 11863e7a55dc45cd1210e4d07e5847f48dfe301876Jeff Hamiltonimport android.content.Context; 12863e7a55dc45cd1210e4d07e5847f48dfe301876Jeff Hamiltonimport android.content.Entity; 13863e7a55dc45cd1210e4d07e5847f48dfe301876Jeff Hamiltonimport android.content.EntityIterator; 14f6ffbae39b62c54c0a96914beaacfca213658a4fJeff Hamiltonimport android.content.Loader.ForceLoadContentObserver; 15863e7a55dc45cd1210e4d07e5847f48dfe301876Jeff Hamiltonimport android.database.Cursor; 16863e7a55dc45cd1210e4d07e5847f48dfe301876Jeff Hamiltonimport android.net.Uri; 17863e7a55dc45cd1210e4d07e5847f48dfe301876Jeff Hamiltonimport android.os.AsyncTask; 18863e7a55dc45cd1210e4d07e5847f48dfe301876Jeff Hamiltonimport android.provider.ContactsContract.Contacts; 19863e7a55dc45cd1210e4d07e5847f48dfe301876Jeff Hamiltonimport android.provider.ContactsContract.Data; 20863e7a55dc45cd1210e4d07e5847f48dfe301876Jeff Hamiltonimport android.provider.ContactsContract.DisplayNameSources; 21863e7a55dc45cd1210e4d07e5847f48dfe301876Jeff Hamiltonimport android.provider.ContactsContract.RawContacts; 22863e7a55dc45cd1210e4d07e5847f48dfe301876Jeff Hamiltonimport android.provider.ContactsContract.RawContactsEntity; 23863e7a55dc45cd1210e4d07e5847f48dfe301876Jeff Hamiltonimport android.provider.ContactsContract.StatusUpdates; 24863e7a55dc45cd1210e4d07e5847f48dfe301876Jeff Hamilton 25863e7a55dc45cd1210e4d07e5847f48dfe301876Jeff Hamiltonimport java.util.ArrayList; 26863e7a55dc45cd1210e4d07e5847f48dfe301876Jeff Hamiltonimport java.util.HashMap; 27863e7a55dc45cd1210e4d07e5847f48dfe301876Jeff Hamilton 28863e7a55dc45cd1210e4d07e5847f48dfe301876Jeff Hamilton/** 29863e7a55dc45cd1210e4d07e5847f48dfe301876Jeff Hamilton * Loads a single Contact and all it constituent RawContacts. 30863e7a55dc45cd1210e4d07e5847f48dfe301876Jeff Hamilton */ 3103d1db253c9e7fa1f83cf467cc25a6a28ba0bdc1Jeff Hamiltonpublic class ContactLoader extends AsyncTaskLoader<ContactLoader.ContactData> { 32863e7a55dc45cd1210e4d07e5847f48dfe301876Jeff Hamilton Uri mLookupUri; 33863e7a55dc45cd1210e4d07e5847f48dfe301876Jeff Hamilton ContactData mContact; 34863e7a55dc45cd1210e4d07e5847f48dfe301876Jeff Hamilton ForceLoadContentObserver mObserver; 35863e7a55dc45cd1210e4d07e5847f48dfe301876Jeff Hamilton boolean mDestroyed; 36863e7a55dc45cd1210e4d07e5847f48dfe301876Jeff Hamilton 37863e7a55dc45cd1210e4d07e5847f48dfe301876Jeff Hamilton public interface Callbacks { 38863e7a55dc45cd1210e4d07e5847f48dfe301876Jeff Hamilton public void onContactLoaded(ContactData contact); 39863e7a55dc45cd1210e4d07e5847f48dfe301876Jeff Hamilton } 40863e7a55dc45cd1210e4d07e5847f48dfe301876Jeff Hamilton 41863e7a55dc45cd1210e4d07e5847f48dfe301876Jeff Hamilton public static final class ContactData { 42863e7a55dc45cd1210e4d07e5847f48dfe301876Jeff Hamilton public Uri uri; 43863e7a55dc45cd1210e4d07e5847f48dfe301876Jeff Hamilton public ArrayList<Entity> entities; 44863e7a55dc45cd1210e4d07e5847f48dfe301876Jeff Hamilton public HashMap<Long, DataStatus> statuses; 45863e7a55dc45cd1210e4d07e5847f48dfe301876Jeff Hamilton public long nameRawContactId = -1; 46863e7a55dc45cd1210e4d07e5847f48dfe301876Jeff Hamilton public int displayNameSource = DisplayNameSources.UNDEFINED; 47863e7a55dc45cd1210e4d07e5847f48dfe301876Jeff Hamilton } 48863e7a55dc45cd1210e4d07e5847f48dfe301876Jeff Hamilton 49863e7a55dc45cd1210e4d07e5847f48dfe301876Jeff Hamilton interface StatusQuery { 50863e7a55dc45cd1210e4d07e5847f48dfe301876Jeff Hamilton final String[] PROJECTION = new String[] { 51863e7a55dc45cd1210e4d07e5847f48dfe301876Jeff Hamilton Data._ID, Data.STATUS, Data.STATUS_RES_PACKAGE, Data.STATUS_ICON, 52863e7a55dc45cd1210e4d07e5847f48dfe301876Jeff Hamilton Data.STATUS_LABEL, Data.STATUS_TIMESTAMP, Data.PRESENCE, 53863e7a55dc45cd1210e4d07e5847f48dfe301876Jeff Hamilton }; 54863e7a55dc45cd1210e4d07e5847f48dfe301876Jeff Hamilton 55863e7a55dc45cd1210e4d07e5847f48dfe301876Jeff Hamilton final int _ID = 0; 56863e7a55dc45cd1210e4d07e5847f48dfe301876Jeff Hamilton } 57863e7a55dc45cd1210e4d07e5847f48dfe301876Jeff Hamilton 5803d1db253c9e7fa1f83cf467cc25a6a28ba0bdc1Jeff Hamilton @Override 5903d1db253c9e7fa1f83cf467cc25a6a28ba0bdc1Jeff Hamilton public ContactData loadInBackground() { 6003d1db253c9e7fa1f83cf467cc25a6a28ba0bdc1Jeff Hamilton ContentResolver resolver = getContext().getContentResolver(); 6103d1db253c9e7fa1f83cf467cc25a6a28ba0bdc1Jeff Hamilton ContactData result = new ContactData(); 6203d1db253c9e7fa1f83cf467cc25a6a28ba0bdc1Jeff Hamilton 6303d1db253c9e7fa1f83cf467cc25a6a28ba0bdc1Jeff Hamilton // Undo the lookup URI 6403d1db253c9e7fa1f83cf467cc25a6a28ba0bdc1Jeff Hamilton Uri contactUri = null; 6503d1db253c9e7fa1f83cf467cc25a6a28ba0bdc1Jeff Hamilton if (mLookupUri != null) { 6603d1db253c9e7fa1f83cf467cc25a6a28ba0bdc1Jeff Hamilton mLookupUri = Contacts.getLookupUri(resolver, mLookupUri); 67863e7a55dc45cd1210e4d07e5847f48dfe301876Jeff Hamilton if (mLookupUri != null) { 6803d1db253c9e7fa1f83cf467cc25a6a28ba0bdc1Jeff Hamilton contactUri = Contacts.lookupContact(resolver, mLookupUri); 69863e7a55dc45cd1210e4d07e5847f48dfe301876Jeff Hamilton } 7003d1db253c9e7fa1f83cf467cc25a6a28ba0bdc1Jeff Hamilton } 71863e7a55dc45cd1210e4d07e5847f48dfe301876Jeff Hamilton 7203d1db253c9e7fa1f83cf467cc25a6a28ba0bdc1Jeff Hamilton if (contactUri == null) { 7303d1db253c9e7fa1f83cf467cc25a6a28ba0bdc1Jeff Hamilton return null; 7403d1db253c9e7fa1f83cf467cc25a6a28ba0bdc1Jeff Hamilton } 7503d1db253c9e7fa1f83cf467cc25a6a28ba0bdc1Jeff Hamilton result.uri = contactUri; 7603d1db253c9e7fa1f83cf467cc25a6a28ba0bdc1Jeff Hamilton 7703d1db253c9e7fa1f83cf467cc25a6a28ba0bdc1Jeff Hamilton // Read available social rows 7803d1db253c9e7fa1f83cf467cc25a6a28ba0bdc1Jeff Hamilton final Uri dataUri = Uri.withAppendedPath(contactUri, Contacts.Data.CONTENT_DIRECTORY); 7903d1db253c9e7fa1f83cf467cc25a6a28ba0bdc1Jeff Hamilton Cursor cursor = resolver.query(dataUri, StatusQuery.PROJECTION, StatusUpdates.PRESENCE 8003d1db253c9e7fa1f83cf467cc25a6a28ba0bdc1Jeff Hamilton + " IS NOT NULL OR " + StatusUpdates.STATUS + " IS NOT NULL", null, null); 8103d1db253c9e7fa1f83cf467cc25a6a28ba0bdc1Jeff Hamilton 8203d1db253c9e7fa1f83cf467cc25a6a28ba0bdc1Jeff Hamilton if (cursor != null) { 8303d1db253c9e7fa1f83cf467cc25a6a28ba0bdc1Jeff Hamilton try { 8403d1db253c9e7fa1f83cf467cc25a6a28ba0bdc1Jeff Hamilton HashMap<Long, DataStatus> statuses = Maps.newHashMap(); 8503d1db253c9e7fa1f83cf467cc25a6a28ba0bdc1Jeff Hamilton 8603d1db253c9e7fa1f83cf467cc25a6a28ba0bdc1Jeff Hamilton // Walk found statuses, creating internal row for each 8703d1db253c9e7fa1f83cf467cc25a6a28ba0bdc1Jeff Hamilton while (cursor.moveToNext()) { 8803d1db253c9e7fa1f83cf467cc25a6a28ba0bdc1Jeff Hamilton final DataStatus status = new DataStatus(cursor); 8903d1db253c9e7fa1f83cf467cc25a6a28ba0bdc1Jeff Hamilton final long dataId = cursor.getLong(StatusQuery._ID); 9003d1db253c9e7fa1f83cf467cc25a6a28ba0bdc1Jeff Hamilton statuses.put(dataId, status); 91863e7a55dc45cd1210e4d07e5847f48dfe301876Jeff Hamilton } 9203d1db253c9e7fa1f83cf467cc25a6a28ba0bdc1Jeff Hamilton result.statuses = statuses; 9303d1db253c9e7fa1f83cf467cc25a6a28ba0bdc1Jeff Hamilton } finally { 9403d1db253c9e7fa1f83cf467cc25a6a28ba0bdc1Jeff Hamilton cursor.close(); 95863e7a55dc45cd1210e4d07e5847f48dfe301876Jeff Hamilton } 9603d1db253c9e7fa1f83cf467cc25a6a28ba0bdc1Jeff Hamilton } 97863e7a55dc45cd1210e4d07e5847f48dfe301876Jeff Hamilton 9803d1db253c9e7fa1f83cf467cc25a6a28ba0bdc1Jeff Hamilton // Read out the info about the display name 9903d1db253c9e7fa1f83cf467cc25a6a28ba0bdc1Jeff Hamilton cursor = resolver.query(dataUri, new String[] { 10003d1db253c9e7fa1f83cf467cc25a6a28ba0bdc1Jeff Hamilton Contacts.NAME_RAW_CONTACT_ID, Contacts.DISPLAY_NAME_SOURCE 10103d1db253c9e7fa1f83cf467cc25a6a28ba0bdc1Jeff Hamilton }, null, null, null); 10203d1db253c9e7fa1f83cf467cc25a6a28ba0bdc1Jeff Hamilton if (cursor != null) { 10303d1db253c9e7fa1f83cf467cc25a6a28ba0bdc1Jeff Hamilton try { 10403d1db253c9e7fa1f83cf467cc25a6a28ba0bdc1Jeff Hamilton if (cursor.moveToFirst()) { 10503d1db253c9e7fa1f83cf467cc25a6a28ba0bdc1Jeff Hamilton result.nameRawContactId = cursor.getLong(cursor 10603d1db253c9e7fa1f83cf467cc25a6a28ba0bdc1Jeff Hamilton .getColumnIndex(Contacts.NAME_RAW_CONTACT_ID)); 10703d1db253c9e7fa1f83cf467cc25a6a28ba0bdc1Jeff Hamilton result.displayNameSource = cursor.getInt(cursor 10803d1db253c9e7fa1f83cf467cc25a6a28ba0bdc1Jeff Hamilton .getColumnIndex(Contacts.DISPLAY_NAME_SOURCE)); 109863e7a55dc45cd1210e4d07e5847f48dfe301876Jeff Hamilton } 11003d1db253c9e7fa1f83cf467cc25a6a28ba0bdc1Jeff Hamilton } finally { 11103d1db253c9e7fa1f83cf467cc25a6a28ba0bdc1Jeff Hamilton cursor.close(); 112863e7a55dc45cd1210e4d07e5847f48dfe301876Jeff Hamilton } 11303d1db253c9e7fa1f83cf467cc25a6a28ba0bdc1Jeff Hamilton } 114863e7a55dc45cd1210e4d07e5847f48dfe301876Jeff Hamilton 11503d1db253c9e7fa1f83cf467cc25a6a28ba0bdc1Jeff Hamilton // Read the constituent raw contacts 11603d1db253c9e7fa1f83cf467cc25a6a28ba0bdc1Jeff Hamilton final long contactId = ContentUris.parseId(contactUri); 11703d1db253c9e7fa1f83cf467cc25a6a28ba0bdc1Jeff Hamilton cursor = resolver.query(RawContactsEntity.CONTENT_URI, null, RawContacts.CONTACT_ID 11803d1db253c9e7fa1f83cf467cc25a6a28ba0bdc1Jeff Hamilton + "=" + contactId, null, null); 11903d1db253c9e7fa1f83cf467cc25a6a28ba0bdc1Jeff Hamilton if (cursor != null) { 12003d1db253c9e7fa1f83cf467cc25a6a28ba0bdc1Jeff Hamilton ArrayList<Entity> entities = Lists.newArrayList(); 12103d1db253c9e7fa1f83cf467cc25a6a28ba0bdc1Jeff Hamilton EntityIterator iterator = RawContacts.newEntityIterator(cursor); 12203d1db253c9e7fa1f83cf467cc25a6a28ba0bdc1Jeff Hamilton try { 12303d1db253c9e7fa1f83cf467cc25a6a28ba0bdc1Jeff Hamilton while (iterator.hasNext()) { 12403d1db253c9e7fa1f83cf467cc25a6a28ba0bdc1Jeff Hamilton Entity entity = iterator.next(); 12503d1db253c9e7fa1f83cf467cc25a6a28ba0bdc1Jeff Hamilton entities.add(entity); 126863e7a55dc45cd1210e4d07e5847f48dfe301876Jeff Hamilton } 12703d1db253c9e7fa1f83cf467cc25a6a28ba0bdc1Jeff Hamilton } finally { 12803d1db253c9e7fa1f83cf467cc25a6a28ba0bdc1Jeff Hamilton iterator.close(); 129863e7a55dc45cd1210e4d07e5847f48dfe301876Jeff Hamilton } 13003d1db253c9e7fa1f83cf467cc25a6a28ba0bdc1Jeff Hamilton result.entities = entities; 131863e7a55dc45cd1210e4d07e5847f48dfe301876Jeff Hamilton } 132863e7a55dc45cd1210e4d07e5847f48dfe301876Jeff Hamilton 13303d1db253c9e7fa1f83cf467cc25a6a28ba0bdc1Jeff Hamilton return result; 13403d1db253c9e7fa1f83cf467cc25a6a28ba0bdc1Jeff Hamilton } 135863e7a55dc45cd1210e4d07e5847f48dfe301876Jeff Hamilton 13603d1db253c9e7fa1f83cf467cc25a6a28ba0bdc1Jeff Hamilton @Override 13703d1db253c9e7fa1f83cf467cc25a6a28ba0bdc1Jeff Hamilton public void deliverResult(ContactData result) { 13803d1db253c9e7fa1f83cf467cc25a6a28ba0bdc1Jeff Hamilton // The creator isn't interested in any further updates 13903d1db253c9e7fa1f83cf467cc25a6a28ba0bdc1Jeff Hamilton if (mDestroyed) { 14003d1db253c9e7fa1f83cf467cc25a6a28ba0bdc1Jeff Hamilton return; 14103d1db253c9e7fa1f83cf467cc25a6a28ba0bdc1Jeff Hamilton } 14203d1db253c9e7fa1f83cf467cc25a6a28ba0bdc1Jeff Hamilton 14303d1db253c9e7fa1f83cf467cc25a6a28ba0bdc1Jeff Hamilton mContact = result; 14403d1db253c9e7fa1f83cf467cc25a6a28ba0bdc1Jeff Hamilton if (result != null) { 14503d1db253c9e7fa1f83cf467cc25a6a28ba0bdc1Jeff Hamilton if (mObserver == null) { 14603d1db253c9e7fa1f83cf467cc25a6a28ba0bdc1Jeff Hamilton mObserver = new ForceLoadContentObserver(); 147863e7a55dc45cd1210e4d07e5847f48dfe301876Jeff Hamilton } 14803d1db253c9e7fa1f83cf467cc25a6a28ba0bdc1Jeff Hamilton getContext().getContentResolver().registerContentObserver(mLookupUri, true, mObserver); 14903d1db253c9e7fa1f83cf467cc25a6a28ba0bdc1Jeff Hamilton super.deliverResult(result); 150863e7a55dc45cd1210e4d07e5847f48dfe301876Jeff Hamilton } 151863e7a55dc45cd1210e4d07e5847f48dfe301876Jeff Hamilton } 152863e7a55dc45cd1210e4d07e5847f48dfe301876Jeff Hamilton 153863e7a55dc45cd1210e4d07e5847f48dfe301876Jeff Hamilton public ContactLoader(Context context, Uri lookupUri) { 154863e7a55dc45cd1210e4d07e5847f48dfe301876Jeff Hamilton super(context); 155863e7a55dc45cd1210e4d07e5847f48dfe301876Jeff Hamilton mLookupUri = lookupUri; 156863e7a55dc45cd1210e4d07e5847f48dfe301876Jeff Hamilton } 157863e7a55dc45cd1210e4d07e5847f48dfe301876Jeff Hamilton 158863e7a55dc45cd1210e4d07e5847f48dfe301876Jeff Hamilton @Override 159863e7a55dc45cd1210e4d07e5847f48dfe301876Jeff Hamilton public void startLoading() { 160863e7a55dc45cd1210e4d07e5847f48dfe301876Jeff Hamilton if (mContact != null) { 161863e7a55dc45cd1210e4d07e5847f48dfe301876Jeff Hamilton deliverResult(mContact); 162863e7a55dc45cd1210e4d07e5847f48dfe301876Jeff Hamilton } else { 163863e7a55dc45cd1210e4d07e5847f48dfe301876Jeff Hamilton forceLoad(); 164863e7a55dc45cd1210e4d07e5847f48dfe301876Jeff Hamilton } 165863e7a55dc45cd1210e4d07e5847f48dfe301876Jeff Hamilton } 166863e7a55dc45cd1210e4d07e5847f48dfe301876Jeff Hamilton 167863e7a55dc45cd1210e4d07e5847f48dfe301876Jeff Hamilton @Override 168863e7a55dc45cd1210e4d07e5847f48dfe301876Jeff Hamilton public void stopLoading() { 169863e7a55dc45cd1210e4d07e5847f48dfe301876Jeff Hamilton mContact = null; 170863e7a55dc45cd1210e4d07e5847f48dfe301876Jeff Hamilton if (mObserver != null) { 1715ae21732ecead724915713cb26e2f79ef54fc5d8Jeff Hamilton getContext().getContentResolver().unregisterContentObserver(mObserver); 172863e7a55dc45cd1210e4d07e5847f48dfe301876Jeff Hamilton } 173863e7a55dc45cd1210e4d07e5847f48dfe301876Jeff Hamilton } 174863e7a55dc45cd1210e4d07e5847f48dfe301876Jeff Hamilton 175863e7a55dc45cd1210e4d07e5847f48dfe301876Jeff Hamilton @Override 176863e7a55dc45cd1210e4d07e5847f48dfe301876Jeff Hamilton public void destroy() { 177863e7a55dc45cd1210e4d07e5847f48dfe301876Jeff Hamilton mContact = null; 178863e7a55dc45cd1210e4d07e5847f48dfe301876Jeff Hamilton mDestroyed = true; 179863e7a55dc45cd1210e4d07e5847f48dfe301876Jeff Hamilton } 180863e7a55dc45cd1210e4d07e5847f48dfe301876Jeff Hamilton} 181