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