diff --git a/assets/1f601.png b/assets/emoji/1f601.png similarity index 100% rename from assets/1f601.png rename to assets/emoji/1f601.png diff --git a/assets/1f602.png b/assets/emoji/1f602.png similarity index 100% rename from assets/1f602.png rename to assets/emoji/1f602.png diff --git a/assets/1f603.png b/assets/emoji/1f603.png similarity index 100% rename from assets/1f603.png rename to assets/emoji/1f603.png diff --git a/assets/1f604.png b/assets/emoji/1f604.png similarity index 100% rename from assets/1f604.png rename to assets/emoji/1f604.png diff --git a/assets/1f605.png b/assets/emoji/1f605.png similarity index 100% rename from assets/1f605.png rename to assets/emoji/1f605.png diff --git a/assets/1f606.png b/assets/emoji/1f606.png similarity index 100% rename from assets/1f606.png rename to assets/emoji/1f606.png diff --git a/assets/1f609.png b/assets/emoji/1f609.png similarity index 100% rename from assets/1f609.png rename to assets/emoji/1f609.png diff --git a/assets/1f60a.png b/assets/emoji/1f60a.png similarity index 100% rename from assets/1f60a.png rename to assets/emoji/1f60a.png diff --git a/assets/1f60b.png b/assets/emoji/1f60b.png similarity index 100% rename from assets/1f60b.png rename to assets/emoji/1f60b.png diff --git a/assets/1f60c.png b/assets/emoji/1f60c.png similarity index 100% rename from assets/1f60c.png rename to assets/emoji/1f60c.png diff --git a/assets/1f60d.png b/assets/emoji/1f60d.png similarity index 100% rename from assets/1f60d.png rename to assets/emoji/1f60d.png diff --git a/assets/1f60f.png b/assets/emoji/1f60f.png similarity index 100% rename from assets/1f60f.png rename to assets/emoji/1f60f.png diff --git a/assets/1f612.png b/assets/emoji/1f612.png similarity index 100% rename from assets/1f612.png rename to assets/emoji/1f612.png diff --git a/assets/1f613.png b/assets/emoji/1f613.png similarity index 100% rename from assets/1f613.png rename to assets/emoji/1f613.png diff --git a/assets/1f614.png b/assets/emoji/1f614.png similarity index 100% rename from assets/1f614.png rename to assets/emoji/1f614.png diff --git a/assets/1f616.png b/assets/emoji/1f616.png similarity index 100% rename from assets/1f616.png rename to assets/emoji/1f616.png diff --git a/assets/1f618.png b/assets/emoji/1f618.png similarity index 100% rename from assets/1f618.png rename to assets/emoji/1f618.png diff --git a/assets/1f61a.png b/assets/emoji/1f61a.png similarity index 100% rename from assets/1f61a.png rename to assets/emoji/1f61a.png diff --git a/assets/1f61c.png b/assets/emoji/1f61c.png similarity index 100% rename from assets/1f61c.png rename to assets/emoji/1f61c.png diff --git a/assets/1f61d.png b/assets/emoji/1f61d.png similarity index 100% rename from assets/1f61d.png rename to assets/emoji/1f61d.png diff --git a/assets/1f61e.png b/assets/emoji/1f61e.png similarity index 100% rename from assets/1f61e.png rename to assets/emoji/1f61e.png diff --git a/assets/1f620.png b/assets/emoji/1f620.png similarity index 100% rename from assets/1f620.png rename to assets/emoji/1f620.png diff --git a/assets/1f621.png b/assets/emoji/1f621.png similarity index 100% rename from assets/1f621.png rename to assets/emoji/1f621.png diff --git a/assets/1f622.png b/assets/emoji/1f622.png similarity index 100% rename from assets/1f622.png rename to assets/emoji/1f622.png diff --git a/assets/1f623.png b/assets/emoji/1f623.png similarity index 100% rename from assets/1f623.png rename to assets/emoji/1f623.png diff --git a/assets/1f624.png b/assets/emoji/1f624.png similarity index 100% rename from assets/1f624.png rename to assets/emoji/1f624.png diff --git a/assets/1f625.png b/assets/emoji/1f625.png similarity index 100% rename from assets/1f625.png rename to assets/emoji/1f625.png diff --git a/assets/1f628.png b/assets/emoji/1f628.png similarity index 100% rename from assets/1f628.png rename to assets/emoji/1f628.png diff --git a/assets/1f629.png b/assets/emoji/1f629.png similarity index 100% rename from assets/1f629.png rename to assets/emoji/1f629.png diff --git a/assets/1f62a.png b/assets/emoji/1f62a.png similarity index 100% rename from assets/1f62a.png rename to assets/emoji/1f62a.png diff --git a/assets/1f62b.png b/assets/emoji/1f62b.png similarity index 100% rename from assets/1f62b.png rename to assets/emoji/1f62b.png diff --git a/assets/1f62d.png b/assets/emoji/1f62d.png similarity index 100% rename from assets/1f62d.png rename to assets/emoji/1f62d.png diff --git a/assets/1f630.png b/assets/emoji/1f630.png similarity index 100% rename from assets/1f630.png rename to assets/emoji/1f630.png diff --git a/assets/1f631.png b/assets/emoji/1f631.png similarity index 100% rename from assets/1f631.png rename to assets/emoji/1f631.png diff --git a/assets/1f632.png b/assets/emoji/1f632.png similarity index 100% rename from assets/1f632.png rename to assets/emoji/1f632.png diff --git a/assets/1f633.png b/assets/emoji/1f633.png similarity index 100% rename from assets/1f633.png rename to assets/emoji/1f633.png diff --git a/assets/1f635.png b/assets/emoji/1f635.png similarity index 100% rename from assets/1f635.png rename to assets/emoji/1f635.png diff --git a/assets/1f637.png b/assets/emoji/1f637.png similarity index 100% rename from assets/1f637.png rename to assets/emoji/1f637.png diff --git a/assets/1f638.png b/assets/emoji/1f638.png similarity index 100% rename from assets/1f638.png rename to assets/emoji/1f638.png diff --git a/assets/1f639.png b/assets/emoji/1f639.png similarity index 100% rename from assets/1f639.png rename to assets/emoji/1f639.png diff --git a/assets/1f63a.png b/assets/emoji/1f63a.png similarity index 100% rename from assets/1f63a.png rename to assets/emoji/1f63a.png diff --git a/assets/1f63b.png b/assets/emoji/1f63b.png similarity index 100% rename from assets/1f63b.png rename to assets/emoji/1f63b.png diff --git a/assets/1f63c.png b/assets/emoji/1f63c.png similarity index 100% rename from assets/1f63c.png rename to assets/emoji/1f63c.png diff --git a/assets/1f63d.png b/assets/emoji/1f63d.png similarity index 100% rename from assets/1f63d.png rename to assets/emoji/1f63d.png diff --git a/assets/1f63e.png b/assets/emoji/1f63e.png similarity index 100% rename from assets/1f63e.png rename to assets/emoji/1f63e.png diff --git a/assets/1f63f.png b/assets/emoji/1f63f.png similarity index 100% rename from assets/1f63f.png rename to assets/emoji/1f63f.png diff --git a/assets/1f640.png b/assets/emoji/1f640.png similarity index 100% rename from assets/1f640.png rename to assets/emoji/1f640.png diff --git a/assets/1f645.png b/assets/emoji/1f645.png similarity index 100% rename from assets/1f645.png rename to assets/emoji/1f645.png diff --git a/assets/1f646.png b/assets/emoji/1f646.png similarity index 100% rename from assets/1f646.png rename to assets/emoji/1f646.png diff --git a/assets/1f647.png b/assets/emoji/1f647.png similarity index 100% rename from assets/1f647.png rename to assets/emoji/1f647.png diff --git a/assets/1f648.png b/assets/emoji/1f648.png similarity index 100% rename from assets/1f648.png rename to assets/emoji/1f648.png diff --git a/assets/1f649.png b/assets/emoji/1f649.png similarity index 100% rename from assets/1f649.png rename to assets/emoji/1f649.png diff --git a/assets/1f64a.png b/assets/emoji/1f64a.png similarity index 100% rename from assets/1f64a.png rename to assets/emoji/1f64a.png diff --git a/assets/1f64b.png b/assets/emoji/1f64b.png similarity index 100% rename from assets/1f64b.png rename to assets/emoji/1f64b.png diff --git a/assets/1f64c.png b/assets/emoji/1f64c.png similarity index 100% rename from assets/1f64c.png rename to assets/emoji/1f64c.png diff --git a/assets/1f64d.png b/assets/emoji/1f64d.png similarity index 100% rename from assets/1f64d.png rename to assets/emoji/1f64d.png diff --git a/assets/1f64e.png b/assets/emoji/1f64e.png similarity index 100% rename from assets/1f64e.png rename to assets/emoji/1f64e.png diff --git a/assets/1f64f.png b/assets/emoji/1f64f.png similarity index 100% rename from assets/1f64f.png rename to assets/emoji/1f64f.png diff --git a/src/org/thoughtcrime/securesms/ConversationItem.java b/src/org/thoughtcrime/securesms/ConversationItem.java index a29eb6db5c..7243f4e0f5 100644 --- a/src/org/thoughtcrime/securesms/ConversationItem.java +++ b/src/org/thoughtcrime/securesms/ConversationItem.java @@ -51,6 +51,7 @@ import org.thoughtcrime.securesms.mms.Slide; import org.thoughtcrime.securesms.mms.SlideDeck; import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.service.SendReceiveService; +import org.thoughtcrime.securesms.util.Emoji; import org.thoughtcrime.securesms.util.FutureTaskListener; import org.thoughtcrime.securesms.util.ListenableFutureTask; @@ -165,7 +166,8 @@ public class ConversationItem extends LinearLayout { /// MessageRecord Attribute Parsers private void setBodyText(MessageRecord messageRecord) { - bodyText.setText(messageRecord.getDisplayBody(), TextView.BufferType.SPANNABLE); + bodyText.setText(Emoji.getInstance(context).emojify(messageRecord.getDisplayBody(), Emoji.EMOJI_LARGE), + TextView.BufferType.SPANNABLE); } private void setContactPhoto(MessageRecord messageRecord) { diff --git a/src/org/thoughtcrime/securesms/ConversationListItem.java b/src/org/thoughtcrime/securesms/ConversationListItem.java index 9d8a86657a..331f4cf179 100644 --- a/src/org/thoughtcrime/securesms/ConversationListItem.java +++ b/src/org/thoughtcrime/securesms/ConversationListItem.java @@ -19,7 +19,6 @@ package org.thoughtcrime.securesms; import android.content.Context; import android.content.Intent; import android.content.res.TypedArray; -import android.graphics.Color; import android.graphics.Typeface; import android.net.Uri; import android.os.Build; @@ -41,6 +40,7 @@ import android.widget.TextView; import org.thoughtcrime.securesms.database.model.ThreadRecord; import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.recipients.Recipients; +import org.thoughtcrime.securesms.util.Emoji; import java.util.Set; @@ -103,7 +103,9 @@ public class ConversationListItem extends RelativeLayout this.recipients.addListener(this); this.fromView.setText(formatFrom(recipients, count, read)); - this.subjectView.setText(thread.getDisplayBody(), TextView.BufferType.SPANNABLE); + this.subjectView.setText(Emoji.getInstance(context).emojify(thread.getDisplayBody(), + Emoji.EMOJI_SMALL), + TextView.BufferType.SPANNABLE); if (thread.getDate() > 0) this.dateView.setText(DateUtils.getRelativeTimeSpanString(getContext(), thread.getDate(), false)); diff --git a/src/org/thoughtcrime/securesms/components/EmojiDrawer.java b/src/org/thoughtcrime/securesms/components/EmojiDrawer.java index 7470ec4ba5..f986d647b0 100644 --- a/src/org/thoughtcrime/securesms/components/EmojiDrawer.java +++ b/src/org/thoughtcrime/securesms/components/EmojiDrawer.java @@ -24,6 +24,7 @@ import android.widget.TextView; import org.thoughtcrime.securesms.R; import org.thoughtcrime.securesms.util.Emoji; +import java.io.File; import java.io.IOException; public class EmojiDrawer extends FrameLayout { @@ -32,6 +33,7 @@ public class EmojiDrawer extends FrameLayout { private FrameLayout recentEmojiGridLayout; private EditText composeText; + private Emoji emoji; public EmojiDrawer(Context context) { super(context); @@ -57,6 +59,7 @@ public class EmojiDrawer extends FrameLayout { } private void initialize() { + this.emoji = Emoji.getInstance(getContext()); LayoutInflater inflater = (LayoutInflater)getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE); inflater.inflate(R.layout.emoji_drawer, this, true); @@ -79,14 +82,14 @@ public class EmojiDrawer extends FrameLayout { private class EmojiClickListener implements AdapterView.OnItemClickListener { @Override public void onItemClick(AdapterView parent, View view, int position, long id) { - int start = composeText.getSelectionStart(); - int end = composeText.getSelectionEnd (); - String emoji = Emoji.EMOJI_ASSET_CODE_MAP.get(Emoji.EMOJI_ASSETS.get(position)); + int start = composeText.getSelectionStart(); + int end = composeText.getSelectionEnd (); + String characters = emoji.getEmojiUnicode(position); composeText.getText().replace(Math.min(start, end), Math.max(start, end), - emoji, 0, emoji.length()); + characters, 0, characters.length()); - composeText.setText(Emoji.emojify(getContext(), composeText.getText().toString()), + composeText.setText(emoji.emojify(composeText.getText().toString()), TextView.BufferType.SPANNABLE); composeText.setSelection(end+2); @@ -97,7 +100,7 @@ public class EmojiDrawer extends FrameLayout { @Override public int getCount() { - return Emoji.EMOJI_ASSETS.size(); + return emoji.getEmojiAssetCount(); } @Override @@ -112,25 +115,19 @@ public class EmojiDrawer extends FrameLayout { @Override public View getView(int position, View convertView, ViewGroup parent) { - try { - String asset = Emoji.EMOJI_ASSETS.get(position); - Drawable drawable = Drawable.createFromStream(getContext().getAssets().open(asset + ".png"), null); + Drawable drawable = emoji.getEmojiDrawable(position); - if (convertView != null && convertView instanceof ImageView) { - ((ImageView)convertView).setImageDrawable(drawable); - return convertView; - } else { - ImageView imageView = new ImageView(getContext()); - imageView.setImageDrawable(drawable); - return imageView; - } - } catch (IOException ioe) { - throw new AssertionError(ioe); + if (convertView != null && convertView instanceof ImageView) { + ((ImageView)convertView).setImageDrawable(drawable); + return convertView; + } else { + ImageView imageView = new ImageView(getContext()); + imageView.setImageDrawable(drawable); + return imageView; } } } - private class EmojiPagerAdapter extends PagerAdapter { @Override diff --git a/src/org/thoughtcrime/securesms/util/Emoji.java b/src/org/thoughtcrime/securesms/util/Emoji.java index 1472f44b42..32fbab2776 100644 --- a/src/org/thoughtcrime/securesms/util/Emoji.java +++ b/src/org/thoughtcrime/securesms/util/Emoji.java @@ -7,170 +7,100 @@ import android.text.SpannableString; import android.text.style.ImageSpan; import android.util.Log; +import java.io.File; import java.io.IOException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Map; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; public class Emoji { - public static final HashMap EMOJI_ASSET_CODE_MAP = new HashMap(); - public static final HashMap EMOJI_CODE_ASSET_MAP = new HashMap(); + private static Emoji instance = null; - public static final ArrayList EMOJI_ASSETS = new ArrayList() {{ - add("1f601"); - add("1f602"); - add("1f603"); - add("1f604"); - add("1f605"); - add("1f606"); - add("1f609"); - add("1f60a"); - add("1f60b"); - add("1f60c"); - add("1f60d"); - add("1f60f"); - add("1f612"); - add("1f613"); - add("1f614"); - add("1f616"); - add("1f618"); - add("1f61a"); - add("1f61c"); - add("1f61d"); - add("1f61e"); - add("1f620"); - add("1f621"); - add("1f622"); - add("1f623"); - add("1f624"); - add("1f625"); - add("1f628"); - add("1f629"); - add("1f62a"); - add("1f62b"); - add("1f62d"); - add("1f630"); - add("1f631"); - add("1f632"); - add("1f633"); - add("1f635"); - add("1f637"); - - add("1f638"); - add("1f639"); - add("1f63a"); - add("1f63b"); - add("1f63c"); - add("1f63d"); - add("1f63e"); - add("1f63f"); - add("1f640"); - add("1f645"); - add("1f646"); - add("1f647"); - add("1f648"); - add("1f649"); - add("1f64a"); - add("1f64b"); - add("1f64c"); - add("1f64d"); - add("1f64e"); - add("1f64f"); - }}; - - public static ArrayList EMOJI_CODES = new ArrayList() {{ - add("\ud83d\ude01"); - add("\ud83d\ude02"); - add("\ud83d\ude03"); - add("\ud83d\ude04"); - add("\ud83d\ude05"); - add("\ud83d\ude06"); - add("\ud83d\ude09"); - add("\ud83d\ude0a"); - add("\ud83d\ude0b"); - add("\ud83d\ude0c"); - add("\ud83d\ude0d"); - add("\ud83d\ude0f"); - add("\ud83d\ude12"); - add("\ud83d\ude13"); - add("\ud83d\ude14"); - add("\ud83d\ude16"); - add("\ud83d\ude18"); - add("\ud83d\ude1a"); - add("\ud83d\ude1c"); - add("\ud83d\ude1d"); - add("\ud83d\ude1e"); - add("\ud83d\ude20"); - add("\ud83d\ude21"); - add("\ud83d\ude22"); - add("\ud83d\ude23"); - add("\ud83d\ude24"); - add("\ud83d\ude25"); - add("\ud83d\ude28"); - add("\ud83d\ude29"); - add("\ud83d\ude2a"); - add("\ud83d\ude2b"); - add("\ud83d\ude2d"); - add("\ud83d\ude30"); - add("\ud83d\ude31"); - add("\ud83d\ude32"); - add("\ud83d\ude33"); - add("\ud83d\ude35"); - add("\ud83d\ude37"); - - add("\ud83d\ude38"); - add("\ud83d\ude39"); - add("\ud83d\ude3a"); - add("\ud83d\ude3b"); - add("\ud83d\ude3c"); - add("\ud83d\ude3d"); - add("\ud83d\ude3e"); - add("\ud83d\ude3f"); - add("\ud83d\ude40"); - add("\ud83d\ude45"); - add("\ud83d\ude46"); - add("\ud83d\ude47"); - add("\ud83d\ude48"); - add("\ud83d\ude49"); - add("\ud83d\ude4a"); - add("\ud83d\ude4b"); - add("\ud83d\ude4c"); - add("\ud83d\ude4d"); - add("\ud83d\ude4e"); - add("\ud83d\ude4f"); - }}; - - static { - for (int i=0;i entry : EMOJI_CODE_ASSET_MAP.entrySet()) { - Matcher matcher = entry.getKey().matcher(spannable); + private final Context context; + private final String[] emojiAssets; + private final Set emojiAssetsSet; - while (matcher.find()) { - Drawable asset = Drawable.createFromStream(context.getAssets().open(entry.getValue() + ".png"), null); - asset.setBounds(0, 0, asset.getIntrinsicWidth(), asset.getIntrinsicHeight()); + private Emoji(Context context) { + this.context = context.getApplicationContext(); + this.emojiAssets = initializeEmojiAssets(); + this.emojiAssetsSet = new HashSet(); + + Collections.addAll(this.emojiAssetsSet, emojiAssets); + } + + public int getEmojiAssetCount() { + return emojiAssets.length; + } + + public String getEmojiUnicode(int position) { + String hexString = emojiAssets[position].split("\\.")[0]; + Integer unicodePoint = Integer.parseInt(hexString, 16); + return new String(Character.toChars(unicodePoint)); + } + + 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); - ImageSpan imageSpan = new ImageSpan(asset, ImageSpan.ALIGN_BASELINE); - Log.w("Emoji", "Replacing text with: " + imageSpan); - spannable.setSpan(imageSpan,matcher.start(), matcher.end(), - Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); } } + } - return spannable; + return text; + } + + private Drawable getEmojiDrawable(String assetName) { + try { + return Drawable.createFromStream(context.getAssets().open("emoji" + File.separator + assetName), null); } 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]; + } + } + }