com.trellmor.berrymotes.EmoteGetter.java Source code

Java tutorial

Introduction

Here is the source code for com.trellmor.berrymotes.EmoteGetter.java

Source

/*
 * LibBerryMotes
 * 
 * Copyright (C) 2013 Daniel Triendl <trellmor@trellmor.com>
 * 
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 3 of the License, or (at your option) any later version.
 * 
 * This library 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
 * Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

package com.trellmor.berrymotes;

import java.util.ArrayList;
import java.util.HashSet;

import android.content.ContentResolver;
import android.content.Context;
import android.database.Cursor;
import android.graphics.drawable.AnimationDrawable;
import android.graphics.drawable.Drawable;
import android.support.v4.util.LruCache;
import android.text.Html.ImageGetter;
import android.util.Log;

import com.trellmor.berrymotes.loader.BasicEmoteLoader;
import com.trellmor.berrymotes.loader.EmoteLoader;
import com.trellmor.berrymotes.provider.EmotesContract;

/**
 * EmoteGetter
 * 
 * Fetches emotes from sd-card and returns Drawables
 * 
 * Decends from ImageGetter and can be used with
 * {@link android.text.Html#fromHtml(String, ImageGetter, android.text.Html.TagHandler)}
 * 
 * @author Daniel
 * 
 */
public class EmoteGetter implements ImageGetter {
    private static final String TAG = EmoteGetter.class.getName();

    private ContentResolver mResolver;

    private final String[] PROJECTION = { EmotesContract.Emote.COLUMN_IMAGE, EmotesContract.Emote.COLUMN_APNG,
            EmotesContract.Emote.COLUMN_DELAY };
    private LruCache<String, Drawable> mCache;
    private LruCache<String, AnimationEmode> mAnimationCache;
    private EmoteLoader mLoader;
    private HashSet<String> mBlacklist;

    /**
     * Create new {@link EmoteGetter} instance
     * 
     * @param context
     *            Android context
     */
    public EmoteGetter(Context context) {
        this(context, new BasicEmoteLoader());
    }

    /**
     * Create new EmoteGetter instance
     * 
     * @param context
     *            Android context
     */
    public EmoteGetter(Context context, EmoteLoader loader) {
        mResolver = context.getContentResolver();
        mCache = new LruCache<String, Drawable>(20);
        mAnimationCache = new LruCache<String, AnimationEmode>(5);
        mBlacklist = new HashSet<String>();
        mLoader = loader;
    }

    @Override
    public Drawable getDrawable(String source) {
        if (mBlacklist.contains(source))
            return null;

        Drawable d = mCache.get(source);
        if (d != null)
            return d;

        AnimationEmode ae = mAnimationCache.get(source);
        if (ae != null) {
            try {
                d = ae.newDrawable();
                d.setBounds(0, 0, d.getIntrinsicWidth(), d.getIntrinsicHeight());
                return d;
            } catch (OutOfMemoryError e) {
                return null;
            }
        }

        Cursor cursor = mResolver.query(EmotesContract.Emote.CONTENT_URI, PROJECTION,
                EmotesContract.Emote.COLUMN_NAME + "=?", new String[] { source },
                EmotesContract.Emote.COLUMN_INDEX + " ASC");

        if (cursor != null && cursor.getCount() > 0) {
            cursor.moveToFirst();

            final int POS_IMAGE = cursor.getColumnIndex(EmotesContract.Emote.COLUMN_IMAGE);

            if (cursor.getCount() > 1
                    && cursor.getInt(cursor.getColumnIndex(EmotesContract.Emote.COLUMN_APNG)) == 1) {

                // Create AnimationDrawable
                ae = new AnimationEmode();

                final int POS_DELAY = cursor.getColumnIndex(EmotesContract.Emote.COLUMN_DELAY);

                try {
                    do {
                        String path = cursor.getString(POS_IMAGE);
                        Drawable frame = mLoader.fromPath(path);
                        if (frame != null) {
                            ae.addFrame(frame, cursor.getInt(POS_DELAY));
                        }
                    } while (cursor.moveToNext());
                    d = ae.newDrawable();
                    mAnimationCache.put(source, ae);
                } catch (OutOfMemoryError e) {
                    d = null;
                    mBlacklist.add(source);
                    Log.e(TAG, "Failed to load " + source, e);
                }
            } else {
                String path = cursor.getString(POS_IMAGE);
                try {
                    d = mLoader.fromPath(path);
                } catch (OutOfMemoryError e) {
                    d = null;
                    mBlacklist.add(source);
                    Log.e(TAG, "Failed to load " + source, e);
                }
                if (d != null) {
                    mCache.put(source, d);
                }
            }
        }

        if (cursor != null)
            cursor.close();

        if (d != null) {
            d.setBounds(0, 0, d.getIntrinsicWidth(), d.getIntrinsicHeight());
        }
        return d;
    }

    private class AnimationEmode {
        private ArrayList<AnimationEmoteFrame> mFrames = new ArrayList<AnimationEmoteFrame>();

        public void addFrame(Drawable drawable, int duration) {
            mFrames.add(new AnimationEmoteFrame(drawable, duration));
        }

        public Drawable newDrawable() {
            AnimationDrawable d = new AnimationDrawable();
            for (AnimationEmoteFrame frame : mFrames) {
                d.addFrame(frame.getDrawable(), frame.getDuration());
            }
            d.setOneShot(false);
            return d;
        }

        private class AnimationEmoteFrame {
            private final Drawable mDrawable;
            private final int mDuration;

            public AnimationEmoteFrame(Drawable drawable, int duration) {
                mDrawable = drawable;
                mDuration = duration;
            }

            public Drawable getDrawable() {
                return mDrawable;
            }

            public int getDuration() {
                return mDuration;
            }
        }
    }
}