com.roamprocess1.roaming4world.utils.ContactsAsyncHelper.java Source code

Java tutorial

Introduction

Here is the source code for com.roamprocess1.roaming4world.utils.ContactsAsyncHelper.java

Source

/**
 * Copyright (C) 2010-2012 Regis Montoya (aka r3gis - www.r3gis.fr)
 * This file is part of CSipSimple.
 *
 *  CSipSimple is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *  If you own a pjsip commercial license you can also redistribute it
 *  and/or modify it under the terms of the GNU Lesser General Public License
 *  as an android library.
 *
 *  CSipSimple 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 General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with CSipSimple.  If not, see <http://www.gnu.org/licenses/>.
 */
/**
 * This file contains relicensed code from Apache copyright of 
 * Copyright (C) 2008 The Android Open Source Project
 */

package com.roamprocess1.roaming4world.utils;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.InputStream;

import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;
import android.support.v4.util.LruCache;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.widget.ImageView;

import com.roamprocess1.roaming4world.R;
import com.roamprocess1.roaming4world.models.CallerInfo;
import com.roamprocess1.roaming4world.roaming4world.ImageHelperCircular;
import com.roamprocess1.roaming4world.utils.contacts.ContactsWrapper;

public class ContactsAsyncHelper extends Handler {
    private static final String THIS_FILE = "ContactsAsyncHelper";

    public static CallerInfo callerInfo;
    // TODO : use LRUCache for bitmaps.

    LruCache<Uri, Bitmap> photoCache = new LruCache<Uri, Bitmap>(5 * 1024 * 1024 /* 5MiB */) {
        protected int sizeOf(Uri key, Bitmap value) {
            return value.getRowBytes() * value.getWidth();
        }
    };

    /**
     * Interface for a WorkerHandler result return.
     */
    public interface OnImageLoadCompleteListener {
        /**
         * Called when the image load is complete.
         * 
         * @param imagePresent true if an image was found
         */
        public void onImageLoadComplete(int token, Object cookie, ImageView iView, boolean imagePresent);
    }

    // constants
    private static final int EVENT_LOAD_IMAGE = 1;
    private static final int EVENT_LOAD_IMAGE_URI = 2;
    private static final int EVENT_LOAD_CONTACT_URI = 3;
    private static final int DEFAULT_TOKEN = -1;
    private static final int TAG_PHOTO_INFOS = R.id.icon;
    private static ContactsWrapper contactsWrapper;

    // static objects
    private static Handler sThreadHandler;

    private static final class WorkerArgs {
        public Context context;
        public ImageView view;
        public int defaultResource;
        public Object result;
        public Uri loadedUri;
        public Object cookie;
        public OnImageLoadCompleteListener listener;
    }

    public static class PhotoViewTag {
        public Uri uri;
        public String number;
    }

    public static final String HIGH_RES_URI_PARAM = "hiRes";

    /**
     * Thread worker class that handles the task of opening the stream and
     * loading the images.
     */
    @SuppressLint("SdCardPath")
    private class WorkerHandler extends Handler {

        public WorkerHandler(Looper looper) {
            super(looper);
        }

