| /* |
| * Copyright (C) 2009 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.android.mms.util; |
| |
| import java.util.HashMap; |
| import java.util.regex.Matcher; |
| import java.util.regex.Pattern; |
| |
| import android.content.Context; |
| import android.text.Spannable; |
| import android.text.SpannableStringBuilder; |
| import android.text.style.ImageSpan; |
| |
| import com.android.mms.R; |
| |
| /** |
| * A class for annotating a CharSequence with spans to convert textual emoticons |
| * to graphical ones. |
| */ |
| public class SmileyParser { |
| // Singleton stuff |
| private static SmileyParser sInstance; |
| public static SmileyParser getInstance() { return sInstance; } |
| public static void init(Context context) { |
| sInstance = new SmileyParser(context); |
| } |
| |
| private final Context mContext; |
| private final String[] mSmileyTexts; |
| private final Pattern mPattern; |
| private final HashMap<String, Integer> mSmileyToRes; |
| |
| private SmileyParser(Context context) { |
| mContext = context; |
| mSmileyTexts = mContext.getResources().getStringArray(DEFAULT_SMILEY_TEXTS); |
| mSmileyToRes = buildSmileyToRes(); |
| mPattern = buildPattern(); |
| } |
| |
| static class Smileys { |
| private static final int[] sIconIds = { |
| R.drawable.emo_im_happy, |
| R.drawable.emo_im_sad, |
| R.drawable.emo_im_winking, |
| R.drawable.emo_im_tongue_sticking_out, |
| R.drawable.emo_im_surprised, |
| R.drawable.emo_im_kissing, |
| R.drawable.emo_im_yelling, |
| R.drawable.emo_im_cool, |
| R.drawable.emo_im_money_mouth, |
| R.drawable.emo_im_foot_in_mouth, |
| R.drawable.emo_im_embarrassed, |
| R.drawable.emo_im_angel, |
| R.drawable.emo_im_undecided, |
| R.drawable.emo_im_crying, |
| R.drawable.emo_im_lips_are_sealed, |
| R.drawable.emo_im_laughing, |
| R.drawable.emo_im_wtf, |
| R.drawable.emo_im_heart, |
| R.drawable.emo_im_mad, |
| R.drawable.emo_im_smirk, |
| R.drawable.emo_im_pokerface |
| }; |
| |
| public static int HAPPY = 0; |
| public static int SAD = 1; |
| public static int WINKING = 2; |
| public static int TONGUE_STICKING_OUT = 3; |
| public static int SURPRISED = 4; |
| public static int KISSING = 5; |
| public static int YELLING = 6; |
| public static int COOL = 7; |
| public static int MONEY_MOUTH = 8; |
| public static int FOOT_IN_MOUTH = 9; |
| public static int EMBARRASSED = 10; |
| public static int ANGEL = 11; |
| public static int UNDECIDED = 12; |
| public static int CRYING = 13; |
| public static int LIPS_ARE_SEALED = 14; |
| public static int LAUGHING = 15; |
| public static int WTF = 16; |
| public static int MAD = 17; |
| public static int HEART = 18; |
| public static int SMIRK = 19; |
| public static int POKERFACE = 20; |
| |
| public static int getSmileyResource(int which) { |
| return sIconIds[which]; |
| } |
| } |
| |
| // NOTE: if you change anything about this array, you must make the corresponding change |
| // to the string arrays: default_smiley_texts and default_smiley_names in res/values/arrays.xml |
| public static final int[] DEFAULT_SMILEY_RES_IDS = { |
| Smileys.getSmileyResource(Smileys.HAPPY), // 0 |
| Smileys.getSmileyResource(Smileys.SAD), // 1 |
| Smileys.getSmileyResource(Smileys.WINKING), // 2 |
| Smileys.getSmileyResource(Smileys.TONGUE_STICKING_OUT), // 3 |
| Smileys.getSmileyResource(Smileys.SURPRISED), // 4 |
| Smileys.getSmileyResource(Smileys.KISSING), // 5 |
| Smileys.getSmileyResource(Smileys.YELLING), // 6 |
| Smileys.getSmileyResource(Smileys.COOL), // 7 |
| Smileys.getSmileyResource(Smileys.MONEY_MOUTH), // 8 |
| Smileys.getSmileyResource(Smileys.FOOT_IN_MOUTH), // 9 |
| Smileys.getSmileyResource(Smileys.EMBARRASSED), // 10 |
| Smileys.getSmileyResource(Smileys.ANGEL), // 11 |
| Smileys.getSmileyResource(Smileys.UNDECIDED), // 12 |
| Smileys.getSmileyResource(Smileys.CRYING), // 13 |
| Smileys.getSmileyResource(Smileys.LIPS_ARE_SEALED), // 14 |
| Smileys.getSmileyResource(Smileys.LAUGHING), // 15 |
| Smileys.getSmileyResource(Smileys.WTF), // 16 |
| Smileys.getSmileyResource(Smileys.MAD), // 17 |
| Smileys.getSmileyResource(Smileys.HEART), // 18 |
| Smileys.getSmileyResource(Smileys.SMIRK), // 19 |
| Smileys.getSmileyResource(Smileys.POKERFACE), // 20 |
| }; |
| |
| public static final int DEFAULT_SMILEY_TEXTS = R.array.default_smiley_texts; |
| public static final int DEFAULT_SMILEY_NAMES = R.array.default_smiley_names; |
| |
| /** |
| * Builds the hashtable we use for mapping the string version |
| * of a smiley (e.g. ":-)") to a resource ID for the icon version. |
| */ |
| private HashMap<String, Integer> buildSmileyToRes() { |
| if (DEFAULT_SMILEY_RES_IDS.length != mSmileyTexts.length) { |
| // Throw an exception if someone updated DEFAULT_SMILEY_RES_IDS |
| // and failed to update arrays.xml |
| throw new IllegalStateException("Smiley resource ID/text mismatch"); |
| } |
| |
| HashMap<String, Integer> smileyToRes = |
| new HashMap<String, Integer>(mSmileyTexts.length); |
| for (int i = 0; i < mSmileyTexts.length; i++) { |
| smileyToRes.put(mSmileyTexts[i], DEFAULT_SMILEY_RES_IDS[i]); |
| } |
| |
| return smileyToRes; |
| } |
| |
| /** |
| * Builds the regular expression we use to find smileys in {@link #addSmileySpans}. |
| */ |
| private Pattern buildPattern() { |
| // Set the StringBuilder capacity with the assumption that the average |
| // smiley is 3 characters long. |
| StringBuilder patternString = new StringBuilder(mSmileyTexts.length * 3); |
| |
| // Build a regex that looks like (:-)|:-(|...), but escaping the smilies |
| // properly so they will be interpreted literally by the regex matcher. |
| patternString.append('('); |
| for (String s : mSmileyTexts) { |
| patternString.append(Pattern.quote(s)); |
| patternString.append('|'); |
| } |
| // Replace the extra '|' with a ')' |
| patternString.replace(patternString.length() - 1, patternString.length(), ")"); |
| |
| return Pattern.compile(patternString.toString()); |
| } |
| |
| |
| /** |
| * Adds ImageSpans to a CharSequence that replace textual emoticons such |
| * as :-) with a graphical version. |
| * |
| * @param text A CharSequence possibly containing emoticons |
| * @return A CharSequence annotated with ImageSpans covering any |
| * recognized emoticons. |
| */ |
| public CharSequence addSmileySpans(CharSequence text) { |
| SpannableStringBuilder builder = new SpannableStringBuilder(text); |
| |
| Matcher matcher = mPattern.matcher(text); |
| while (matcher.find()) { |
| int resId = mSmileyToRes.get(matcher.group()); |
| builder.setSpan(new ImageSpan(mContext, resId), |
| matcher.start(), matcher.end(), |
| Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); |
| } |
| |
| return builder; |
| } |
| } |
| |
| |