package com.netease.nim.uikit.session.emoji; import android.content.Context; import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.BitmapFactory.Options; import android.graphics.Rect; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.support.v4.util.LruCache; import android.util.DisplayMetrics; import android.util.Xml; import org.xml.sax.Attributes; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; import com.netease.nim.uikit.NimUIKit; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.regex.Pattern; public class EmojiManager { private static final String EMOT_DIR = "emoji/"; // max cache size private static final int CACHE_MAX_SIZE = 1024; private static Pattern pattern; // default entries private static final List<Entry> defaultEntries = new ArrayList<Entry>(); // text to entry private static final Map<String, Entry> text2entry = new HashMap<String, Entry>(); // asset bitmap cache, key: asset path private static LruCache<String, Bitmap> drawableCache; static { Context context = NimUIKit.getContext(); load(context, EMOT_DIR + "emoji.xml"); pattern = makePattern(); drawableCache = new LruCache<String, Bitmap>(CACHE_MAX_SIZE) { @Override protected void entryRemoved(boolean evicted, String key, Bitmap oldValue, Bitmap newValue) { if (oldValue != newValue) oldValue.recycle(); } }; } private static class Entry { String text; String assetPath; Entry(String text, String assetPath) { this.text = text; this.assetPath = assetPath; } } // // display // public static final int getDisplayCount() { return defaultEntries.size(); } public static final Drawable getDisplayDrawable(Context context, int index) { String text = (index >= 0 && index < defaultEntries.size() ? defaultEntries.get(index).text : null); return text == null ? null : getDrawable(context, text); } public static final String getDisplayText(int index) { return index >= 0 && index < defaultEntries.size() ? defaultEntries .get(index).text : null; } public static final Pattern getPattern() { return pattern; } public static final Drawable getDrawable(Context context, String text) { Entry entry = text2entry.get(text); if (entry == null) { return null; } Bitmap cache = drawableCache.get(entry.assetPath); if (cache == null) { cache = loadAssetBitmap(context, entry.assetPath); } return new BitmapDrawable(context.getResources(), cache); } // // internal // private static Pattern makePattern() { return Pattern.compile(patternOfDefault()); } private static String patternOfDefault() { return "\\[[^\\[]{1,10}\\]"; } private static Bitmap loadAssetBitmap(Context context, String assetPath) { InputStream is = null; try { Resources resources = context.getResources(); Options options = new Options(); options.inDensity = DisplayMetrics.DENSITY_HIGH; options.inScreenDensity = resources.getDisplayMetrics().densityDpi; options.inTargetDensity = resources.getDisplayMetrics().densityDpi; is = context.getAssets().open(assetPath); Bitmap bitmap = BitmapFactory.decodeStream(is, new Rect(), options); if (bitmap != null) { drawableCache.put(assetPath, bitmap); } return bitmap; } catch (Exception e) { e.printStackTrace(); } finally { if (is != null) { try { is.close(); } catch (IOException e) { e.printStackTrace(); } } } return null; } private static final void load(Context context, String xmlPath) { new EntryLoader().load(context, xmlPath); } // // load emoticons from asset // private static class EntryLoader extends DefaultHandler { private String catalog = ""; void load(Context context, String assetPath) { InputStream is = null; try { is = context.getAssets().open(assetPath); Xml.parse(is, Xml.Encoding.UTF_8, this); } catch (IOException e) { e.printStackTrace(); } catch (SAXException e) { e.printStackTrace(); } finally { if (is != null) { try { is.close(); } catch (IOException e) { e.printStackTrace(); } } } } @Override public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { if (localName.equals("Catalog")) { catalog = attributes.getValue(uri, "Title"); } else if (localName.equals("Emoticon")) { String tag = attributes.getValue(uri, "Tag"); String fileName = attributes.getValue(uri, "File"); Entry entry = new Entry(tag, EMOT_DIR + catalog + "/" + fileName); text2entry.put(entry.text, entry); if (catalog.equals("default")) { defaultEntries.add(entry); } } } } }