Home | History | Annotate | Download | only in model
      1 
      2 package com.android.loaderapp.model;
      3 
      4 import com.android.loaderapp.util.DataStatus;
      5 import com.google.android.collect.Lists;
      6 import com.google.android.collect.Maps;
      7 
      8 import android.content.AsyncTaskLoader;
      9 import android.content.ContentResolver;
     10 import android.content.ContentUris;
     11 import android.content.Context;
     12 import android.content.Entity;
     13 import android.content.EntityIterator;
     14 import android.content.Loader.ForceLoadContentObserver;
     15 import android.database.Cursor;
     16 import android.net.Uri;
     17 import android.os.AsyncTask;
     18 import android.provider.ContactsContract.Contacts;
     19 import android.provider.ContactsContract.Data;
     20 import android.provider.ContactsContract.DisplayNameSources;
     21 import android.provider.ContactsContract.RawContacts;
     22 import android.provider.ContactsContract.RawContactsEntity;
     23 import android.provider.ContactsContract.StatusUpdates;
     24 
     25 import java.util.ArrayList;
     26 import java.util.HashMap;
     27 
     28 /**
     29  * Loads a single Contact and all it constituent RawContacts.
     30  */
     31 public class ContactLoader extends AsyncTaskLoader<ContactLoader.ContactData> {
     32     Uri mLookupUri;
     33     ContactData mContact;
     34     ForceLoadContentObserver mObserver;
     35     boolean mDestroyed;
     36 
     37     public interface Callbacks {
     38         public void onContactLoaded(ContactData contact);
     39     }
     40 
     41     public static final class ContactData {
     42         public Uri uri;
     43         public ArrayList<Entity> entities;
     44         public HashMap<Long, DataStatus> statuses;
     45         public long nameRawContactId = -1;
     46         public int displayNameSource = DisplayNameSources.UNDEFINED;
     47     }
     48 
     49     interface StatusQuery {
     50         final String[] PROJECTION = new String[] {
     51                 Data._ID, Data.STATUS, Data.STATUS_RES_PACKAGE, Data.STATUS_ICON,
     52                 Data.STATUS_LABEL, Data.STATUS_TIMESTAMP, Data.PRESENCE,
     53         };
     54 
     55         final int _ID = 0;
     56     }
     57 
     58     @Override
     59     public ContactData loadInBackground() {
     60         ContentResolver resolver = getContext().getContentResolver();
     61         ContactData result = new ContactData();
     62 
     63         // Undo the lookup URI
     64         Uri contactUri = null;
     65         if (mLookupUri != null) {
     66             mLookupUri = Contacts.getLookupUri(resolver, mLookupUri);
     67             if (mLookupUri != null) {
     68                 contactUri = Contacts.lookupContact(resolver, mLookupUri);
     69             }
     70         }
     71 
     72         if (contactUri == null) {
     73             return null;
     74         }
     75         result.uri = contactUri;
     76 
     77         // Read available social rows
     78         final Uri dataUri = Uri.withAppendedPath(contactUri, Contacts.Data.CONTENT_DIRECTORY);
     79         Cursor cursor = resolver.query(dataUri, StatusQuery.PROJECTION, StatusUpdates.PRESENCE
     80                 + " IS NOT NULL OR " + StatusUpdates.STATUS + " IS NOT NULL", null, null);
     81 
     82         if (cursor != null) {
     83             try {
     84                 HashMap<Long, DataStatus> statuses = Maps.newHashMap();
     85 
     86                 // Walk found statuses, creating internal row for each
     87                 while (cursor.moveToNext()) {
     88                     final DataStatus status = new DataStatus(cursor);
     89                     final long dataId = cursor.getLong(StatusQuery._ID);
     90                     statuses.put(dataId, status);
     91                 }
     92                 result.statuses = statuses;
     93             } finally {
     94                 cursor.close();
     95             }
     96         }
     97 
     98         // Read out the info about the display name
     99         cursor = resolver.query(dataUri, new String[] {
    100                 Contacts.NAME_RAW_CONTACT_ID, Contacts.DISPLAY_NAME_SOURCE
    101         }, null, null, null);
    102         if (cursor != null) {
    103             try {
    104                 if (cursor.moveToFirst()) {
    105                     result.nameRawContactId = cursor.getLong(cursor
    106                             .getColumnIndex(Contacts.NAME_RAW_CONTACT_ID));
    107                     result.displayNameSource = cursor.getInt(cursor
    108                             .getColumnIndex(Contacts.DISPLAY_NAME_SOURCE));
    109                 }
    110             } finally {
    111                 cursor.close();
    112             }
    113         }
    114 
    115         // Read the constituent raw contacts
    116         final long contactId = ContentUris.parseId(contactUri);
    117         cursor = resolver.query(RawContactsEntity.CONTENT_URI, null, RawContacts.CONTACT_ID
    118                 + "=" + contactId, null, null);
    119         if (cursor != null) {
    120             ArrayList<Entity> entities = Lists.newArrayList();
    121             EntityIterator iterator = RawContacts.newEntityIterator(cursor);
    122             try {
    123                 while (iterator.hasNext()) {
    124                     Entity entity = iterator.next();
    125                     entities.add(entity);
    126                 }
    127             } finally {
    128                 iterator.close();
    129             }
    130             result.entities = entities;
    131         }
    132 
    133         return result;
    134     }
    135 
    136     @Override
    137     public void deliverResult(ContactData result) {
    138         // The creator isn't interested in any further updates
    139         if (mDestroyed) {
    140             return;
    141         }
    142 
    143         mContact = result;
    144         if (result != null) {
    145             if (mObserver == null) {
    146                 mObserver = new ForceLoadContentObserver();
    147             }
    148             getContext().getContentResolver().registerContentObserver(mLookupUri, true, mObserver);
    149             super.deliverResult(result);
    150         }
    151     }
    152 
    153     public ContactLoader(Context context, Uri lookupUri) {
    154         super(context);
    155         mLookupUri = lookupUri;
    156     }
    157 
    158     @Override
    159     public void startLoading() {
    160         if (mContact != null) {
    161             deliverResult(mContact);
    162         } else {
    163             forceLoad();
    164         }
    165     }
    166 
    167     @Override
    168     public void stopLoading() {
    169         mContact = null;
    170         if (mObserver != null) {
    171             getContext().getContentResolver().unregisterContentObserver(mObserver);
    172         }
    173     }
    174 
    175     @Override
    176     public void destroy() {
    177         mContact = null;
    178         mDestroyed = true;
    179     }
    180 }
    181