ContactResolver.java revision c12da4a53eee911765975f0d8afe62f749806b60
1a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei/* 2a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei * Copyright (C) 2013 Google Inc. 3a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei * Licensed to The Android Open Source Project. 4a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei * 5a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei * Licensed under the Apache License, Version 2.0 (the "License"); 6a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei * you may not use this file except in compliance with the License. 7a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei * You may obtain a copy of the License at 8a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei * 9a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei * http://www.apache.org/licenses/LICENSE-2.0 10a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei * 11a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei * Unless required by applicable law or agreed to in writing, software 12a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei * distributed under the License is distributed on an "AS IS" BASIS, 13a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei * See the License for the specific language governing permissions and 15a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei * limitations under the License. 16a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei */ 17a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei 18a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Weipackage com.android.mail.bitmap; 19a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei 20a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Weiimport android.content.ContentResolver; 21a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Weiimport android.os.AsyncTask; 22a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Weiimport android.os.AsyncTask.Status; 23a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Weiimport android.os.Handler; 24a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei 252b806edc62eb8e83c77edc471fda4652281a15c4James Lemieuximport com.android.bitmap.BitmapCache; 262b806edc62eb8e83c77edc471fda4652281a15c4James Lemieuximport com.android.bitmap.DecodeTask; 272b806edc62eb8e83c77edc471fda4652281a15c4James Lemieuximport com.android.bitmap.RequestKey; 282b806edc62eb8e83c77edc471fda4652281a15c4James Lemieuximport com.android.bitmap.ReusableBitmap; 29a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Weiimport com.android.ex.photo.util.Trace; 30a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Weiimport com.android.mail.ContactInfo; 31a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Weiimport com.android.mail.SenderInfoLoader; 32a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Weiimport com.android.mail.bitmap.ContactRequest.ContactRequestHolder; 33a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Weiimport com.android.mail.utils.LogTag; 34a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Weiimport com.android.mail.utils.LogUtils; 35a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Weiimport com.google.common.collect.ImmutableMap; 36a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei 37a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Weiimport java.util.HashSet; 38a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Weiimport java.util.LinkedHashSet; 39a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Weiimport java.util.Set; 40a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Weiimport java.util.concurrent.Executor; 41a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Weiimport java.util.concurrent.LinkedBlockingQueue; 42a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Weiimport java.util.concurrent.ThreadPoolExecutor; 43a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Weiimport java.util.concurrent.TimeUnit; 44a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei 45a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei/** 46a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei * Batches up ContactRequests so we can efficiently query the contacts provider. Kicks off a 47a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei * ContactResolverTask to query for contact images in the background. 48a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei */ 49a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Weipublic class ContactResolver implements Runnable { 50a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei 51a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei private static final String TAG = LogTag.getLogTag(); 52a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei 53c12da4a53eee911765975f0d8afe62f749806b60Jin Cao // The maximum size returned from ContactsContract.Contacts.Photo.PHOTO is 96px by 96px. 54c12da4a53eee911765975f0d8afe62f749806b60Jin Cao private static final int MAXIMUM_PHOTO_SIZE = 96; 55c12da4a53eee911765975f0d8afe62f749806b60Jin Cao private static final int HALF_MAXIMUM_PHOTO_SIZE = 48; 56c12da4a53eee911765975f0d8afe62f749806b60Jin Cao 578913ca6aebe6017efe8060b61b8ad38eda95aa8bAndrew Sapperstein protected final ContentResolver mResolver; 58a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei private final BitmapCache mCache; 59a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei /** Insertion ordered set allows us to work from the top down. */ 60a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei private final LinkedHashSet<ContactRequestHolder> mBatch; 61a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei 62a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei private final Handler mHandler = new Handler(); 63a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei private ContactResolverTask mTask; 64a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei 65a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei 66a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei /** Size 1 pool mostly to make systrace output traces on one line. */ 67a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei private static final Executor SMALL_POOL_EXECUTOR = new ThreadPoolExecutor(1, 1, 68a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei 1, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>()); 69a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei private static final Executor EXECUTOR = SMALL_POOL_EXECUTOR; 70a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei 71c7849b23a73d699b5e7f199f0a3afce5b9dee7a6Martin Hibdon public interface ContactDrawableInterface { 722b806edc62eb8e83c77edc471fda4652281a15c4James Lemieux public void onDecodeComplete(final RequestKey key, final ReusableBitmap result); 732b806edc62eb8e83c77edc471fda4652281a15c4James Lemieux public int getDecodeWidth(); 742b806edc62eb8e83c77edc471fda4652281a15c4James Lemieux public int getDecodeHeight(); 75c7849b23a73d699b5e7f199f0a3afce5b9dee7a6Martin Hibdon } 76c7849b23a73d699b5e7f199f0a3afce5b9dee7a6Martin Hibdon 77a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei public ContactResolver(final ContentResolver resolver, final BitmapCache cache) { 78a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei mResolver = resolver; 79a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei mCache = cache; 80a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei mBatch = new LinkedHashSet<ContactRequestHolder>(); 81a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei } 82a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei 83a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei @Override 84a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei public void run() { 85a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei // Start to process a new batch. 86a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei if (mBatch.isEmpty()) { 87a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei return; 88a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei } 89a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei 90a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei if (mTask != null && mTask.getStatus() == Status.RUNNING) { 91a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei LogUtils.d(TAG, "ContactResolver << batch skip"); 92a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei return; 93a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei } 94a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei 95a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei Trace.beginSection("ContactResolver run"); 96a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei LogUtils.d(TAG, "ContactResolver >> batch start"); 97a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei 98a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei // Make a copy of the batch. 99a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei LinkedHashSet<ContactRequestHolder> batch = new LinkedHashSet<ContactRequestHolder>(mBatch); 100a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei 101a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei if (mTask != null) { 102a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei mTask.cancel(true); 103a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei } 104a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei 1058913ca6aebe6017efe8060b61b8ad38eda95aa8bAndrew Sapperstein mTask = getContactResolverTask(batch); 106a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei mTask.executeOnExecutor(EXECUTOR); 107a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei Trace.endSection(); 108a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei } 109a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei 1108913ca6aebe6017efe8060b61b8ad38eda95aa8bAndrew Sapperstein protected ContactResolverTask getContactResolverTask( 1118913ca6aebe6017efe8060b61b8ad38eda95aa8bAndrew Sapperstein LinkedHashSet<ContactRequestHolder> batch) { 1128913ca6aebe6017efe8060b61b8ad38eda95aa8bAndrew Sapperstein return new ContactResolverTask(batch, mResolver, mCache, this); 1138913ca6aebe6017efe8060b61b8ad38eda95aa8bAndrew Sapperstein } 1148913ca6aebe6017efe8060b61b8ad38eda95aa8bAndrew Sapperstein 1158913ca6aebe6017efe8060b61b8ad38eda95aa8bAndrew Sapperstein public BitmapCache getCache() { 1168913ca6aebe6017efe8060b61b8ad38eda95aa8bAndrew Sapperstein return mCache; 1178913ca6aebe6017efe8060b61b8ad38eda95aa8bAndrew Sapperstein } 1188913ca6aebe6017efe8060b61b8ad38eda95aa8bAndrew Sapperstein 119c7849b23a73d699b5e7f199f0a3afce5b9dee7a6Martin Hibdon public void add(final ContactRequest request, final ContactDrawableInterface drawable) { 120a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei mBatch.add(new ContactRequestHolder(request, drawable)); 121a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei notifyBatchReady(); 122a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei } 123a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei 124c7849b23a73d699b5e7f199f0a3afce5b9dee7a6Martin Hibdon public void remove(final ContactRequest request, final ContactDrawableInterface drawable) { 125a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei mBatch.remove(new ContactRequestHolder(request, drawable)); 126a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei } 127a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei 128a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei /** 129a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei * A layout pass traverses the whole tree during a single iteration of the event loop. That 130a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei * means that every ContactDrawable on the screen will add its ContactRequest to the batch in 131a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei * a single iteration of the event loop. 132a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei * 133a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei * <p/> 134a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei * We take advantage of this by posting a Runnable (happens to be this object) at the end of 135a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei * the event queue. Every time something is added to the batch as part of the same layout pass, 136a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei * the Runnable is moved to the back of the queue. When the next layout pass occurs, 137a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei * it is placed in the event loop behind this Runnable. That allows us to process the batch 138a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei * that was added previously. 139a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei */ 140a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei private void notifyBatchReady() { 141a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei LogUtils.d(TAG, "ContactResolver > batch %d", mBatch.size()); 142a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei mHandler.removeCallbacks(this); 143a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei mHandler.post(this); 144a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei } 145a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei 146a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei /** 147a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei * This is not a very traditional AsyncTask, in the sense that we do not care about what gets 148a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei * returned in doInBackground(). Instead, we signal traditional "return values" through 149a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei * publishProgress(). 150a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei * 151a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei * <p/> 152a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei * The reason we do this is because this task is responsible for decoding an entire batch of 153a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei * ContactRequests. But, we do not want to have to wait to decode all of them before updating 154a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei * any views. So we must do all the work in doInBackground(), 155a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei * but upon finishing each individual task, we need to jump out to the UI thread and update 156a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei * that view. 157a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei */ 1588913ca6aebe6017efe8060b61b8ad38eda95aa8bAndrew Sapperstein public static class ContactResolverTask extends AsyncTask<Void, Result, Void> { 159a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei 160a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei private final Set<ContactRequestHolder> mContactRequests; 161a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei private final ContentResolver mResolver; 162a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei private final BitmapCache mCache; 163a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei private final ContactResolver mCallback; 164a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei 165a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei public ContactResolverTask(final Set<ContactRequestHolder> contactRequests, 166a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei final ContentResolver resolver, final BitmapCache cache, 167a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei final ContactResolver callback) { 168a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei mContactRequests = contactRequests; 169a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei mResolver = resolver; 170a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei mCache = cache; 171a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei mCallback = callback; 172a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei } 173a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei 174a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei @Override 175a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei protected Void doInBackground(final Void... params) { 176a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei Trace.beginSection("set up"); 177a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei final Set<String> emails = new HashSet<String>(mContactRequests.size()); 178a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei for (ContactRequestHolder request : mContactRequests) { 179a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei final String email = request.getEmail(); 180a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei emails.add(email); 181a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei } 182a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei Trace.endSection(); 183a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei 184a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei Trace.beginSection("load contact photo bytes"); 185a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei // Query the contacts provider for the current batch of emails. 1868913ca6aebe6017efe8060b61b8ad38eda95aa8bAndrew Sapperstein final ImmutableMap<String, ContactInfo> contactInfos = loadContactPhotos(emails); 187a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei Trace.endSection(); 188a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei 189a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei for (ContactRequestHolder request : mContactRequests) { 190a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei Trace.beginSection("decode"); 191a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei final String email = request.getEmail(); 192a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei if (contactInfos == null) { 193a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei // Query failed. 194a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei LogUtils.d(TAG, "ContactResolver -- failed %s", email); 195a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei publishProgress(new Result(request, null)); 196a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei Trace.endSection(); 197a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei continue; 198a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei } 199a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei 200a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei final ContactInfo contactInfo = contactInfos.get(email); 201a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei if (contactInfo == null) { 202a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei // Request skipped. Try again next batch. 203a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei LogUtils.d(TAG, "ContactResolver = skipped %s", email); 204a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei Trace.endSection(); 205a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei continue; 206a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei } 207a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei 208a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei // Query attempted. 209a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei final byte[] photo = contactInfo.photoBytes; 210a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei if (photo == null) { 211a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei // No photo bytes found. 212a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei LogUtils.d(TAG, "ContactResolver -- failed %s", email); 213a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei publishProgress(new Result(request, null)); 214a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei Trace.endSection(); 215a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei continue; 216a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei } 217a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei 218a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei // Query succeeded. Photo bytes found. 219a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei request.contactRequest.bytes = photo; 220a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei 221a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei // Start decode. 222a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei LogUtils.d(TAG, "ContactResolver ++ found %s", email); 223a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei // Synchronously decode the photo bytes. We are already in a background 224a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei // thread, and we want decodes to finish in order. The decodes are blazing 225a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei // fast so we don't need to kick off multiple threads. 226c12da4a53eee911765975f0d8afe62f749806b60Jin Cao final int width = HALF_MAXIMUM_PHOTO_SIZE >= request.destination.getDecodeWidth() 227c12da4a53eee911765975f0d8afe62f749806b60Jin Cao ? HALF_MAXIMUM_PHOTO_SIZE : MAXIMUM_PHOTO_SIZE; 228c12da4a53eee911765975f0d8afe62f749806b60Jin Cao final int height = HALF_MAXIMUM_PHOTO_SIZE >= request.destination.getDecodeHeight() 229c12da4a53eee911765975f0d8afe62f749806b60Jin Cao ? HALF_MAXIMUM_PHOTO_SIZE : MAXIMUM_PHOTO_SIZE; 2302b806edc62eb8e83c77edc471fda4652281a15c4James Lemieux final DecodeTask.DecodeOptions opts = new DecodeTask.DecodeOptions( 231c12da4a53eee911765975f0d8afe62f749806b60Jin Cao width, height, 1 / 2f, DecodeTask.DecodeOptions.STRATEGY_ROUND_NEAREST); 2322b806edc62eb8e83c77edc471fda4652281a15c4James Lemieux final ReusableBitmap result = new DecodeTask(request.contactRequest, opts, null, 2332b806edc62eb8e83c77edc471fda4652281a15c4James Lemieux null, mCache).decode(); 234a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei request.contactRequest.bytes = null; 235a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei 236a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei // Decode success. 237a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei publishProgress(new Result(request, result)); 238a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei Trace.endSection(); 239a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei } 240a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei 241a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei return null; 242a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei } 243a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei 2448913ca6aebe6017efe8060b61b8ad38eda95aa8bAndrew Sapperstein protected ImmutableMap<String, ContactInfo> loadContactPhotos(Set<String> emails) { 24524ab60e7864f45b10bb74105bb8a1cf1a908dbeaRégis Décamps if (mResolver == null) { 24624ab60e7864f45b10bb74105bb8a1cf1a908dbeaRégis Décamps return null; 24724ab60e7864f45b10bb74105bb8a1cf1a908dbeaRégis Décamps } 2488913ca6aebe6017efe8060b61b8ad38eda95aa8bAndrew Sapperstein return SenderInfoLoader.loadContactPhotos(mResolver, emails, false /* decodeBitmaps */); 2498913ca6aebe6017efe8060b61b8ad38eda95aa8bAndrew Sapperstein } 2508913ca6aebe6017efe8060b61b8ad38eda95aa8bAndrew Sapperstein 251a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei /** 252a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei * We use progress updates to jump to the UI thread so we can decode the batch 253a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei * incrementally. 254a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei */ 255a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei @Override 256a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei protected void onProgressUpdate(final Result... values) { 257a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei final ContactRequestHolder request = values[0].request; 258a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei final ReusableBitmap bitmap = values[0].bitmap; 259a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei 260a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei // DecodeTask does not add null results to the cache. 26124ab60e7864f45b10bb74105bb8a1cf1a908dbeaRégis Décamps if (bitmap == null && mCache != null) { 262a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei // Cache null result. 263a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei mCache.put(request.contactRequest, null); 264a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei } 265a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei 266a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei request.destination.onDecodeComplete(request.contactRequest, bitmap); 267a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei } 268a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei 269a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei @Override 270a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei protected void onPostExecute(final Void aVoid) { 271a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei // Batch completed. Start next batch. 272a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei mCallback.notifyBatchReady(); 273a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei } 274a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei } 275a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei 276a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei /** 277a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei * Wrapper for the ContactRequest and its decoded bitmap. This class is used to pass results 278a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei * to onProgressUpdate(). 279a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei */ 280a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei private static class Result { 281a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei public final ContactRequestHolder request; 282a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei public final ReusableBitmap bitmap; 283a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei 284a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei private Result(final ContactRequestHolder request, final ReusableBitmap bitmap) { 285a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei this.request = request; 286a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei this.bitmap = bitmap; 287a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei } 288a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei } 289a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei} 290