ContactResolver.java revision a8301e2eb5a083a73f58331279c86e8ec7b11a48
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 25a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Weiimport com.android.bitmap.BitmapCache; 26a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Weiimport com.android.bitmap.DecodeTask; 27a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Weiimport com.android.bitmap.ReusableBitmap; 28a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Weiimport com.android.ex.photo.util.Trace; 29a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Weiimport com.android.mail.ContactInfo; 30a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Weiimport com.android.mail.SenderInfoLoader; 31a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Weiimport com.android.mail.bitmap.ContactRequest.ContactRequestHolder; 32a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Weiimport com.android.mail.utils.LogTag; 33a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Weiimport com.android.mail.utils.LogUtils; 34a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Weiimport com.google.common.collect.ImmutableMap; 35a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei 36a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Weiimport java.util.HashSet; 37a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Weiimport java.util.LinkedHashSet; 38a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Weiimport java.util.Set; 39a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Weiimport java.util.concurrent.Executor; 40a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Weiimport java.util.concurrent.LinkedBlockingQueue; 41a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Weiimport java.util.concurrent.ThreadPoolExecutor; 42a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Weiimport java.util.concurrent.TimeUnit; 43a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei 44a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei/** 45a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei * Batches up ContactRequests so we can efficiently query the contacts provider. Kicks off a 46a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei * ContactResolverTask to query for contact images in the background. 47a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei */ 48a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Weipublic class ContactResolver implements Runnable { 49a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei 50a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei private static final String TAG = LogTag.getLogTag(); 51a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei 52a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei private final ContentResolver mResolver; 53a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei private final BitmapCache mCache; 54a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei /** Insertion ordered set allows us to work from the top down. */ 55a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei private final LinkedHashSet<ContactRequestHolder> mBatch; 56a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei 57a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei private final Handler mHandler = new Handler(); 58a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei private ContactResolverTask mTask; 59a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei 60a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei 61a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei /** Size 1 pool mostly to make systrace output traces on one line. */ 62a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei private static final Executor SMALL_POOL_EXECUTOR = new ThreadPoolExecutor(1, 1, 63a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei 1, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>()); 64a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei private static final Executor EXECUTOR = SMALL_POOL_EXECUTOR; 65a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei 66a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei public ContactResolver(final ContentResolver resolver, final BitmapCache cache) { 67a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei mResolver = resolver; 68a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei mCache = cache; 69a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei mBatch = new LinkedHashSet<ContactRequestHolder>(); 70a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei } 71a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei 72a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei @Override 73a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei public void run() { 74a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei // Start to process a new batch. 75a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei if (mBatch.isEmpty()) { 76a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei return; 77a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei } 78a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei 79a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei if (mTask != null && mTask.getStatus() == Status.RUNNING) { 80a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei LogUtils.d(TAG, "ContactResolver << batch skip"); 81a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei return; 82a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei } 83a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei 84a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei Trace.beginSection("ContactResolver run"); 85a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei LogUtils.d(TAG, "ContactResolver >> batch start"); 86a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei 87a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei // Make a copy of the batch. 88a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei LinkedHashSet<ContactRequestHolder> batch = new LinkedHashSet<ContactRequestHolder>(mBatch); 89a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei 90a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei if (mTask != null) { 91a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei mTask.cancel(true); 92a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei } 93a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei 94a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei mTask = new ContactResolverTask(batch, mResolver, mCache, this); 95a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei mTask.executeOnExecutor(EXECUTOR); 96a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei Trace.endSection(); 97a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei } 98a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei 99a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei public void add(final ContactRequest request, final ContactDrawable drawable) { 100a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei mBatch.add(new ContactRequestHolder(request, drawable)); 101a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei notifyBatchReady(); 102a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei } 103a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei 104a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei public void remove(final ContactRequest request, final ContactDrawable drawable) { 105a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei mBatch.remove(new ContactRequestHolder(request, drawable)); 106a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei } 107a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei 108a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei /** 109a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei * A layout pass traverses the whole tree during a single iteration of the event loop. That 110a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei * means that every ContactDrawable on the screen will add its ContactRequest to the batch in 111a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei * a single iteration of the event loop. 112a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei * 113a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei * <p/> 114a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei * We take advantage of this by posting a Runnable (happens to be this object) at the end of 115a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei * the event queue. Every time something is added to the batch as part of the same layout pass, 116a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei * the Runnable is moved to the back of the queue. When the next layout pass occurs, 117a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei * it is placed in the event loop behind this Runnable. That allows us to process the batch 118a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei * that was added previously. 119a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei */ 120a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei private void notifyBatchReady() { 121a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei LogUtils.d(TAG, "ContactResolver > batch %d", mBatch.size()); 122a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei mHandler.removeCallbacks(this); 123a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei mHandler.post(this); 124a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei } 125a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei 126a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei /** 127a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei * This is not a very traditional AsyncTask, in the sense that we do not care about what gets 128a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei * returned in doInBackground(). Instead, we signal traditional "return values" through 129a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei * publishProgress(). 130a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei * 131a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei * <p/> 132a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei * The reason we do this is because this task is responsible for decoding an entire batch of 133a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei * ContactRequests. But, we do not want to have to wait to decode all of them before updating 134a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei * any views. So we must do all the work in doInBackground(), 135a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei * but upon finishing each individual task, we need to jump out to the UI thread and update 136a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei * that view. 137a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei */ 138a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei private static class ContactResolverTask extends AsyncTask<Void, Result, Void> { 139a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei 140a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei private final Set<ContactRequestHolder> mContactRequests; 141a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei private final ContentResolver mResolver; 142a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei private final BitmapCache mCache; 143a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei private final ContactResolver mCallback; 144a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei 145a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei public ContactResolverTask(final Set<ContactRequestHolder> contactRequests, 146a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei final ContentResolver resolver, final BitmapCache cache, 147a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei final ContactResolver callback) { 148a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei mContactRequests = contactRequests; 149a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei mResolver = resolver; 150a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei mCache = cache; 151a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei mCallback = callback; 152a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei } 153a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei 154a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei @Override 155a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei protected Void doInBackground(final Void... params) { 156a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei Trace.beginSection("set up"); 157a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei final Set<String> emails = new HashSet<String>(mContactRequests.size()); 158a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei for (ContactRequestHolder request : mContactRequests) { 159a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei final String email = request.getEmail(); 160a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei emails.add(email); 161a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei } 162a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei Trace.endSection(); 163a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei 164a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei Trace.beginSection("load contact photo bytes"); 165a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei // Query the contacts provider for the current batch of emails. 166a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei ImmutableMap<String, ContactInfo> contactInfos = SenderInfoLoader 167a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei .loadContactPhotos(mResolver, emails, false /* decodeBitmaps */); 168a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei Trace.endSection(); 169a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei 170a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei for (ContactRequestHolder request : mContactRequests) { 171a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei Trace.beginSection("decode"); 172a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei final String email = request.getEmail(); 173a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei if (contactInfos == null) { 174a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei // Query failed. 175a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei LogUtils.d(TAG, "ContactResolver -- failed %s", email); 176a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei publishProgress(new Result(request, null)); 177a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei Trace.endSection(); 178a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei continue; 179a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei } 180a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei 181a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei final ContactInfo contactInfo = contactInfos.get(email); 182a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei if (contactInfo == null) { 183a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei // Request skipped. Try again next batch. 184a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei LogUtils.d(TAG, "ContactResolver = skipped %s", email); 185a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei Trace.endSection(); 186a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei continue; 187a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei } 188a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei 189a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei // Query attempted. 190a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei final byte[] photo = contactInfo.photoBytes; 191a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei if (photo == null) { 192a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei // No photo bytes found. 193a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei LogUtils.d(TAG, "ContactResolver -- failed %s", email); 194a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei publishProgress(new Result(request, null)); 195a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei Trace.endSection(); 196a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei continue; 197a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei } 198a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei 199a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei // Query succeeded. Photo bytes found. 200a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei request.contactRequest.bytes = photo; 201a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei 202a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei // Start decode. 203a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei LogUtils.d(TAG, "ContactResolver ++ found %s", email); 204a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei final ReusableBitmap result; 205a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei final int width = mCache.getDecodeWidth(); 206a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei final int height = mCache.getDecodeHeight(); 207a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei // Synchronously decode the photo bytes. We are already in a background 208a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei // thread, and we want decodes to finish in order. The decodes are blazing 209a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei // fast so we don't need to kick off multiple threads. 210a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei result = new DecodeTask(request.contactRequest, width, height, width, height, null, 211a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei mCache).decode(); 212a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei request.contactRequest.bytes = null; 213a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei 214a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei // Decode success. 215a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei publishProgress(new Result(request, result)); 216a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei Trace.endSection(); 217a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei } 218a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei 219a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei return null; 220a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei } 221a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei 222a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei /** 223a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei * We use progress updates to jump to the UI thread so we can decode the batch 224a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei * incrementally. 225a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei */ 226a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei @Override 227a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei protected void onProgressUpdate(final Result... values) { 228a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei final ContactRequestHolder request = values[0].request; 229a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei final ReusableBitmap bitmap = values[0].bitmap; 230a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei 231a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei // DecodeTask does not add null results to the cache. 232a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei if (bitmap == null) { 233a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei // Cache null result. 234a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei mCache.put(request.contactRequest, null); 235a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei } 236a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei 237a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei request.destination.onDecodeComplete(request.contactRequest, bitmap); 238a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei } 239a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei 240a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei @Override 241a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei protected void onPostExecute(final Void aVoid) { 242a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei // Batch completed. Start next batch. 243a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei mCallback.notifyBatchReady(); 244a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei } 245a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei } 246a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei 247a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei /** 248a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei * Wrapper for the ContactRequest and its decoded bitmap. This class is used to pass results 249a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei * to onProgressUpdate(). 250a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei */ 251a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei private static class Result { 252a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei public final ContactRequestHolder request; 253a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei public final ReusableBitmap bitmap; 254a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei 255a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei private Result(final ContactRequestHolder request, final ReusableBitmap bitmap) { 256a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei this.request = request; 257a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei this.bitmap = bitmap; 258a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei } 259a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei } 260a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei} 261