org.tigase.mobile.utils.AvatarHelper.java Source code

Java tutorial

Introduction

Here is the source code for org.tigase.mobile.utils.AvatarHelper.java

Source

/*
 * Tigase Mobile Messenger for Android
 * Copyright (C) 2011-2013 "Artur Hefczyc" <artur.hefczyc@tigase.org>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, version 3 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program. Look for COPYING file in the top folder.
 * If not, see http://www.gnu.org/licenses/.
 */
package org.tigase.mobile.utils;

import java.io.InputStream;

import org.tigase.mobile.R;
import org.tigase.mobile.db.VCardsCacheTableMetaData;
import org.tigase.mobile.db.providers.RosterProvider;
import org.tigase.mobile.sync.SyncAdapter;

import tigase.jaxmpp.core.client.BareJID;
import android.annotation.TargetApi;
import android.content.Context;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Build;
import android.provider.ContactsContract;
import android.support.v4.util.LruCache;
import android.util.Log;
import android.widget.ImageView;

//import tigase.jaxmpp.R;

public class AvatarHelper {

    private static LruCache<BareJID, Bitmap> avatarCache;

    private static Context context;
    private static int defaultAvatarSize = 50;
    private static float density = 1;
    public static Bitmap mPlaceHolderBitmap;
    private static final String TAG = "AvatarHelper";

    private static int calculateSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
        final int height = options.outHeight;
        final int width = options.outWidth;
        int inSampleSize = 1;

