19758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Gargus/* 29758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Gargus * Copyright (C) 2012 The Android Open Source Project 39758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Gargus * 49758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Gargus * Licensed under the Apache License, Version 2.0 (the "License"); 59758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Gargus * you may not use this file except in compliance with the License. 69758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Gargus * You may obtain a copy of the License at 79758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Gargus * 89758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Gargus * http://www.apache.org/licenses/LICENSE-2.0 99758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Gargus * 109758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Gargus * Unless required by applicable law or agreed to in writing, software 119758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Gargus * distributed under the License is distributed on an "AS IS" BASIS, 129758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Gargus * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 139758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Gargus * See the License for the specific language governing permissions and 149758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Gargus * limitations under the License. 159758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Gargus */ 169758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Gargus 179758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Garguspackage com.android.contacts.util; 189758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Gargus 199758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Gargusimport android.content.res.Resources; 209758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Gargusimport android.content.res.Resources.NotFoundException; 219758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Gargusimport android.graphics.Bitmap; 229758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Gargusimport android.graphics.BitmapFactory; 239758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Gargusimport android.graphics.drawable.BitmapDrawable; 249758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Gargusimport android.graphics.drawable.Drawable; 259758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Gargusimport android.graphics.drawable.TransitionDrawable; 26b00ca40641bfa0f8056edae7420b7f4cf713b5a1Yorke Leeimport android.provider.ContactsContract.DisplayNameSources; 27b00ca40641bfa0f8056edae7420b7f4cf713b5a1Yorke Leeimport android.text.TextUtils; 289758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Gargusimport android.util.Log; 299758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Gargusimport android.widget.ImageView; 309758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Gargus 3179a6b5d3a885bc508b4b98c92a946fe12643c444Chiao Chengimport com.android.contacts.common.ContactPhotoManager; 32b00ca40641bfa0f8056edae7420b7f4cf713b5a1Yorke Leeimport com.android.contacts.common.ContactPhotoManager.DefaultImageRequest; 33b00ca40641bfa0f8056edae7420b7f4cf713b5a1Yorke Leeimport com.android.contacts.common.lettertiles.LetterTileDrawable; 34cd321f65f1e50409812976380ad1f0fdb3fa35cbYorke Leeimport com.android.contacts.common.model.Contact; 35e0b2f1e2d01d1ac52ba207dc7ce76971d853298eChiao Cheng 369758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Gargusimport java.util.Arrays; 379758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Gargus 389758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Gargus/** 399758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Gargus * Initialized with a target ImageView. When provided with a compressed image 409758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Gargus * (i.e. a byte[]), it appropriately updates the ImageView's Drawable. 419758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Gargus */ 429758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Garguspublic class ImageViewDrawableSetter { 439758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Gargus private ImageView mTarget; 449758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Gargus private byte[] mCompressed; 459758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Gargus private Drawable mPreviousDrawable; 466e607d54ce08ebcc78d94963646a42605697f132Maurice Chu private int mDurationInMillis = 0; 47b00ca40641bfa0f8056edae7420b7f4cf713b5a1Yorke Lee private Contact mContact; 489758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Gargus private static final String TAG = "ImageViewDrawableSetter"; 499758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Gargus 509758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Gargus public ImageViewDrawableSetter() { 519758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Gargus } 529758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Gargus 539758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Gargus public ImageViewDrawableSetter(ImageView target) { 549758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Gargus mTarget = target; 559758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Gargus } 569758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Gargus 57b00ca40641bfa0f8056edae7420b7f4cf713b5a1Yorke Lee public Bitmap setupContactPhoto(Contact contactData, ImageView photoView) { 58b00ca40641bfa0f8056edae7420b7f4cf713b5a1Yorke Lee mContact = contactData; 599758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Gargus setTarget(photoView); 60b00ca40641bfa0f8056edae7420b7f4cf713b5a1Yorke Lee return setCompressedImage(contactData.getPhotoBinaryData()); 619758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Gargus } 629758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Gargus 636e607d54ce08ebcc78d94963646a42605697f132Maurice Chu public void setTransitionDuration(int durationInMillis) { 646e607d54ce08ebcc78d94963646a42605697f132Maurice Chu mDurationInMillis = durationInMillis; 656e607d54ce08ebcc78d94963646a42605697f132Maurice Chu } 666e607d54ce08ebcc78d94963646a42605697f132Maurice Chu 67187c8167d77687fbc04237c9ac1e87564b2d5f33Josh Gargus public ImageView getTarget() { 68187c8167d77687fbc04237c9ac1e87564b2d5f33Josh Gargus return mTarget; 699758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Gargus } 709758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Gargus 719758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Gargus /** 729758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Gargus * Re-initialize to use new target. As a result, the next time a new image 739758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Gargus * is set, it will immediately be applied to the target (there will be no 749758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Gargus * fade transition). 759758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Gargus */ 76187c8167d77687fbc04237c9ac1e87564b2d5f33Josh Gargus protected void setTarget(ImageView target) { 779758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Gargus if (mTarget != target) { 789758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Gargus mTarget = target; 799758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Gargus mCompressed = null; 809758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Gargus mPreviousDrawable = null; 819758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Gargus } 829758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Gargus } 839758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Gargus 84187c8167d77687fbc04237c9ac1e87564b2d5f33Josh Gargus protected byte[] getCompressedImage() { 85187c8167d77687fbc04237c9ac1e87564b2d5f33Josh Gargus return mCompressed; 86187c8167d77687fbc04237c9ac1e87564b2d5f33Josh Gargus } 87187c8167d77687fbc04237c9ac1e87564b2d5f33Josh Gargus 88187c8167d77687fbc04237c9ac1e87564b2d5f33Josh Gargus protected Bitmap setCompressedImage(byte[] compressed) { 899758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Gargus if (mPreviousDrawable == null) { 909758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Gargus // If we don't already have a drawable, skip the exit-early test 919758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Gargus // below; otherwise we might not end up setting the default image. 929758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Gargus } else if (mPreviousDrawable != null && Arrays.equals(mCompressed, compressed)) { 939758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Gargus // TODO: the worst case is when the arrays are equal but not 949758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Gargus // identical. This takes about 1ms (more with high-res photos). A 959758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Gargus // possible optimization is to sparsely sample chunks of the arrays 969758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Gargus // to compare. 979758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Gargus return previousBitmap(); 989758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Gargus } 999758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Gargus 1009758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Gargus final Drawable newDrawable = (compressed == null) 1019758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Gargus ? defaultDrawable() 1029758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Gargus : decodedBitmapDrawable(compressed); 1039758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Gargus 1049758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Gargus // Remember this for next time, so that we can check if it changed. 1059758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Gargus mCompressed = compressed; 1069758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Gargus 1079758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Gargus // If we don't have a new Drawable, something went wrong... bail out. 1089758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Gargus if (newDrawable == null) return previousBitmap(); 1099758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Gargus 1106e607d54ce08ebcc78d94963646a42605697f132Maurice Chu if (mPreviousDrawable == null || mDurationInMillis == 0) { 1119758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Gargus // Set the new one immediately. 1129758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Gargus mTarget.setImageDrawable(newDrawable); 1139758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Gargus } else { 1149758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Gargus // Set up a transition from the previous Drawable to the new one. 1159758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Gargus final Drawable[] beforeAndAfter = new Drawable[2]; 1169758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Gargus beforeAndAfter[0] = mPreviousDrawable; 1179758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Gargus beforeAndAfter[1] = newDrawable; 1189758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Gargus final TransitionDrawable transition = new TransitionDrawable(beforeAndAfter); 1199758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Gargus mTarget.setImageDrawable(transition); 1206e607d54ce08ebcc78d94963646a42605697f132Maurice Chu transition.startTransition(mDurationInMillis); 1219758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Gargus } 1229758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Gargus 1239758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Gargus // Remember this for next time, so that we can transition from it to the 1249758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Gargus // new one. 1259758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Gargus mPreviousDrawable = newDrawable; 1269758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Gargus 1279758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Gargus return previousBitmap(); 1289758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Gargus } 1299758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Gargus 1309758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Gargus private Bitmap previousBitmap() { 131b00ca40641bfa0f8056edae7420b7f4cf713b5a1Yorke Lee return (mPreviousDrawable == null) ? null 132b00ca40641bfa0f8056edae7420b7f4cf713b5a1Yorke Lee : mPreviousDrawable instanceof LetterTileDrawable ? null 1339758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Gargus : ((BitmapDrawable) mPreviousDrawable).getBitmap(); 1349758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Gargus } 1359758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Gargus 1369758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Gargus /** 137b00ca40641bfa0f8056edae7420b7f4cf713b5a1Yorke Lee * Obtain the default drawable for a contact when no photo is available. If this is a local 138b00ca40641bfa0f8056edae7420b7f4cf713b5a1Yorke Lee * contact, then use the contact's display name and lookup key (as a unique identifier) to 139b00ca40641bfa0f8056edae7420b7f4cf713b5a1Yorke Lee * retrieve a default drawable for this contact. If not, then use the name as the contact 140b00ca40641bfa0f8056edae7420b7f4cf713b5a1Yorke Lee * identifier instead. 1419758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Gargus */ 1429758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Gargus private Drawable defaultDrawable() { 1439758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Gargus Resources resources = mTarget.getResources(); 144b00ca40641bfa0f8056edae7420b7f4cf713b5a1Yorke Lee DefaultImageRequest request; 145b00ca40641bfa0f8056edae7420b7f4cf713b5a1Yorke Lee int contactType = ContactPhotoManager.TYPE_DEFAULT; 146b00ca40641bfa0f8056edae7420b7f4cf713b5a1Yorke Lee 147b00ca40641bfa0f8056edae7420b7f4cf713b5a1Yorke Lee if (mContact.isDisplayNameFromOrganization()) { 148b00ca40641bfa0f8056edae7420b7f4cf713b5a1Yorke Lee contactType = ContactPhotoManager.TYPE_BUSINESS; 1499758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Gargus } 150b00ca40641bfa0f8056edae7420b7f4cf713b5a1Yorke Lee 151b00ca40641bfa0f8056edae7420b7f4cf713b5a1Yorke Lee if (TextUtils.isEmpty(mContact.getLookupKey())) { 152b00ca40641bfa0f8056edae7420b7f4cf713b5a1Yorke Lee request = new DefaultImageRequest(null, mContact.getDisplayName(), contactType); 153b00ca40641bfa0f8056edae7420b7f4cf713b5a1Yorke Lee } else { 154b00ca40641bfa0f8056edae7420b7f4cf713b5a1Yorke Lee request = new DefaultImageRequest(mContact.getDisplayName(), mContact.getLookupKey(), 155b00ca40641bfa0f8056edae7420b7f4cf713b5a1Yorke Lee contactType); 156b00ca40641bfa0f8056edae7420b7f4cf713b5a1Yorke Lee } 157b00ca40641bfa0f8056edae7420b7f4cf713b5a1Yorke Lee return ContactPhotoManager.getDefaultAvatarDrawableForContact(resources, true, request); 1589758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Gargus } 1599758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Gargus 1609758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Gargus private BitmapDrawable decodedBitmapDrawable(byte[] compressed) { 1619758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Gargus Resources rsrc = mTarget.getResources(); 1629758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Gargus Bitmap bitmap = BitmapFactory.decodeByteArray(compressed, 0, compressed.length); 1639758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Gargus return new BitmapDrawable(rsrc, bitmap); 1649758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Gargus } 1659758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Gargus} 166