ContactResolver.java revision 24ab60e7864f45b10bb74105bb8a1cf1a908dbea
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 538913ca6aebe6017efe8060b61b8ad38eda95aa8bAndrew Sapperstein protected final ContentResolver mResolver; 54a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei private final BitmapCache mCache; 55a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei /** Insertion ordered set allows us to work from the top down. */ 56a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei private final LinkedHashSet<ContactRequestHolder> mBatch; 57a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei 58a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei private final Handler mHandler = new Handler(); 59a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei private ContactResolverTask mTask; 60a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei 61a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei 62a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei /** Size 1 pool mostly to make systrace output traces on one line. */ 63a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei private static final Executor SMALL_POOL_EXECUTOR = new ThreadPoolExecutor(1, 1, 64a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei 1, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>()); 65a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei private static final Executor EXECUTOR = SMALL_POOL_EXECUTOR; 66a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei 67c7849b23a73d699b5e7f199f0a3afce5b9dee7a6Martin Hibdon public interface ContactDrawableInterface { 682b806edc62eb8e83c77edc471fda4652281a15c4James Lemieux public void onDecodeComplete(final RequestKey key, final ReusableBitmap result); 692b806edc62eb8e83c77edc471fda4652281a15c4James Lemieux public int getDecodeWidth(); 702b806edc62eb8e83c77edc471fda4652281a15c4James Lemieux public int getDecodeHeight(); 71c7849b23a73d699b5e7f199f0a3afce5b9dee7a6Martin Hibdon } 72c7849b23a73d699b5e7f199f0a3afce5b9dee7a6Martin Hibdon 73a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei public ContactResolver(final ContentResolver resolver, final BitmapCache cache) { 74a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei mResolver = resolver; 75a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei mCache = cache; 76a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei mBatch = new LinkedHashSet<ContactRequestHolder>(); 77a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei } 78a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei 79a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei @Override 80a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei public void run() { 81a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei // Start to process a new batch. 82a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei if (mBatch.isEmpty()) { 83a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei return; 84a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei } 85a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei 86a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei if (mTask != null && mTask.getStatus() == Status.RUNNING) { 87a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei LogUtils.d(TAG, "ContactResolver << batch skip"); 88a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei return; 89a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei } 90a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei 91a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei Trace.beginSection("ContactResolver run"); 92a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei LogUtils.d(TAG, "ContactResolver >> batch start"); 93a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei 94a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei // Make a copy of the batch. 95a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei LinkedHashSet<ContactRequestHolder> batch = new LinkedHashSet<ContactRequestHolder>(mBatch); 96a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei 97a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei if (mTask != null) { 98a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei mTask.cancel(true); 99a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei } 100a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei 1018913ca6aebe6017efe8060b61b8ad38eda95aa8bAndrew Sapperstein mTask = getContactResolverTask(batch); 102a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei mTask.executeOnExecutor(EXECUTOR); 103a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei Trace.endSection(); 104a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei } 105a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei 1068913ca6aebe6017efe8060b61b8ad38eda95aa8bAndrew Sapperstein protected ContactResolverTask getContactResolverTask( 1078913ca6aebe6017efe8060b61b8ad38eda95aa8bAndrew Sapperstein LinkedHashSet<ContactRequestHolder> batch) { 1088913ca6aebe6017efe8060b61b8ad38eda95aa8bAndrew Sapperstein return new ContactResolverTask(batch, mResolver, mCache, this); 1098913ca6aebe6017efe8060b61b8ad38eda95aa8bAndrew Sapperstein } 1108913ca6aebe6017efe8060b61b8ad38eda95aa8bAndrew Sapperstein 1118913ca6aebe6017efe8060b61b8ad38eda95aa8bAndrew Sapperstein public BitmapCache getCache() { 1128913ca6aebe6017efe8060b61b8ad38eda95aa8bAndrew Sapperstein return mCache; 1138913ca6aebe6017efe8060b61b8ad38eda95aa8bAndrew Sapperstein } 1148913ca6aebe6017efe8060b61b8ad38eda95aa8bAndrew Sapperstein 115c7849b23a73d699b5e7f199f0a3afce5b9dee7a6Martin Hibdon public void add(final ContactRequest request, final ContactDrawableInterface drawable) { 116a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei mBatch.add(new ContactRequestHolder(request, drawable)); 117a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei notifyBatchReady(); 118a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei } 119a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei 120c7849b23a73d699b5e7f199f0a3afce5b9dee7a6Martin Hibdon public void remove(final ContactRequest request, final ContactDrawableInterface drawable) { 121a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei mBatch.remove(new ContactRequestHolder(request, drawable)); 122a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei } 123a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei 124a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei /** 125a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei * A layout pass traverses the whole tree during a single iteration of the event loop. That 126a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei * means that every ContactDrawable on the screen will add its ContactRequest to the batch in 127a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei * a single iteration of the event loop. 128a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei * 129a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei * <p/> 130a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei * We take advantage of this by posting a Runnable (happens to be this object) at the end of 131a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei * the event queue. Every time something is added to the batch as part of the same layout pass, 132a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei * the Runnable is moved to the back of the queue. When the next layout pass occurs, 133a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei * it is placed in the event loop behind this Runnable. That allows us to process the batch 134a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei * that was added previously. 135a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei */ 136a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei private void notifyBatchReady() { 137a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei LogUtils.d(TAG, "ContactResolver > batch %d", mBatch.size()); 138a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei mHandler.removeCallbacks(this); 139a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei mHandler.post(this); 140a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei } 141a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei 142a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei /** 143a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei * This is not a very traditional AsyncTask, in the sense that we do not care about what gets 144a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei * returned in doInBackground(). Instead, we signal traditional "return values" through 145a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei * publishProgress(). 146a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei * 147a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei * <p/> 148a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei * The reason we do this is because this task is responsible for decoding an entire batch of 149a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei * ContactRequests. But, we do not want to have to wait to decode all of them before updating 150a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei * any views. So we must do all the work in doInBackground(), 151a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei * but upon finishing each individual task, we need to jump out to the UI thread and update 152a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei * that view. 153a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei */ 1548913ca6aebe6017efe8060b61b8ad38eda95aa8bAndrew Sapperstein public static class ContactResolverTask extends AsyncTask<Void, Result, Void> { 155a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei 156a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei private final Set<ContactRequestHolder> mContactRequests; 157a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei private final ContentResolver mResolver; 158a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei private final BitmapCache mCache; 159a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei private final ContactResolver mCallback; 160a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei 161a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei public ContactResolverTask(final Set<ContactRequestHolder> contactRequests, 162a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei final ContentResolver resolver, final BitmapCache cache, 163a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei final ContactResolver callback) { 164a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei mContactRequests = contactRequests; 165a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei mResolver = resolver; 166a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei mCache = cache; 167a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei mCallback = callback; 168a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei } 169a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei 170a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei @Override 171a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei protected Void doInBackground(final Void... params) { 172a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei Trace.beginSection("set up"); 173a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei final Set<String> emails = new HashSet<String>(mContactRequests.size()); 174a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei for (ContactRequestHolder request : mContactRequests) { 175a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei final String email = request.getEmail(); 176a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei emails.add(email); 177a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei } 178a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei Trace.endSection(); 179a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei 180a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei Trace.beginSection("load contact photo bytes"); 181a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei // Query the contacts provider for the current batch of emails. 1828913ca6aebe6017efe8060b61b8ad38eda95aa8bAndrew Sapperstein final ImmutableMap<String, ContactInfo> contactInfos = loadContactPhotos(emails); 183a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei Trace.endSection(); 184a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei 185a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei for (ContactRequestHolder request : mContactRequests) { 186a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei Trace.beginSection("decode"); 187a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei final String email = request.getEmail(); 188a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei if (contactInfos == null) { 189a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei // Query failed. 190a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei LogUtils.d(TAG, "ContactResolver -- failed %s", email); 191a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei publishProgress(new Result(request, null)); 192a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei Trace.endSection(); 193a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei continue; 194a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei } 195a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei 196a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei final ContactInfo contactInfo = contactInfos.get(email); 197a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei if (contactInfo == null) { 198a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei // Request skipped. Try again next batch. 199a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei LogUtils.d(TAG, "ContactResolver = skipped %s", email); 200a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei Trace.endSection(); 201a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei continue; 202a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei } 203a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei 204a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei // Query attempted. 205a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei final byte[] photo = contactInfo.photoBytes; 206a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei if (photo == null) { 207a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei // No photo bytes found. 208a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei LogUtils.d(TAG, "ContactResolver -- failed %s", email); 209a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei publishProgress(new Result(request, null)); 210a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei Trace.endSection(); 211a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei continue; 212a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei } 213a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei 214a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei // Query succeeded. Photo bytes found. 215a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei request.contactRequest.bytes = photo; 216a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei 217a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei // Start decode. 218a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei LogUtils.d(TAG, "ContactResolver ++ found %s", email); 219a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei // Synchronously decode the photo bytes. We are already in a background 220a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei // thread, and we want decodes to finish in order. The decodes are blazing 221a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei // fast so we don't need to kick off multiple threads. 2222b806edc62eb8e83c77edc471fda4652281a15c4James Lemieux final DecodeTask.DecodeOptions opts = new DecodeTask.DecodeOptions( 2232b806edc62eb8e83c77edc471fda4652281a15c4James Lemieux request.destination.getDecodeWidth(), 2242b806edc62eb8e83c77edc471fda4652281a15c4James Lemieux request.destination.getDecodeHeight(), 1 / 2f, 2252b806edc62eb8e83c77edc471fda4652281a15c4James Lemieux DecodeTask.DecodeOptions.STRATEGY_ROUND_NEAREST); 2262b806edc62eb8e83c77edc471fda4652281a15c4James Lemieux final ReusableBitmap result = new DecodeTask(request.contactRequest, opts, null, 2272b806edc62eb8e83c77edc471fda4652281a15c4James Lemieux null, mCache).decode(); 228a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei request.contactRequest.bytes = null; 229a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei 230a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei // Decode success. 231a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei publishProgress(new Result(request, result)); 232a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei Trace.endSection(); 233a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei } 234a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei 235a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei return null; 236a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei } 237a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei 2388913ca6aebe6017efe8060b61b8ad38eda95aa8bAndrew Sapperstein protected ImmutableMap<String, ContactInfo> loadContactPhotos(Set<String> emails) { 23924ab60e7864f45b10bb74105bb8a1cf1a908dbeaRégis Décamps if (mResolver == null) { 24024ab60e7864f45b10bb74105bb8a1cf1a908dbeaRégis Décamps return null; 24124ab60e7864f45b10bb74105bb8a1cf1a908dbeaRégis Décamps } 2428913ca6aebe6017efe8060b61b8ad38eda95aa8bAndrew Sapperstein return SenderInfoLoader.loadContactPhotos(mResolver, emails, false /* decodeBitmaps */); 2438913ca6aebe6017efe8060b61b8ad38eda95aa8bAndrew Sapperstein } 2448913ca6aebe6017efe8060b61b8ad38eda95aa8bAndrew Sapperstein 245a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei /** 246a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei * We use progress updates to jump to the UI thread so we can decode the batch 247a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei * incrementally. 248a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei */ 249a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei @Override 250a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei protected void onProgressUpdate(final Result... values) { 251a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei final ContactRequestHolder request = values[0].request; 252a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei final ReusableBitmap bitmap = values[0].bitmap; 253a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei 254a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei // DecodeTask does not add null results to the cache. 25524ab60e7864f45b10bb74105bb8a1cf1a908dbeaRégis Décamps if (bitmap == null && mCache != null) { 256a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei // Cache null result. 257a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei mCache.put(request.contactRequest, null); 258a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei } 259a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei 260a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei request.destination.onDecodeComplete(request.contactRequest, bitmap); 261a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei } 262a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei 263a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei @Override 264a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei protected void onPostExecute(final Void aVoid) { 265a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei // Batch completed. Start next batch. 266a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei mCallback.notifyBatchReady(); 267a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei } 268a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei } 269a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei 270a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei /** 271a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei * Wrapper for the ContactRequest and its decoded bitmap. This class is used to pass results 272a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei * to onProgressUpdate(). 273a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei */ 274a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei private static class Result { 275a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei public final ContactRequestHolder request; 276a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei public final ReusableBitmap bitmap; 277a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei 278a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei private Result(final ContactRequestHolder request, final ReusableBitmap bitmap) { 279a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei this.request = request; 280a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei this.bitmap = bitmap; 281a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei } 282a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei } 283a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei} 284