        if (height > reqHeight || width > reqWidth) {
            if (width > height) {
                inSampleSize = Math.round((float) height / (float) reqHeight);
            } else {
                inSampleSize = Math.round((float) width / (float) reqWidth);
            }
        }
        int scale = 1;
        while (inSampleSize > scale) {
            scale *= 2;
        }
        // is it needed?
        // if (inSampleSize < scale) {
        // scale /= 2;
        // }
        return scale;
        // return inSampleSize;
    }

    public static boolean cancelPotentialWork(BareJID jid, ImageView imageView) {
        final BitmapWorkerTask bitmapWorkerTask = getBitmapWorkerTask(imageView);

        if (bitmapWorkerTask != null) {
            final BareJID bitmapData = bitmapWorkerTask.data;
            if (!jid.equals(bitmapData)) {
                // Cancel previous task
                bitmapWorkerTask.cancel(true);
            } else {
                // The same work is already in progress
                return false;
            }
        }
        // No task associated with the ImageView, or an existing task was
        // cancelled
        return true;
    }

    public static void clearAvatar(BareJID jid) {
        avatarCache.remove(jid);
    }

    public static Bitmap getAvatar(BareJID jid) {
        Bitmap bmp = avatarCache.get(jid);
        if (bmp == null) {
            bmp = loadAvatar(jid);
        }
        return bmp;
    }

    protected static BitmapWorkerTask getBitmapWorkerTask(ImageView imageView) {
        if (imageView != null) {
            final Drawable drawable = imageView.getDrawable();
            if (drawable instanceof AsyncDrawable) {
                final AsyncDrawable asyncDrawable = (AsyncDrawable) drawable;
                return asyncDrawable.getBitmapWorkerTask();
            }
        }
        return null;
    }

    public static void initilize(Context context_) {
        if (avatarCache == null) {
            context = context_;

            density = context.getResources().getDisplayMetrics().density;
            defaultAvatarSize = Math.round(density * 50);

            // Get memory class of this device, exceeding this amount will throw
            // an
            // OutOfMemory exception.
            final int memClass = ((android.app.ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE))
                    .getMemoryClass();

            // Use 1/8th of the available memory for this memory cache.
            final int cacheSize = 1024 * 1024 * memClass / 8;

            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR1) {
                avatarCache = new LruCache<BareJID, Bitmap>(cacheSize) {
                    @TargetApi(12)
                    @Override
                    protected int sizeOf(BareJID key, Bitmap bitmap) {
                        // The cache size will be measured in bytes rather than
                        // number of items. Ignoring placeholder bitmap as well.
                        return bitmap == mPlaceHolderBitmap ? 0 : bitmap.getByteCount();
                    }
                };
            } else {
                // below SDK 12 there is no getByteCount method
                avatarCache = new LruCache<BareJID, Bitmap>(cacheSize) {
                    @Override
                    protected int sizeOf(BareJID key, Bitmap bitmap) {
                        // The cache size will be measured in bytes rather than
                        // number of items. Ignoring placeholder bitmap as well.
                        return bitmap == mPlaceHolderBitmap ? 0 : (bitmap.getRowBytes() * bitmap.getHeight());
                    }
                };
            }

            mPlaceHolderBitmap = BitmapFactory.decodeResource(context.getResources(), R.drawable.user_avatar);
        }
    }

    protected static Bitmap loadAvatar(BareJID jid) {
        Bitmap bmp = loadAvatar(jid, defaultAvatarSize);
        if (bmp == null) {
            avatarCache.put(jid, mPlaceHolderBitmap);
        } else {
            avatarCache.put(jid, bmp);
        }
        return bmp;
    }

    protected static Bitmap loadAvatar(BareJID jid, int size) {
        Bitmap bmp = null;

        Log.v(TAG, "loading avatar with size " + size);

        Cursor cursor = context.getContentResolver().query(
                Uri.parse(RosterProvider.VCARD_URI + "/" + Uri.encode(jid.toString())), null, null, null, null);
        try {
            if (cursor.moveToNext()) {
                // we found avatar in our store
                byte[] avatar = cursor.getBlob(cursor.getColumnIndex(VCardsCacheTableMetaData.FIELD_DATA));
                if (avatar != null) {
                    BitmapFactory.Options options = new BitmapFactory.Options();
                    options.inJustDecodeBounds = true;
                    Bitmap bmp1 = BitmapFactory.decodeByteArray(avatar, 0, avatar.length, options);
                    if (bmp1 != null) {
                        bmp1.recycle();
                    }
                    // options.inSampleSize = calculateSize(options, 96, 96);
                    options.inPreferredConfig = Bitmap.Config.ARGB_8888;
                    options.inSampleSize = calculateSize(options, size, size);
                    options.inJustDecodeBounds = false;
                    bmp = BitmapFactory.decodeByteArray(avatar, 0, avatar.length, options);
                }
            } else {
                // no avatar in our store - checking for avatar in Android
                // contacts
                Uri photoUri = SyncAdapter.getAvatarUriFromContacts(context.getContentResolver(), jid);
                if (photoUri != null) {
                    InputStream input = ContactsContract.Contacts
                            .openContactPhotoInputStream(context.getContentResolver(), photoUri);
                    if (input != null) {
                        BitmapFactory.Options options = new BitmapFactory.Options();
                        options.inJustDecodeBounds = true;
                        Bitmap bmp1 = BitmapFactory.decodeStream(input, null, options);
                        if (bmp1 != null) {
                            bmp1.recycle();
                        }
                        // options.inSampleSize = calculateSize(options, 96,
                        // 96);
                        input.close();
                        input = ContactsContract.Contacts.openContactPhotoInputStream(context.getContentResolver(),
                                photoUri);
                        options.inPreferredConfig = Bitmap.Config.ARGB_8888;
                        options.inSampleSize = calculateSize(options, size, size);
                        options.inJustDecodeBounds = false;
                        bmp = BitmapFactory.decodeStream(input, null, options);
                        input.close();
                    }
                }
            }
        } catch (Exception ex) {
            Log.v(TAG, "exception retrieving avatar for " + jid.toString(), ex);
        } finally {
            cursor.close();
        }
        return bmp;
    }

    public static void setAvatarToImageView(BareJID jid, ImageView imageView) {
        Bitmap bmp = avatarCache.get(jid);
        if (bmp != null) {
            imageView.setImageBitmap(bmp);
            return;
        }

        if (cancelPotentialWork(jid, imageView)) {
            final BitmapWorkerTask task = new BitmapWorkerTask(imageView, null);
            final AsyncDrawable asyncDrawable = new AsyncDrawable(context.getResources(), mPlaceHolderBitmap, task);
            imageView.setImageDrawable(asyncDrawable);
            try {
                task.execute(jid);
            } catch (java.util.concurrent.RejectedExecutionException e) {
                // ignoring: probably avatar big as cow
                Log.e(TAG, "loading avatar failed for " + jid.toString(), e);
            }
        }
    }

    public static void setAvatarToImageView(BareJID jid, ImageView imageView, int size) {
        if (cancelPotentialWork(jid, imageView)) {
            final BitmapWorkerTask task = new BitmapWorkerTask(imageView, (int) Math.ceil(size * density));
            final AsyncDrawable asyncDrawable = new AsyncDrawable(context.getResources(), mPlaceHolderBitmap, task);
            imageView.setImageDrawable(asyncDrawable);
            try {
                task.execute(jid);
            } catch (java.util.concurrent.RejectedExecutionException e) {
                // ignoring: probably avatar big as cow
                Log.e(TAG, "loading avatar failed for " + jid.toString(), e);
            }
        }
    }

}