1 /* 2 * Copyright (C) 2015 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 package com.android.car.dialer.telecom; 17 18 import android.content.ContentResolver; 19 import android.graphics.Bitmap; 20 import android.os.AsyncTask; 21 import android.support.annotation.MainThread; 22 import android.support.annotation.Nullable; 23 import android.widget.ImageView; 24 25 import java.lang.ref.WeakReference; 26 27 /** 28 * Helper task that retrieves a Contact photo from the local Contacts store. The loading task 29 * is tied to an ImageView that allows a lightweight management of the task upon update of the view. 30 * 31 * TODO(mcrico): Using a View's TAG to store and manage Async task loading is pretty brittle. 32 * Vanagon is not depending on this logic and projected shouldn't either. 33 */ 34 public class ContactBitmapWorker extends AsyncTask<Void, Void, Bitmap> { 35 private final WeakReference<ImageView> mImageViewReference; 36 private final WeakReference<ContentResolver> mContentResolverReference; 37 private final String mNumber; 38 private final BitmapWorkerListener mListener; 39 40 /** Interface to receive updates from this worker */ 41 public interface BitmapWorkerListener { 42 /** Called in the main thread upon bitmap load finish */ 43 @MainThread onBitmapLoaded(@ullable Bitmap bitmap)44 void onBitmapLoaded(@Nullable Bitmap bitmap); 45 } 46 47 /** 48 * @return A worker task if a new one was needed to load the bitmap. 49 */ loadBitmap( ContentResolver contentResolver, ImageView imageView, String number, BitmapWorkerListener listener)50 @Nullable public static ContactBitmapWorker loadBitmap( 51 ContentResolver contentResolver, 52 ImageView imageView, 53 String number, 54 BitmapWorkerListener listener) { 55 56 // This work may be underway already. 57 if (!cancelPotentialWork(number, imageView)) { 58 return null; 59 } 60 61 ContactBitmapWorker task = 62 new ContactBitmapWorker(contentResolver, imageView, number, listener); 63 imageView.setTag(task); 64 imageView.setImageResource(0); 65 task.execute(); 66 return task; 67 } 68 69 /** Use {@link #loadBitmap} instead, as it guarantees de-duplication of work */ ContactBitmapWorker( ContentResolver contentResolver, ImageView imageView, String number, BitmapWorkerListener listener)70 private ContactBitmapWorker( 71 ContentResolver contentResolver, 72 ImageView imageView, 73 String number, 74 BitmapWorkerListener listener) { 75 mImageViewReference = new WeakReference<>(imageView); 76 mContentResolverReference = new WeakReference<>(contentResolver); 77 mNumber = number; 78 mListener = listener; 79 } 80 81 @Override doInBackground(Void... voids)82 protected Bitmap doInBackground(Void... voids) { 83 final ContentResolver contentResolver = mContentResolverReference.get(); 84 if (contentResolver != null) { 85 return TelecomUtils.getContactPhotoFromNumber(contentResolver, mNumber); 86 } 87 return null; 88 } 89 90 @Override onPostExecute(Bitmap bitmap)91 protected void onPostExecute(Bitmap bitmap) { 92 if (isCancelled()) { 93 return; 94 } 95 96 if (mImageViewReference.get() != null) { 97 mListener.onBitmapLoaded(bitmap); 98 } 99 } 100 101 /** 102 * @return Whether a new Bitmap loading should continue for this imageView. 103 */ cancelPotentialWork(String number, ImageView imageView)104 private static boolean cancelPotentialWork(String number, ImageView imageView) { 105 final ContactBitmapWorker bitmapWorkerTask = (ContactBitmapWorker) imageView.getTag(); 106 if (bitmapWorkerTask != null) { 107 if (bitmapWorkerTask.mNumber != number) { 108 bitmapWorkerTask.cancel(true); 109 imageView.setTag(null); 110 } else { 111 // The same work is already in progress 112 return false; 113 } 114 } 115 116 return true; 117 } 118 } 119