Home | History | Annotate | Download | only in activity
      1 /*
      2  * Copyright (C) 2010 The Android Open Source Project
      3  *
      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 
     17 package com.android.email.activity;
     18 
     19 import android.content.AsyncTaskLoader;
     20 import android.content.ContentUris;
     21 import android.content.Context;
     22 import android.database.Cursor;
     23 import android.graphics.Bitmap;
     24 import android.graphics.BitmapFactory;
     25 import android.net.Uri;
     26 import android.provider.ContactsContract.CommonDataKinds.Email;
     27 import android.provider.ContactsContract.CommonDataKinds.Photo;
     28 import android.provider.ContactsContract.Contacts;
     29 import android.provider.ContactsContract.Data;
     30 import android.provider.ContactsContract.StatusUpdates;
     31 
     32 import com.android.emailcommon.Logging;
     33 import com.android.emailcommon.utility.Utility;
     34 import com.android.mail.utils.LogUtils;
     35 import com.google.common.annotations.VisibleForTesting;
     36 
     37 /**
     38  * Loader to load presence statuses and the contact photo.
     39  */
     40 public class ContactStatusLoader extends AsyncTaskLoader<ContactStatusLoader.Result> {
     41     @VisibleForTesting
     42     static final int PRESENCE_UNKNOWN_RESOURCE_ID = android.R.drawable.presence_offline;
     43 
     44     /** email address -> photo id, presence */
     45     /* package */ static final String[] PROJECTION_PHOTO_ID_PRESENCE = new String[] {
     46             Contacts.PHOTO_ID,
     47             Contacts.CONTACT_PRESENCE
     48             };
     49     private static final int COLUMN_PHOTO_ID = 0;
     50     private static final int COLUMN_PRESENCE = 1;
     51 
     52     /** photo id -> photo data */
     53     /* package */ static final String[] PHOTO_PROJECTION = new String[] {
     54             Photo.PHOTO
     55             };
     56     private static final int PHOTO_COLUMN = 0;
     57 
     58     private final Context mContext;
     59     private final String mEmailAddress;
     60 
     61     /**
     62      * Class that encapsulates the result.
     63      */
     64     public static class Result {
     65         public static final Result UNKNOWN = new Result(null, PRESENCE_UNKNOWN_RESOURCE_ID, null);
     66 
     67         /** Contact photo.  Null if unknown */
     68         public final Bitmap mPhoto;
     69 
     70         /** Presence image resource ID.  Always has a valid value, even if unknown. */
     71         public final int mPresenceResId;
     72 
     73         /** URI for opening quick contact.  Null if unknown. */
     74         public final Uri mLookupUri;
     75 
     76         public Result(Bitmap photo, int presenceResId, Uri lookupUri) {
     77             mPhoto = photo;
     78             mPresenceResId = presenceResId;
     79             mLookupUri = lookupUri;
     80         }
     81 
     82         public boolean isUnknown() {
     83             return PRESENCE_UNKNOWN_RESOURCE_ID == mPresenceResId;
     84         }
     85     }
     86 
     87     public ContactStatusLoader(Context context, String emailAddress) {
     88         super(context);
     89         mContext = context;
     90         mEmailAddress = emailAddress;
     91     }
     92 
     93     @Override
     94     public Result loadInBackground() {
     95         return getContactInfo(mContext, mEmailAddress);
     96     }
     97 
     98     /**
     99      * Synchronously loads contact data.
    100      *
    101      * NOTE: DO NOT CALL THIS METHOD FROM THE UI THREAD (DATABASE ACCESS)
    102      */
    103     public static Result getContactInfo(Context context, String emailAddress) {
    104         // Load photo-id and presence status.
    105         Uri uri = Uri.withAppendedPath(Email.CONTENT_LOOKUP_URI, Uri.encode(emailAddress));
    106         Cursor c = context.getContentResolver().query(
    107                 uri,
    108                 PROJECTION_PHOTO_ID_PRESENCE, null, null, null);
    109         if (c == null) {
    110             return Result.UNKNOWN;
    111         }
    112         final long photoId;
    113         final int presenceStatus;
    114         try {
    115             if (!c.moveToFirst()) {
    116                 return Result.UNKNOWN;
    117             }
    118             photoId = c.getLong(COLUMN_PHOTO_ID);
    119             presenceStatus = c.getInt(COLUMN_PRESENCE);
    120         } finally {
    121             c.close();
    122         }
    123 
    124         // Convert presence status into the res id.
    125         final int presenceStatusResId = StatusUpdates.getPresenceIconResourceId(presenceStatus);
    126 
    127         // load photo from photo-id.
    128         Bitmap photo = null;
    129         if (photoId != -1) {
    130             final byte[] photoData = Utility.getFirstRowBlob(context,
    131                     ContentUris.withAppendedId(Data.CONTENT_URI, photoId), PHOTO_PROJECTION,
    132                     null, null, null, PHOTO_COLUMN, null);
    133             if (photoData != null) {
    134                 try {
    135                     photo = BitmapFactory.decodeByteArray(photoData, 0, photoData.length, null);
    136                 } catch (OutOfMemoryError e) {
    137                     LogUtils.d(Logging.LOG_TAG, "Decoding bitmap failed with " + e.getMessage());
    138                 }
    139             }
    140         }
    141 
    142         // Get lookup URI
    143         final Uri lookupUri = Data.getContactLookupUri(context.getContentResolver(), uri);
    144         return new Result(photo, presenceStatusResId, lookupUri);
    145     }
    146 
    147     @Override
    148     protected void onStartLoading() {
    149         cancelLoad();
    150         forceLoad();
    151     }
    152 
    153     @Override
    154     protected void onStopLoading() {
    155         cancelLoad();
    156     }
    157 
    158     @Override
    159     protected void onReset() {
    160         stopLoading();
    161     }
    162 }
    163