        public void handleMessage(Message msg) {

            WorkerArgs args = (WorkerArgs) msg.obj;
            Uri uri = null, imageuri = null;

            if (msg.arg1 == EVENT_LOAD_IMAGE) {

                PhotoViewTag photoTag = (PhotoViewTag) args.view.getTag(TAG_PHOTO_INFOS);

                Bitmap imagebitmap = null, img = null;
                String filename = callerInfo.phoneNumber;

                Log.d("filename", filename + " !");
                Log.d("if photo true", "00");

                filename = filename + ".png";
                Log.d("filenamenumber", filename + " !");
                String path = "/sdcard/R4W/ProfilePic/" + filename;
                File f = new File(path);
                if (f.exists()) {
                    imageuri = Uri.fromFile(f);
                }

                if (imageuri != null) {

                    imagebitmap = BitmapFactory.decodeFile(imageuri.getPath());
                    try {
                        imagebitmap = ImageHelperCircular.getRoundedCornerBitmap(imagebitmap, 400);
                    } catch (Exception e) {
                        if (f.exists()) {
                            f.delete();
                        }
                        e.printStackTrace();
                    }
                    Log.d("filebitmap", imagebitmap.getHeight() + " !");
                    args.result = imagebitmap;

                }

                uri = photoTag.uri;
                boolean hiRes = false;
                String p = uri.getQueryParameter(HIGH_RES_URI_PARAM);
                if (!TextUtils.isEmpty(p) && p.equalsIgnoreCase("1")) {
                    hiRes = true;
                }
                Log.v(THIS_FILE, "get : " + uri);

                synchronized (photoCache) {
                    img = imagebitmap;
                }
                if (img == null) {

                    img = contactsWrapper.getContactPhoto(args.context, uri, hiRes, args.defaultResource);

                    synchronized (photoCache) {
                        photoCache.put(uri, img);
                    }
                }
                if (img != null) {
                    img = ImageHelperCircular.getRoundedCornerBitmap(img, 400);
                    args.result = img;
                } else {
                    args.result = null;
                }

            } else if (msg.arg1 == EVENT_LOAD_IMAGE_URI || msg.arg1 == EVENT_LOAD_CONTACT_URI) {
                PhotoViewTag photoTag = (PhotoViewTag) args.view.getTag(TAG_PHOTO_INFOS);
                if (photoTag != null && photoTag.uri != null) {

                    String filename = callerInfo.phoneNumber;

                    Log.d("filename", filename + " !");
                    Log.d("if photo true", "01");

                    filename = filename + ".png";
                    Log.d("filenamenumber", filename + " !");
                    String path = "/sdcard/R4W/ProfilePic/" + filename;
                    File f = new File(path);
                    if (f.exists()) {
                        imageuri = Uri.fromFile(f);
                    } else {
                        uri = photoTag.uri;
                    }
                    Log.v(THIS_FILE, "get : " + uri);

                    Bitmap img = null;

                    synchronized (photoCache) {
                        img = photoCache.get(uri);
                    }
                    if (img == null) {

                        if (msg.arg1 == EVENT_LOAD_IMAGE_URI) {

                            try {
                                byte[] buffer = new byte[1024 * 16];
                                InputStream is = args.context.getContentResolver().openInputStream(uri);
                                if (is != null) {
                                    ByteArrayOutputStream baos = new ByteArrayOutputStream();
                                    try {
                                        int size;
                                        while ((size = is.read(buffer)) != -1) {
                                            baos.write(buffer, 0, size);
                                        }
                                    } finally {
                                        is.close();
                                    }
                                    byte[] boasBytes = baos.toByteArray();
                                    img = BitmapFactory.decodeByteArray(boasBytes, 0, boasBytes.length, null);
                                }

                            } catch (Exception ex) {
                                Log.v(THIS_FILE, "Cannot load photo " + uri, ex);
                            }

                        } else if (msg.arg1 == EVENT_LOAD_CONTACT_URI) {
                            img = ContactsWrapper.getInstance().getContactPhoto(args.context, uri, false, null);
                        }
                    }

                    if (img != null) {
                        args.result = img;
                        synchronized (photoCache) {
                            photoCache.put(uri, img);
                        }
                    } else {
                        args.result = null;
                    }

                }
            }
            args.loadedUri = uri;

            // send the reply to the enclosing class.
            Message reply = ContactsAsyncHelper.this.obtainMessage(msg.what);
            reply.arg1 = msg.arg1;
            reply.obj = msg.obj;
            reply.sendToTarget();
        }
    }

    /**
     * Private constructor for static class
     */
    private ContactsAsyncHelper() {
        HandlerThread thread = new HandlerThread("ContactsAsyncWorker");
        thread.start();
        sThreadHandler = new WorkerHandler(thread.getLooper());
        contactsWrapper = ContactsWrapper.getInstance();
    }

    /**
     * Convenience method for calls that do not want to deal with listeners and
     * tokens.
     */
    public static final void updateImageViewWithContactPhotoAsync(Context context, ImageView imageView,
            CallerInfo person, int placeholderImageResource) {
        // Added additional Cookie field in the callee.
        callerInfo = person;
        updateImageViewWithContactPhotoAsync(DEFAULT_TOKEN, null, null, context, imageView, person,
                placeholderImageResource);
    }

    /**
     * Start an image load, attach the result to the specified CallerInfo
     * object. Note, when the query is started, we make the ImageView INVISIBLE
     * if the placeholderImageResource value is -1. When we're given a valid (!=
     * -1) placeholderImageResource value, we make sure the image is visible.
     */
    @SuppressLint("SdCardPath")
    public static final void updateImageViewWithContactPhotoAsync(int token, OnImageLoadCompleteListener listener,
            Object cookie, Context context, ImageView imageView, CallerInfo callerInfo,
            int placeholderImageResource) {

        System.out.println("1 phoneNumber " + callerInfo.phoneNumber);

        File file = new File("/sdcard/R4W/ProfilePic/" + callerInfo.phoneNumber + ".png");
        if (file.exists()) {
            new ContactsAsyncHelper();
        } else {

            if (sThreadHandler == null) {
                new ContactsAsyncHelper();
            }

            // in case the source caller info is null, the URI will be null as well.
            // just update using the placeholder image in this case.

            if (callerInfo == null || callerInfo.contactContentUri == null) {
                defaultImage(imageView, placeholderImageResource);
                return;
            }

        }
        // Check that the view is not already loading for same uri
        if (isAlreadyProcessed(imageView, callerInfo.contactContentUri)) {
            return;
        }

        // Added additional Cookie field in the callee to handle arguments
        // sent to the callback function.

        // setup arguments
        WorkerArgs args = new WorkerArgs();
        args.cookie = cookie;
        args.context = context;
        args.view = imageView;
        PhotoViewTag photoTag = new PhotoViewTag();
        photoTag.uri = callerInfo.contactContentUri;
        args.view.setTag(TAG_PHOTO_INFOS, photoTag);
        args.defaultResource = placeholderImageResource;
        args.listener = listener;

        // setup message arguments
        Message msg = sThreadHandler.obtainMessage(token);
        msg.arg1 = EVENT_LOAD_IMAGE;
        msg.obj = args;

        preloadImage(imageView, placeholderImageResource, msg);
    }

