blob: b90cf1f028606b51911217700942eb4524a40d41 [file] [log] [blame]
/*
* Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.contacts.util;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.TransitionDrawable;
import android.media.ThumbnailUtils;
import android.text.TextUtils;
import android.widget.ImageView;
import com.android.contacts.ContactPhotoManager;
import com.android.contacts.ContactPhotoManager.DefaultImageRequest;
import com.android.contacts.lettertiles.LetterTileDrawable;
import com.android.contacts.model.Contact;
import java.util.Arrays;
/**
* Initialized with a target ImageView. When provided with a compressed image
* (i.e. a byte[]), it appropriately updates the ImageView's Drawable.
*/
public class ImageViewDrawableSetter {
private ImageView mTarget;
private byte[] mCompressed;
private Drawable mPreviousDrawable;
private int mDurationInMillis = 0;
private Contact mContact;
private static final String TAG = "ImageViewDrawableSetter";
public ImageViewDrawableSetter() {
}
public ImageViewDrawableSetter(ImageView target) {
mTarget = target;
}
public Bitmap setupContactPhoto(Contact contactData, ImageView photoView) {
mContact = contactData;
setTarget(photoView);
return setCompressedImage(contactData.getPhotoBinaryData());
}
public void setTransitionDuration(int durationInMillis) {
mDurationInMillis = durationInMillis;
}
public ImageView getTarget() {
return mTarget;
}
/**
* Re-initialize to use new target. As a result, the next time a new image
* is set, it will immediately be applied to the target (there will be no
* fade transition).
*/
protected void setTarget(ImageView target) {
if (mTarget != target) {
mTarget = target;
mCompressed = null;
mPreviousDrawable = null;
}
}
protected byte[] getCompressedImage() {
return mCompressed;
}
protected Bitmap setCompressedImage(byte[] compressed) {
if (mPreviousDrawable == null) {
// If we don't already have a drawable, skip the exit-early test
// below; otherwise we might not end up setting the default image.
} else if (mPreviousDrawable != null
&& mPreviousDrawable instanceof BitmapDrawable
&& Arrays.equals(mCompressed, compressed)) {
// TODO: the worst case is when the arrays are equal but not
// identical. This takes about 1ms (more with high-res photos). A
// possible optimization is to sparsely sample chunks of the arrays
// to compare.
return previousBitmap();
}
Drawable newDrawable = decodedBitmapDrawable(compressed);
if (newDrawable == null) {
newDrawable = defaultDrawable();
}
// Remember this for next time, so that we can check if it changed.
mCompressed = compressed;
// If we don't have a new Drawable, something went wrong... bail out.
if (newDrawable == null) return previousBitmap();
if (mPreviousDrawable == null || mDurationInMillis == 0) {
// Set the new one immediately.
mTarget.setImageDrawable(newDrawable);
} else {
// Set up a transition from the previous Drawable to the new one.
final Drawable[] beforeAndAfter = new Drawable[2];
beforeAndAfter[0] = mPreviousDrawable;
beforeAndAfter[1] = newDrawable;
final TransitionDrawable transition = new TransitionDrawable(beforeAndAfter);
mTarget.setImageDrawable(transition);
transition.startTransition(mDurationInMillis);
}
// Remember this for next time, so that we can transition from it to the
// new one.
mPreviousDrawable = newDrawable;
return previousBitmap();
}
private Bitmap previousBitmap() {
return (mPreviousDrawable == null) ? null
: mPreviousDrawable instanceof LetterTileDrawable ? null
: ((BitmapDrawable) mPreviousDrawable).getBitmap();
}
/**
* Obtain the default drawable for a contact when no photo is available. If this is a local
* contact, then use the contact's display name and lookup key (as a unique identifier) to
* retrieve a default drawable for this contact. If not, then use the name as the contact
* identifier instead.
*/
private Drawable defaultDrawable() {
Resources resources = mTarget.getResources();
DefaultImageRequest request;
int contactType = ContactPhotoManager.TYPE_DEFAULT;
if (mContact.isDisplayNameFromOrganization()) {
contactType = ContactPhotoManager.TYPE_BUSINESS;
}
if (TextUtils.isEmpty(mContact.getLookupKey())) {
request = new DefaultImageRequest(null, mContact.getDisplayName(), contactType,
false /* isCircular */);
} else {
request = new DefaultImageRequest(mContact.getDisplayName(), mContact.getLookupKey(),
contactType, false /* isCircular */);
}
return ContactPhotoManager.getDefaultAvatarDrawableForContact(resources, true, request);
}
private BitmapDrawable decodedBitmapDrawable(byte[] compressed) {
if (compressed == null) {
return null;
}
final Resources rsrc = mTarget.getResources();
Bitmap bitmap = BitmapFactory.decodeByteArray(compressed, 0, compressed.length);
if (bitmap == null) {
return null;
}
if (bitmap.getHeight() != bitmap.getWidth()) {
// Crop the bitmap into a square.
final int size = Math.min(bitmap.getWidth(), bitmap.getHeight());
bitmap = ThumbnailUtils.extractThumbnail(bitmap, size, size);
}
return new BitmapDrawable(rsrc, bitmap);
}
}