session-android/src/org/thoughtcrime/securesms/util/Emoji.java
2013-07-15 17:33:30 -07:00

192 lines
6.0 KiB
Java

package org.thoughtcrime.securesms.util;
import android.content.Context;
import android.content.SharedPreferences;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.preference.PreferenceManager;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.style.ImageSpan;
import android.util.Log;
import com.google.thoughtcrimegson.Gson;
import com.google.thoughtcrimegson.reflect.TypeToken;
import org.thoughtcrime.securesms.R;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Type;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Emoji {
private static Emoji instance = null;
public synchronized static Emoji getInstance(Context context) {
if (instance == null) {
instance = new Emoji(context);
}
return instance;
}
private static final Pattern EMOJI_RANGE = Pattern.compile("[\ud83d\ude01-\ud83d\ude4f]");
public static final double EMOJI_LARGE = 1;
public static final double EMOJI_SMALL = 0.7;
private final Context context;
private final String[] emojiAssets;
private final Set<String> emojiAssetsSet;
private final BitmapFactory.Options bitmapOptions;
private Emoji(Context context) {
this.context = context.getApplicationContext();
this.emojiAssets = initializeEmojiAssets();
this.emojiAssetsSet = new HashSet<String>();
this.bitmapOptions = initializeBitmapOptions();
Collections.addAll(this.emojiAssetsSet, emojiAssets);
}
public int getEmojiAssetCount() {
return emojiAssets.length;
}
public String getEmojiUnicode(int position) {
return getEmojiUnicodeFromAssetName(emojiAssets[position]);
}
public String getRecentEmojiUnicode(int position) {
return getEmojiUnicodeFromAssetName(EmojiLRU.getRecentlyUsed(context).get(position));
}
public Drawable getEmojiDrawable(int position) {
return getEmojiDrawable(emojiAssets[position]);
}
public SpannableString emojify(String text) {
return emojify(new SpannableString(text), EMOJI_LARGE);
}
public SpannableString emojify(SpannableString text, double size) {
if (text.toString().contains("\ud83d")) {
Matcher matches = EMOJI_RANGE.matcher(text);
while (matches.find()) {
String resource = Integer.toHexString(matches.group().codePointAt(0)) + ".png";
if (emojiAssetsSet.contains(resource)) {
Drawable drawable = getEmojiDrawable(resource);
drawable.setBounds(0, 0, (int)(drawable.getIntrinsicWidth()*size),
(int)(drawable.getIntrinsicHeight()*size));
ImageSpan imageSpan = new ImageSpan(drawable, ImageSpan.ALIGN_BOTTOM);
text.setSpan(imageSpan, matches.start(), matches.end(),
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
}
}
return text;
}
public void setRecentlyUsed(int position) {
String assetName = emojiAssets[position];
EmojiLRU.putRecentlyUsed(context, assetName);
}
public int getRecentlyUsedAssetCount() {
return EmojiLRU.getRecentlyUsed(context).size();
}
public Drawable getRecentlyUsed(int position) {
return getEmojiDrawable(EmojiLRU.getRecentlyUsed(context).get(position));
}
private String getEmojiUnicodeFromAssetName(String assetName) {
String hexString = assetName.split("\\.")[0];
Integer unicodePoint = Integer.parseInt(hexString, 16);
return new String(Character.toChars(unicodePoint));
}
private Drawable getEmojiDrawable(String assetName) {
try {
Bitmap bitmap = BitmapFactory.decodeStream(context.getAssets().open("emoji" + File.separator + assetName),
null, bitmapOptions);
bitmap = Bitmap.createScaledBitmap(bitmap, 40, 40, true);
return new BitmapDrawable(context.getResources(), bitmap);
} catch (IOException e) {
throw new AssertionError(e);
}
}
private String[] initializeEmojiAssets() {
try {
return context.getAssets().list("emoji");
} catch (IOException e) {
Log.w("Emoji", e);
return new String[0];
}
}
private BitmapFactory.Options initializeBitmapOptions() {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inScaled = true;
// options.inDensity = 64;
options.inTargetDensity = context.getResources().getDimensionPixelSize(R.dimen.emoji_size);
options.inSampleSize = 1;
options.inJustDecodeBounds = false;
return options;
}
private static class EmojiLRU {
private static final String EMOJI_LRU_PREFERENCE = "pref_popular_emoji";
private static final int EMOJI_LRU_SIZE = 10;
public static List<String> getRecentlyUsed(Context context) {
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
String serialized = preferences.getString(EMOJI_LRU_PREFERENCE, "[]");
Type type = new TypeToken<Collection<String>>(){}.getType();
return new Gson().fromJson(serialized, type);
}
public static void putRecentlyUsed(Context context, String asset) {
LinkedHashSet<String> recentlyUsed = new LinkedHashSet<String>(getRecentlyUsed(context));
recentlyUsed.add(asset);
if (recentlyUsed.size() > 10) {
Iterator<String> iterator = recentlyUsed.iterator();
iterator.next();
iterator.remove();
}
String serialized = new Gson().toJson(recentlyUsed);
PreferenceManager.getDefaultSharedPreferences(context)
.edit()
.putString(EMOJI_LRU_PREFERENCE, serialized)
.commit();
}
}
}