    public static void updateImageViewWithContactPhotoAsync(Context context, ImageView imageView, Uri photoUri,
            int placeholderImageResource) {
        updateImageViewWithUriAsync(context, imageView, photoUri, placeholderImageResource, EVENT_LOAD_IMAGE_URI);
    }

    public static void updateImageViewWithContactAsync(Context context, ImageView imageView, Uri contactUri,
            int placeholderImageResource) {
        updateImageViewWithUriAsync(context, imageView, contactUri, placeholderImageResource,
                EVENT_LOAD_CONTACT_URI);
    }

    @SuppressLint("SdCardPath")
    private static void updateImageViewWithUriAsync(Context context, ImageView imageView, Uri photoUri,
            int placeholderImageResource, int eventType) {

        System.out.println("2 phoneNumber " + callerInfo.phoneNumber);

        File file = new File("/sdcard/R4W/ProfilePic/" + callerInfo.phoneNumber + ".png");
        if (file.exists()) {
            new ContactsAsyncHelper();
        } else {

            if (sThreadHandler == null) {
                Log.v(THIS_FILE, "Update image view with contact async");
                new ContactsAsyncHelper();
            }

            // in case the source caller info is null, the URI will be null as well.
            // just update using the placeholder image in this case.
            if (photoUri == null) {
                defaultImage(imageView, placeholderImageResource);
                return;
            }
        }
        if (isAlreadyProcessed(imageView, photoUri)) {
            return;
        }

        // Added additional Cookie field in the callee to handle arguments
        // sent to the callback function.

        // setup arguments
        WorkerArgs args = new WorkerArgs();
        args.context = context;
        args.view = imageView;
        PhotoViewTag photoTag = new PhotoViewTag();
        photoTag.uri = photoUri;
        args.view.setTag(TAG_PHOTO_INFOS, photoTag);
        args.defaultResource = placeholderImageResource;

        // setup message arguments
        Message msg = sThreadHandler.obtainMessage();
        msg.arg1 = eventType;
        msg.obj = args;

        preloadImage(imageView, placeholderImageResource, msg);
    }

    private static void defaultImage(ImageView imageView, int placeholderImageResource) {
        Log.v(THIS_FILE, "No uri, just display placeholder.");
        PhotoViewTag photoTag = new PhotoViewTag();
        photoTag.uri = null;
        imageView.setTag(TAG_PHOTO_INFOS, photoTag);
        imageView.setVisibility(View.VISIBLE);
        imageView.setImageResource(placeholderImageResource);
    }

    private static void preloadImage(ImageView imageView, int placeholderImageResource, Message msg) {
        // set the default image first, when the query is complete, we will
        // replace the image with the correct one.
        if (placeholderImageResource != -1) {
            imageView.setVisibility(View.VISIBLE);
            imageView.setImageResource(placeholderImageResource);
        } else {
            imageView.setVisibility(View.INVISIBLE);
        }

        // notify the thread to begin working
        sThreadHandler.sendMessage(msg);
    }

    private static boolean isAlreadyProcessed(ImageView imageView, Uri uri) {
        if (imageView != null) {
            PhotoViewTag vt = (PhotoViewTag) imageView.getTag(TAG_PHOTO_INFOS);
            return (vt != null && UriUtils.areEqual(uri, vt.uri));
        }
        return true;
    }

    /**
     * Called when loading is done.
     */
    @Override
    public void handleMessage(Message msg) {
        WorkerArgs args = (WorkerArgs) msg.obj;
        if (msg.arg1 == EVENT_LOAD_IMAGE || msg.arg1 == EVENT_LOAD_IMAGE_URI
                || msg.arg1 == EVENT_LOAD_CONTACT_URI) {
            boolean imagePresent = false;
            // Sanity check on image view
            PhotoViewTag photoTag = (PhotoViewTag) args.view.getTag(TAG_PHOTO_INFOS);
            if (photoTag == null) {
                Log.w(THIS_FILE, "Tag has been removed meanwhile");
                return;
            }
            if (!UriUtils.areEqual(args.loadedUri, photoTag.uri)) {
                Log.w(THIS_FILE, "Image view has changed uri meanwhile");
                return;
            }

            // if the image has been loaded then display it, otherwise set
            // default.
            // in either case, make sure the image is visible.
            if (args.result != null) {
                args.view.setVisibility(View.VISIBLE);
                args.view.setImageBitmap((Bitmap) args.result);
                imagePresent = true;
            } else if (args.defaultResource != -1) {
                args.view.setVisibility(View.VISIBLE);
                args.view.setImageResource(args.defaultResource);
            }
            // notify the listener if it is there.
            if (args.listener != null) {
                Log.v(THIS_FILE, "Notifying listener: " + args.listener.toString() + " image: " + args.loadedUri
                        + " completed");
                args.listener.onImageLoadComplete(msg.what, args.cookie, args.view, imagePresent);
            }
        }
    }

}