Home | History | Annotate | Download | only in util
      1 /*
      2  * Copyright (C) 2009 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.mms.util;
     18 
     19 import android.content.Context;
     20 import android.text.Spannable;
     21 import android.text.SpannableStringBuilder;
     22 import android.text.style.ImageSpan;
     23 
     24 import com.android.mms.R;
     25 
     26 import java.util.HashMap;
     27 import java.util.regex.Matcher;
     28 import java.util.regex.Pattern;
     29 
     30 /**
     31  * A class for annotating a CharSequence with spans to convert textual emoticons
     32  * to graphical ones.
     33  */
     34 public class SmileyParser {
     35     // Singleton stuff
     36     private static SmileyParser sInstance;
     37     public static SmileyParser getInstance() { return sInstance; }
     38     public static void init(Context context) {
     39         sInstance = new SmileyParser(context);
     40     }
     41 
     42     private final Context mContext;
     43     private final String[] mSmileyTexts;
     44     private final Pattern mPattern;
     45     private final HashMap<String, Integer> mSmileyToRes;
     46 
     47     private SmileyParser(Context context) {
     48         mContext = context;
     49         mSmileyTexts = mContext.getResources().getStringArray(DEFAULT_SMILEY_TEXTS);
     50         mSmileyToRes = buildSmileyToRes();
     51         mPattern = buildPattern();
     52     }
     53 
     54     static class Smileys {
     55         private static final int[] sIconIds = {
     56             R.drawable.emo_im_happy,
     57             R.drawable.emo_im_sad,
     58             R.drawable.emo_im_winking,
     59             R.drawable.emo_im_tongue_sticking_out,
     60             R.drawable.emo_im_surprised,
     61             R.drawable.emo_im_kissing,
     62             R.drawable.emo_im_yelling,
     63             R.drawable.emo_im_cool,
     64             R.drawable.emo_im_money_mouth,
     65             R.drawable.emo_im_foot_in_mouth,
     66             R.drawable.emo_im_embarrassed,
     67             R.drawable.emo_im_angel,
     68             R.drawable.emo_im_undecided,
     69             R.drawable.emo_im_crying,
     70             R.drawable.emo_im_lips_are_sealed,
     71             R.drawable.emo_im_laughing,
     72             R.drawable.emo_im_wtf
     73         };
     74 
     75         public static int HAPPY = 0;
     76         public static int SAD = 1;
     77         public static int WINKING = 2;
     78         public static int TONGUE_STICKING_OUT = 3;
     79         public static int SURPRISED = 4;
     80         public static int KISSING = 5;
     81         public static int YELLING = 6;
     82         public static int COOL = 7;
     83         public static int MONEY_MOUTH = 8;
     84         public static int FOOT_IN_MOUTH = 9;
     85         public static int EMBARRASSED = 10;
     86         public static int ANGEL = 11;
     87         public static int UNDECIDED = 12;
     88         public static int CRYING = 13;
     89         public static int LIPS_ARE_SEALED = 14;
     90         public static int LAUGHING = 15;
     91         public static int WTF = 16;
     92 
     93         public static int getSmileyResource(int which) {
     94             return sIconIds[which];
     95         }
     96     }
     97 
     98     // NOTE: if you change anything about this array, you must make the corresponding change
     99     // to the string arrays: default_smiley_texts and default_smiley_names in res/values/arrays.xml
    100     public static final int[] DEFAULT_SMILEY_RES_IDS = {
    101         Smileys.getSmileyResource(Smileys.HAPPY),                //  0
    102         Smileys.getSmileyResource(Smileys.SAD),                  //  1
    103         Smileys.getSmileyResource(Smileys.WINKING),              //  2
    104         Smileys.getSmileyResource(Smileys.TONGUE_STICKING_OUT),  //  3
    105         Smileys.getSmileyResource(Smileys.SURPRISED),            //  4
    106         Smileys.getSmileyResource(Smileys.KISSING),              //  5
    107         Smileys.getSmileyResource(Smileys.YELLING),              //  6
    108         Smileys.getSmileyResource(Smileys.COOL),                 //  7
    109         Smileys.getSmileyResource(Smileys.MONEY_MOUTH),          //  8
    110         Smileys.getSmileyResource(Smileys.FOOT_IN_MOUTH),        //  9
    111         Smileys.getSmileyResource(Smileys.EMBARRASSED),          //  10
    112         Smileys.getSmileyResource(Smileys.ANGEL),                //  11
    113         Smileys.getSmileyResource(Smileys.UNDECIDED),            //  12
    114         Smileys.getSmileyResource(Smileys.CRYING),               //  13
    115         Smileys.getSmileyResource(Smileys.LIPS_ARE_SEALED),      //  14
    116         Smileys.getSmileyResource(Smileys.LAUGHING),             //  15
    117         Smileys.getSmileyResource(Smileys.WTF),                   //  16
    118     };
    119 
    120     public static final int DEFAULT_SMILEY_TEXTS = R.array.default_smiley_texts;
    121     public static final int DEFAULT_SMILEY_NAMES = R.array.default_smiley_names;
    122 
    123     /**
    124      * Builds the hashtable we use for mapping the string version
    125      * of a smiley (e.g. ":-)") to a resource ID for the icon version.
    126      */
    127     private HashMap<String, Integer> buildSmileyToRes() {
    128         if (DEFAULT_SMILEY_RES_IDS.length != mSmileyTexts.length) {
    129             // Throw an exception if someone updated DEFAULT_SMILEY_RES_IDS
    130             // and failed to update arrays.xml
    131             throw new IllegalStateException("Smiley resource ID/text mismatch");
    132         }
    133 
    134         HashMap<String, Integer> smileyToRes =
    135                             new HashMap<String, Integer>(mSmileyTexts.length);
    136         for (int i = 0; i < mSmileyTexts.length; i++) {
    137             smileyToRes.put(mSmileyTexts[i], DEFAULT_SMILEY_RES_IDS[i]);
    138         }
    139 
    140         return smileyToRes;
    141     }
    142 
    143     /**
    144      * Builds the regular expression we use to find smileys in {@link #addSmileySpans}.
    145      */
    146     private Pattern buildPattern() {
    147         // Set the StringBuilder capacity with the assumption that the average
    148         // smiley is 3 characters long.
    149         StringBuilder patternString = new StringBuilder(mSmileyTexts.length * 3);
    150 
    151         // Build a regex that looks like (:-)|:-(|...), but escaping the smilies
    152         // properly so they will be interpreted literally by the regex matcher.
    153         patternString.append('(');
    154         for (String s : mSmileyTexts) {
    155             patternString.append(Pattern.quote(s));
    156             patternString.append('|');
    157         }
    158         // Replace the extra '|' with a ')'
    159         patternString.replace(patternString.length() - 1, patternString.length(), ")");
    160 
    161         return Pattern.compile(patternString.toString());
    162     }
    163 
    164 
    165     /**
    166      * Adds ImageSpans to a CharSequence that replace textual emoticons such
    167      * as :-) with a graphical version.
    168      *
    169      * @param text A CharSequence possibly containing emoticons
    170      * @return A CharSequence annotated with ImageSpans covering any
    171      *         recognized emoticons.
    172      */
    173     public CharSequence addSmileySpans(CharSequence text) {
    174         SpannableStringBuilder builder = new SpannableStringBuilder(text);
    175 
    176         Matcher matcher = mPattern.matcher(text);
    177         while (matcher.find()) {
    178             int resId = mSmileyToRes.get(matcher.group());
    179             builder.setSpan(new ImageSpan(mContext, resId),
    180                             matcher.start(), matcher.end(),
    181                             Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
    182         }
    183 
    184         return builder;
    185     }
    186 }
    187 
    188 
    189