Home | History | Annotate | Download | only in pinyin
      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.inputmethod.pinyin;
     18 
     19 import com.android.inputmethod.pinyin.SoftKeyboard.KeyRow;
     20 
     21 import android.content.res.Resources;
     22 import android.view.inputmethod.EditorInfo;
     23 
     24 /**
     25  * Switcher used to switching input mode between Chinese, English, symbol,etc.
     26  */
     27 public class InputModeSwitcher {
     28     /**
     29      * User defined key code, used by soft keyboard.
     30      */
     31     private static final int USERDEF_KEYCODE_SHIFT_1 = -1;
     32 
     33     /**
     34      * User defined key code, used by soft keyboard.
     35      */
     36     private static final int USERDEF_KEYCODE_LANG_2 = -2;
     37 
     38     /**
     39      * User defined key code, used by soft keyboard.
     40      */
     41     private static final int USERDEF_KEYCODE_SYM_3 = -3;
     42 
     43     /**
     44      * User defined key code, used by soft keyboard.
     45      */
     46     public static final int USERDEF_KEYCODE_PHONE_SYM_4 = -4;
     47 
     48     /**
     49      * User defined key code, used by soft keyboard.
     50      */
     51     private static final int USERDEF_KEYCODE_MORE_SYM_5 = -5;
     52 
     53     /**
     54      * User defined key code, used by soft keyboard.
     55      */
     56     private static final int USERDEF_KEYCODE_SMILEY_6 = -6;
     57 
     58 
     59     /**
     60      * Bits used to indicate soft keyboard layout. If none bit is set, the
     61      * current input mode does not require a soft keyboard.
     62      **/
     63     private static final int MASK_SKB_LAYOUT = 0xf0000000;
     64 
     65     /**
     66      * A kind of soft keyboard layout. An input mode should be anded with
     67      * {@link #MASK_SKB_LAYOUT} to get its soft keyboard layout.
     68      */
     69     private static final int MASK_SKB_LAYOUT_QWERTY = 0x10000000;
     70 
     71     /**
     72      * A kind of soft keyboard layout. An input mode should be anded with
     73      * {@link #MASK_SKB_LAYOUT} to get its soft keyboard layout.
     74      */
     75     private static final int MASK_SKB_LAYOUT_SYMBOL1 = 0x20000000;
     76 
     77     /**
     78      * A kind of soft keyboard layout. An input mode should be anded with
     79      * {@link #MASK_SKB_LAYOUT} to get its soft keyboard layout.
     80      */
     81     private static final int MASK_SKB_LAYOUT_SYMBOL2 = 0x30000000;
     82 
     83     /**
     84      * A kind of soft keyboard layout. An input mode should be anded with
     85      * {@link #MASK_SKB_LAYOUT} to get its soft keyboard layout.
     86      */
     87     private static final int MASK_SKB_LAYOUT_SMILEY = 0x40000000;
     88 
     89     /**
     90      * A kind of soft keyboard layout. An input mode should be anded with
     91      * {@link #MASK_SKB_LAYOUT} to get its soft keyboard layout.
     92      */
     93     private static final int MASK_SKB_LAYOUT_PHONE = 0x50000000;
     94 
     95     /**
     96      * Used to indicate which language the current input mode is in. If the
     97      * current input mode works with a none-QWERTY soft keyboard, these bits are
     98      * also used to get language information. For example, a Chinese symbol soft
     99      * keyboard and an English one are different in an icon which is used to
    100      * tell user the language information. BTW, the smiley soft keyboard mode
    101      * should be set with {@link #MASK_LANGUAGE_CN} because it can only be
    102      * launched from Chinese QWERTY soft keyboard, and it has Chinese icon on
    103      * soft keyboard.
    104      */
    105     private static final int MASK_LANGUAGE = 0x0f000000;
    106 
    107     /**
    108      * Used to indicate the current language. An input mode should be anded with
    109      * {@link #MASK_LANGUAGE} to get this information.
    110      */
    111     private static final int MASK_LANGUAGE_CN = 0x01000000;
    112 
    113     /**
    114      * Used to indicate the current language. An input mode should be anded with
    115      * {@link #MASK_LANGUAGE} to get this information.
    116      */
    117     private static final int MASK_LANGUAGE_EN = 0x02000000;
    118 
    119     /**
    120      * Used to indicate which case the current input mode is in. For example,
    121      * English QWERTY has lowercase and uppercase. For the Chinese QWERTY, these
    122      * bits are ignored. For phone keyboard layout, these bits can be
    123      * {@link #MASK_CASE_UPPER} to request symbol page for phone soft keyboard.
    124      */
    125     private static final int MASK_CASE = 0x00f00000;
    126 
    127     /**
    128      * Used to indicate the current case information. An input mode should be
    129      * anded with {@link #MASK_CASE} to get this information.
    130      */
    131     private static final int MASK_CASE_LOWER = 0x00100000;
    132 
    133     /**
    134      * Used to indicate the current case information. An input mode should be
    135      * anded with {@link #MASK_CASE} to get this information.
    136      */
    137     private static final int MASK_CASE_UPPER = 0x00200000;
    138 
    139     /**
    140      * Mode for inputing Chinese with soft keyboard.
    141      */
    142     public static final int MODE_SKB_CHINESE = (MASK_SKB_LAYOUT_QWERTY | MASK_LANGUAGE_CN);
    143 
    144     /**
    145      * Mode for inputing basic symbols for Chinese mode with soft keyboard.
    146      */
    147     public static final int MODE_SKB_SYMBOL1_CN = (MASK_SKB_LAYOUT_SYMBOL1 | MASK_LANGUAGE_CN);
    148 
    149     /**
    150      * Mode for inputing more symbols for Chinese mode with soft keyboard.
    151      */
    152     public static final int MODE_SKB_SYMBOL2_CN = (MASK_SKB_LAYOUT_SYMBOL2 | MASK_LANGUAGE_CN);
    153 
    154     /**
    155      * Mode for inputing English lower characters with soft keyboard.
    156      */
    157     public static final int MODE_SKB_ENGLISH_LOWER = (MASK_SKB_LAYOUT_QWERTY
    158             | MASK_LANGUAGE_EN | MASK_CASE_LOWER);
    159 
    160     /**
    161      * Mode for inputing English upper characters with soft keyboard.
    162      */
    163     public static final int MODE_SKB_ENGLISH_UPPER = (MASK_SKB_LAYOUT_QWERTY
    164             | MASK_LANGUAGE_EN | MASK_CASE_UPPER);
    165 
    166     /**
    167      * Mode for inputing basic symbols for English mode with soft keyboard.
    168      */
    169     public static final int MODE_SKB_SYMBOL1_EN = (MASK_SKB_LAYOUT_SYMBOL1 | MASK_LANGUAGE_EN);
    170 
    171     /**
    172      * Mode for inputing more symbols for English mode with soft keyboard.
    173      */
    174     public static final int MODE_SKB_SYMBOL2_EN = (MASK_SKB_LAYOUT_SYMBOL2 | MASK_LANGUAGE_EN);
    175 
    176     /**
    177      * Mode for inputing smileys with soft keyboard.
    178      */
    179     public static final int MODE_SKB_SMILEY = (MASK_SKB_LAYOUT_SMILEY | MASK_LANGUAGE_CN);
    180 
    181     /**
    182      * Mode for inputing phone numbers.
    183      */
    184     public static final int MODE_SKB_PHONE_NUM = (MASK_SKB_LAYOUT_PHONE);
    185 
    186     /**
    187      * Mode for inputing phone numbers.
    188      */
    189     public static final int MODE_SKB_PHONE_SYM = (MASK_SKB_LAYOUT_PHONE | MASK_CASE_UPPER);
    190 
    191     /**
    192      * Mode for inputing Chinese with a hardware keyboard.
    193      */
    194     public static final int MODE_HKB_CHINESE = (MASK_LANGUAGE_CN);
    195 
    196     /**
    197      * Mode for inputing English with a hardware keyboard
    198      */
    199     public static final int MODE_HKB_ENGLISH = (MASK_LANGUAGE_EN);
    200 
    201     /**
    202      * Unset mode.
    203      */
    204     public static final int MODE_UNSET = 0;
    205 
    206     /**
    207      * Maximum toggle states for a soft keyboard.
    208      */
    209     public static final int MAX_TOGGLE_STATES = 4;
    210 
    211     /**
    212      * The input mode for the current edit box.
    213      */
    214     private int mInputMode = MODE_UNSET;
    215 
    216     /**
    217      * Used to remember previous input mode. When user enters an edit field, the
    218      * previous input mode will be tried. If the previous mode can not be used
    219      * for the current situation (For example, previous mode is a soft keyboard
    220      * mode to input symbols, and we have a hardware keyboard for the current
    221      * situation), {@link #mRecentLauageInputMode} will be tried.
    222      **/
    223     private int mPreviousInputMode = MODE_SKB_CHINESE;
    224 
    225     /**
    226      * Used to remember recent mode to input language.
    227      */
    228     private int mRecentLauageInputMode = MODE_SKB_CHINESE;
    229 
    230     /**
    231      * Editor information of the current edit box.
    232      */
    233     private EditorInfo mEditorInfo;
    234 
    235     /**
    236      * Used to indicate required toggling operations.
    237      */
    238     private ToggleStates mToggleStates = new ToggleStates();
    239 
    240     /**
    241      * The current field is a short message field?
    242      */
    243     private boolean mShortMessageField;
    244 
    245     /**
    246      * Is return key in normal state?
    247      */
    248     private boolean mEnterKeyNormal = true;
    249 
    250     /**
    251      * Current icon. 0 for none icon.
    252      */
    253     int mInputIcon = R.drawable.ime_pinyin;
    254 
    255     /**
    256      * IME service.
    257      */
    258     private PinyinIME mImeService;
    259 
    260     /**
    261      * Key toggling state for Chinese mode.
    262      */
    263     private int mToggleStateCn;
    264 
    265     /**
    266      * Key toggling state for Chinese mode with candidates.
    267      */
    268     private int mToggleStateCnCand;
    269 
    270     /**
    271      * Key toggling state for English lowwercase mode.
    272      */
    273     private int mToggleStateEnLower;
    274 
    275     /**
    276      * Key toggling state for English upppercase mode.
    277      */
    278     private int mToggleStateEnUpper;
    279 
    280     /**
    281      * Key toggling state for English symbol mode for the first page.
    282      */
    283     private int mToggleStateEnSym1;
    284 
    285     /**
    286      * Key toggling state for English symbol mode for the second page.
    287      */
    288     private int mToggleStateEnSym2;
    289 
    290     /**
    291      * Key toggling state for smiley mode.
    292      */
    293     private int mToggleStateSmiley;
    294 
    295     /**
    296      * Key toggling state for phone symbol mode.
    297      */
    298     private int mToggleStatePhoneSym;
    299 
    300     /**
    301      * Key toggling state for GO action of ENTER key.
    302      */
    303     private int mToggleStateGo;
    304 
    305     /**
    306      * Key toggling state for SEARCH action of ENTER key.
    307      */
    308     private int mToggleStateSearch;
    309 
    310     /**
    311      * Key toggling state for SEND action of ENTER key.
    312      */
    313     private int mToggleStateSend;
    314 
    315     /**
    316      * Key toggling state for NEXT action of ENTER key.
    317      */
    318     private int mToggleStateNext;
    319 
    320     /**
    321      * Key toggling state for SEND action of ENTER key.
    322      */
    323     private int mToggleStateDone;
    324 
    325     /**
    326      * QWERTY row toggling state for Chinese input.
    327      */
    328     private int mToggleRowCn;
    329 
    330     /**
    331      * QWERTY row toggling state for English input.
    332      */
    333     private int mToggleRowEn;
    334 
    335     /**
    336      * QWERTY row toggling state for URI input.
    337      */
    338     private int mToggleRowUri;
    339 
    340     /**
    341      * QWERTY row toggling state for email address input.
    342      */
    343     private int mToggleRowEmailAddress;
    344 
    345     class ToggleStates {
    346         /**
    347          * If it is true, this soft keyboard is a QWERTY one.
    348          */
    349         boolean mQwerty;
    350 
    351         /**
    352          * If {@link #mQwerty} is true, this variable is used to decide the
    353          * letter case of the QWERTY keyboard.
    354          */
    355         boolean mQwertyUpperCase;
    356 
    357         /**
    358          * The id of enabled row in the soft keyboard. Refer to
    359          * {@link com.android.inputmethod.pinyin.SoftKeyboard.KeyRow} for
    360          * details.
    361          */
    362         public int mRowIdToEnable;
    363 
    364         /**
    365          * Used to store all other toggle states for the current input mode.
    366          */
    367         public int mKeyStates[] = new int[MAX_TOGGLE_STATES];
    368 
    369         /**
    370          * Number of states to toggle.
    371          */
    372         public int mKeyStatesNum;
    373     }
    374 
    375     public InputModeSwitcher(PinyinIME imeService) {
    376         mImeService = imeService;
    377         Resources r = mImeService.getResources();
    378         mToggleStateCn = Integer.parseInt(r.getString(R.string.toggle_cn));
    379         mToggleStateCnCand = Integer.parseInt(r
    380                 .getString(R.string.toggle_cn_cand));
    381         mToggleStateEnLower = Integer.parseInt(r
    382                 .getString(R.string.toggle_en_lower));
    383         mToggleStateEnUpper = Integer.parseInt(r
    384                 .getString(R.string.toggle_en_upper));
    385         mToggleStateEnSym1 = Integer.parseInt(r
    386                 .getString(R.string.toggle_en_sym1));
    387         mToggleStateEnSym2 = Integer.parseInt(r
    388                 .getString(R.string.toggle_en_sym2));
    389         mToggleStateSmiley = Integer.parseInt(r
    390                 .getString(R.string.toggle_smiley));
    391         mToggleStatePhoneSym = Integer.parseInt(r
    392                 .getString(R.string.toggle_phone_sym));
    393 
    394         mToggleStateGo = Integer
    395                 .parseInt(r.getString(R.string.toggle_enter_go));
    396         mToggleStateSearch = Integer.parseInt(r
    397                 .getString(R.string.toggle_enter_search));
    398         mToggleStateSend = Integer.parseInt(r
    399                 .getString(R.string.toggle_enter_send));
    400         mToggleStateNext = Integer.parseInt(r
    401                 .getString(R.string.toggle_enter_next));
    402         mToggleStateDone = Integer.parseInt(r
    403                 .getString(R.string.toggle_enter_done));
    404 
    405         mToggleRowCn = Integer.parseInt(r.getString(R.string.toggle_row_cn));
    406         mToggleRowEn = Integer.parseInt(r.getString(R.string.toggle_row_en));
    407         mToggleRowUri = Integer.parseInt(r.getString(R.string.toggle_row_uri));
    408         mToggleRowEmailAddress = Integer.parseInt(r
    409                 .getString(R.string.toggle_row_emailaddress));
    410     }
    411 
    412     public int getInputMode() {
    413         return mInputMode;
    414     }
    415 
    416     public ToggleStates getToggleStates() {
    417         return mToggleStates;
    418     }
    419 
    420     public int getSkbLayout() {
    421         int layout = (mInputMode & MASK_SKB_LAYOUT);
    422 
    423         switch (layout) {
    424         case MASK_SKB_LAYOUT_QWERTY:
    425             return R.xml.skb_qwerty;
    426         case MASK_SKB_LAYOUT_SYMBOL1:
    427             return R.xml.skb_sym1;
    428         case MASK_SKB_LAYOUT_SYMBOL2:
    429             return R.xml.skb_sym2;
    430         case MASK_SKB_LAYOUT_SMILEY:
    431             return R.xml.skb_smiley;
    432         case MASK_SKB_LAYOUT_PHONE:
    433             return R.xml.skb_phone;
    434         }
    435         return 0;
    436     }
    437 
    438     // Return the icon to update.
    439     public int switchLanguageWithHkb() {
    440         int newInputMode = MODE_HKB_CHINESE;
    441         mInputIcon = R.drawable.ime_pinyin;
    442 
    443         if (MODE_HKB_CHINESE == mInputMode) {
    444             newInputMode = MODE_HKB_ENGLISH;
    445             mInputIcon = R.drawable.ime_en;
    446         }
    447 
    448         saveInputMode(newInputMode);
    449         return mInputIcon;
    450     }
    451 
    452     // Return the icon to update.
    453     public int switchModeForUserKey(int userKey) {
    454         int newInputMode = MODE_UNSET;
    455 
    456         if (USERDEF_KEYCODE_LANG_2 == userKey) {
    457             if (MODE_SKB_CHINESE == mInputMode) {
    458                 newInputMode = MODE_SKB_ENGLISH_LOWER;
    459             } else if (MODE_SKB_ENGLISH_LOWER == mInputMode
    460                     || MODE_SKB_ENGLISH_UPPER == mInputMode) {
    461                 newInputMode = MODE_SKB_CHINESE;
    462             } else if (MODE_SKB_SYMBOL1_CN == mInputMode) {
    463                 newInputMode = MODE_SKB_SYMBOL1_EN;
    464             } else if (MODE_SKB_SYMBOL1_EN == mInputMode) {
    465                 newInputMode = MODE_SKB_SYMBOL1_CN;
    466             } else if (MODE_SKB_SYMBOL2_CN == mInputMode) {
    467                 newInputMode = MODE_SKB_SYMBOL2_EN;
    468             } else if (MODE_SKB_SYMBOL2_EN == mInputMode) {
    469                 newInputMode = MODE_SKB_SYMBOL2_CN;
    470             } else if (MODE_SKB_SMILEY == mInputMode) {
    471                 newInputMode = MODE_SKB_CHINESE;
    472             }
    473         } else if (USERDEF_KEYCODE_SYM_3 == userKey) {
    474             if (MODE_SKB_CHINESE == mInputMode) {
    475                 newInputMode = MODE_SKB_SYMBOL1_CN;
    476             } else if (MODE_SKB_ENGLISH_UPPER == mInputMode
    477                     || MODE_SKB_ENGLISH_LOWER == mInputMode) {
    478                 newInputMode = MODE_SKB_SYMBOL1_EN;
    479             } else if (MODE_SKB_SYMBOL1_EN == mInputMode
    480                     || MODE_SKB_SYMBOL2_EN == mInputMode) {
    481                 newInputMode = MODE_SKB_ENGLISH_LOWER;
    482             } else if (MODE_SKB_SYMBOL1_CN == mInputMode
    483                     || MODE_SKB_SYMBOL2_CN == mInputMode) {
    484                 newInputMode = MODE_SKB_CHINESE;
    485             } else if (MODE_SKB_SMILEY == mInputMode) {
    486                 newInputMode = MODE_SKB_SYMBOL1_CN;
    487             }
    488         } else if (USERDEF_KEYCODE_SHIFT_1 == userKey) {
    489             if (MODE_SKB_ENGLISH_LOWER == mInputMode) {
    490                 newInputMode = MODE_SKB_ENGLISH_UPPER;
    491             } else if (MODE_SKB_ENGLISH_UPPER == mInputMode) {
    492                 newInputMode = MODE_SKB_ENGLISH_LOWER;
    493             }
    494         } else if (USERDEF_KEYCODE_MORE_SYM_5 == userKey) {
    495             int sym = (MASK_SKB_LAYOUT & mInputMode);
    496             if (MASK_SKB_LAYOUT_SYMBOL1 == sym) {
    497                 sym = MASK_SKB_LAYOUT_SYMBOL2;
    498             } else {
    499                 sym = MASK_SKB_LAYOUT_SYMBOL1;
    500             }
    501             newInputMode = ((mInputMode & (~MASK_SKB_LAYOUT)) | sym);
    502         } else if (USERDEF_KEYCODE_SMILEY_6 == userKey) {
    503             if (MODE_SKB_CHINESE == mInputMode) {
    504                 newInputMode = MODE_SKB_SMILEY;
    505             } else {
    506                 newInputMode = MODE_SKB_CHINESE;
    507             }
    508         } else if (USERDEF_KEYCODE_PHONE_SYM_4 == userKey) {
    509             if (MODE_SKB_PHONE_NUM == mInputMode) {
    510                 newInputMode = MODE_SKB_PHONE_SYM;
    511             } else {
    512                 newInputMode = MODE_SKB_PHONE_NUM;
    513             }
    514         }
    515 
    516         if (newInputMode == mInputMode || MODE_UNSET == newInputMode) {
    517             return mInputIcon;
    518         }
    519 
    520         saveInputMode(newInputMode);
    521         prepareToggleStates(true);
    522         return mInputIcon;
    523     }
    524 
    525     // Return the icon to update.
    526     public int requestInputWithHkb(EditorInfo editorInfo) {
    527         mShortMessageField = false;
    528         boolean english = false;
    529         int newInputMode = MODE_HKB_CHINESE;
    530 
    531         switch (editorInfo.inputType & EditorInfo.TYPE_MASK_CLASS) {
    532         case EditorInfo.TYPE_CLASS_NUMBER:
    533         case EditorInfo.TYPE_CLASS_PHONE:
    534         case EditorInfo.TYPE_CLASS_DATETIME:
    535             english = true;
    536             break;
    537         case EditorInfo.TYPE_CLASS_TEXT:
    538             int v = editorInfo.inputType & EditorInfo.TYPE_MASK_VARIATION;
    539             if (v == EditorInfo.TYPE_TEXT_VARIATION_EMAIL_ADDRESS
    540                     || v == EditorInfo.TYPE_TEXT_VARIATION_PASSWORD
    541                     || v == EditorInfo.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD
    542                     || v == EditorInfo.TYPE_TEXT_VARIATION_URI) {
    543                 english = true;
    544             } else if (v == EditorInfo.TYPE_TEXT_VARIATION_SHORT_MESSAGE) {
    545                 mShortMessageField = true;
    546             }
    547             break;
    548         default:
    549         }
    550 
    551         if (english) {
    552             // If the application request English mode, we switch to it.
    553             newInputMode = MODE_HKB_ENGLISH;
    554         } else {
    555             // If the application do not request English mode, we will
    556             // try to keep the previous mode to input language text.
    557             // Because there is not soft keyboard, we need discard all
    558             // soft keyboard related information from the previous language
    559             // mode.
    560             if ((mRecentLauageInputMode & MASK_LANGUAGE) == MASK_LANGUAGE_CN) {
    561                 newInputMode = MODE_HKB_CHINESE;
    562             } else {
    563                 newInputMode = MODE_HKB_ENGLISH;
    564             }
    565         }
    566         mEditorInfo = editorInfo;
    567         saveInputMode(newInputMode);
    568         prepareToggleStates(false);
    569         return mInputIcon;
    570     }
    571 
    572     // Return the icon to update.
    573     public int requestInputWithSkb(EditorInfo editorInfo) {
    574         mShortMessageField = false;
    575 
    576         int newInputMode = MODE_SKB_CHINESE;
    577 
    578         switch (editorInfo.inputType & EditorInfo.TYPE_MASK_CLASS) {
    579         case EditorInfo.TYPE_CLASS_NUMBER:
    580         case EditorInfo.TYPE_CLASS_DATETIME:
    581             newInputMode = MODE_SKB_SYMBOL1_EN;
    582             break;
    583         case EditorInfo.TYPE_CLASS_PHONE:
    584             newInputMode = MODE_SKB_PHONE_NUM;
    585             break;
    586         case EditorInfo.TYPE_CLASS_TEXT:
    587             int v = editorInfo.inputType & EditorInfo.TYPE_MASK_VARIATION;
    588             if (v == EditorInfo.TYPE_TEXT_VARIATION_EMAIL_ADDRESS
    589                     || v == EditorInfo.TYPE_TEXT_VARIATION_PASSWORD
    590                     || v == EditorInfo.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD
    591                     || v == EditorInfo.TYPE_TEXT_VARIATION_URI) {
    592                 // If the application request English mode, we switch to it.
    593                 newInputMode = MODE_SKB_ENGLISH_LOWER;
    594             } else {
    595                 if (v == EditorInfo.TYPE_TEXT_VARIATION_SHORT_MESSAGE) {
    596                     mShortMessageField = true;
    597                 }
    598                 // If the application do not request English mode, we will
    599                 // try to keep the previous mode.
    600                 int skbLayout = (mInputMode & MASK_SKB_LAYOUT);
    601                 newInputMode = mInputMode;
    602                 if (0 == skbLayout) {
    603                     if ((mInputMode & MASK_LANGUAGE) == MASK_LANGUAGE_CN) {
    604                         newInputMode = MODE_SKB_CHINESE;
    605                     } else {
    606                         newInputMode = MODE_SKB_ENGLISH_LOWER;
    607                     }
    608                 }
    609             }
    610             break;
    611         default:
    612             // Try to keep the previous mode.
    613             int skbLayout = (mInputMode & MASK_SKB_LAYOUT);
    614             newInputMode = mInputMode;
    615             if (0 == skbLayout) {
    616                 if ((mInputMode & MASK_LANGUAGE) == MASK_LANGUAGE_CN) {
    617                     newInputMode = MODE_SKB_CHINESE;
    618                 } else {
    619                     newInputMode = MODE_SKB_ENGLISH_LOWER;
    620                 }
    621             }
    622             break;
    623         }
    624 
    625         mEditorInfo = editorInfo;
    626         saveInputMode(newInputMode);
    627         prepareToggleStates(true);
    628         return mInputIcon;
    629     }
    630 
    631     // Return the icon to update.
    632     public int requestBackToPreviousSkb() {
    633         int layout = (mInputMode & MASK_SKB_LAYOUT);
    634         int lastLayout = (mPreviousInputMode & MASK_SKB_LAYOUT);
    635         if (0 != layout && 0 != lastLayout) {
    636             mInputMode = mPreviousInputMode;
    637             saveInputMode(mInputMode);
    638             prepareToggleStates(true);
    639             return mInputIcon;
    640         }
    641         return 0;
    642     }
    643 
    644     public int getTooggleStateForCnCand() {
    645         return mToggleStateCnCand;
    646     }
    647 
    648     public boolean isEnglishWithHkb() {
    649         return MODE_HKB_ENGLISH == mInputMode;
    650     }
    651 
    652     public boolean isEnglishWithSkb() {
    653         return MODE_SKB_ENGLISH_LOWER == mInputMode
    654                 || MODE_SKB_ENGLISH_UPPER == mInputMode;
    655     }
    656 
    657     public boolean isEnglishUpperCaseWithSkb() {
    658         return MODE_SKB_ENGLISH_UPPER == mInputMode;
    659     }
    660 
    661     public boolean isChineseText() {
    662         int skbLayout = (mInputMode & MASK_SKB_LAYOUT);
    663         if (MASK_SKB_LAYOUT_QWERTY == skbLayout || 0 == skbLayout) {
    664             int language = (mInputMode & MASK_LANGUAGE);
    665             if (MASK_LANGUAGE_CN == language) return true;
    666         }
    667         return false;
    668     }
    669 
    670     public boolean isChineseTextWithHkb() {
    671         int skbLayout = (mInputMode & MASK_SKB_LAYOUT);
    672         if (0 == skbLayout) {
    673             int language = (mInputMode & MASK_LANGUAGE);
    674             if (MASK_LANGUAGE_CN == language) return true;
    675         }
    676         return false;
    677     }
    678 
    679     public boolean isChineseTextWithSkb() {
    680         int skbLayout = (mInputMode & MASK_SKB_LAYOUT);
    681         if (MASK_SKB_LAYOUT_QWERTY == skbLayout) {
    682             int language = (mInputMode & MASK_LANGUAGE);
    683             if (MASK_LANGUAGE_CN == language) return true;
    684         }
    685         return false;
    686     }
    687 
    688     public boolean isSymbolWithSkb() {
    689         int skbLayout = (mInputMode & MASK_SKB_LAYOUT);
    690         if (MASK_SKB_LAYOUT_SYMBOL1 == skbLayout
    691                 || MASK_SKB_LAYOUT_SYMBOL2 == skbLayout) {
    692             return true;
    693         }
    694         return false;
    695     }
    696 
    697     public boolean isEnterNoramlState() {
    698         return mEnterKeyNormal;
    699     }
    700 
    701     public boolean tryHandleLongPressSwitch(int keyCode) {
    702         if (USERDEF_KEYCODE_LANG_2 == keyCode
    703                 || USERDEF_KEYCODE_PHONE_SYM_4 == keyCode) {
    704             mImeService.showOptionsMenu();
    705             return true;
    706         }
    707         return false;
    708     }
    709 
    710     private void saveInputMode(int newInputMode) {
    711         mPreviousInputMode = mInputMode;
    712         mInputMode = newInputMode;
    713 
    714         int skbLayout = (mInputMode & MASK_SKB_LAYOUT);
    715         if (MASK_SKB_LAYOUT_QWERTY == skbLayout || 0 == skbLayout) {
    716             mRecentLauageInputMode = mInputMode;
    717         }
    718 
    719         mInputIcon = R.drawable.ime_pinyin;
    720         if (isEnglishWithHkb()) {
    721             mInputIcon = R.drawable.ime_en;
    722         } else if (isChineseTextWithHkb()) {
    723             mInputIcon = R.drawable.ime_pinyin;
    724         }
    725 
    726         if (!Environment.getInstance().hasHardKeyboard()) {
    727             mInputIcon = 0;
    728         }
    729     }
    730 
    731     private void prepareToggleStates(boolean needSkb) {
    732         mEnterKeyNormal = true;
    733         if (!needSkb) return;
    734 
    735         mToggleStates.mQwerty = false;
    736         mToggleStates.mKeyStatesNum = 0;
    737 
    738         int states[] = mToggleStates.mKeyStates;
    739         int statesNum = 0;
    740         // Toggle state for language.
    741         int language = (mInputMode & MASK_LANGUAGE);
    742         int layout = (mInputMode & MASK_SKB_LAYOUT);
    743         int charcase = (mInputMode & MASK_CASE);
    744         int variation = mEditorInfo.inputType & EditorInfo.TYPE_MASK_VARIATION;
    745 
    746         if (MASK_SKB_LAYOUT_PHONE != layout) {
    747             if (MASK_LANGUAGE_CN == language) {
    748                 // Chinese and Chinese symbol are always the default states,
    749                 // do not add a toggling operation.
    750                 if (MASK_SKB_LAYOUT_QWERTY == layout) {
    751                     mToggleStates.mQwerty = true;
    752                     mToggleStates.mQwertyUpperCase = true;
    753                     if (mShortMessageField) {
    754                         states[statesNum] = mToggleStateSmiley;
    755                         statesNum++;
    756                     }
    757                 }
    758             } else if (MASK_LANGUAGE_EN == language) {
    759                 if (MASK_SKB_LAYOUT_QWERTY == layout) {
    760                     mToggleStates.mQwerty = true;
    761                     mToggleStates.mQwertyUpperCase = false;
    762                     states[statesNum] = mToggleStateEnLower;
    763                     if (MASK_CASE_UPPER == charcase) {
    764                         mToggleStates.mQwertyUpperCase = true;
    765                         states[statesNum] = mToggleStateEnUpper;
    766                     }
    767                     statesNum++;
    768                 } else if (MASK_SKB_LAYOUT_SYMBOL1 == layout) {
    769                     states[statesNum] = mToggleStateEnSym1;
    770                     statesNum++;
    771                 } else if (MASK_SKB_LAYOUT_SYMBOL2 == layout) {
    772                     states[statesNum] = mToggleStateEnSym2;
    773                     statesNum++;
    774                 }
    775             }
    776 
    777             // Toggle rows for QWERTY.
    778             mToggleStates.mRowIdToEnable = KeyRow.DEFAULT_ROW_ID;
    779             if (variation == EditorInfo.TYPE_TEXT_VARIATION_EMAIL_ADDRESS) {
    780                 mToggleStates.mRowIdToEnable = mToggleRowEmailAddress;
    781             } else if (variation == EditorInfo.TYPE_TEXT_VARIATION_URI) {
    782                 mToggleStates.mRowIdToEnable = mToggleRowUri;
    783             } else if (MASK_LANGUAGE_CN == language) {
    784                 mToggleStates.mRowIdToEnable = mToggleRowCn;
    785             } else if (MASK_LANGUAGE_EN == language) {
    786                 mToggleStates.mRowIdToEnable = mToggleRowEn;
    787             }
    788         } else {
    789             if (MASK_CASE_UPPER == charcase) {
    790                 states[statesNum] = mToggleStatePhoneSym;
    791                 statesNum++;
    792             }
    793         }
    794 
    795         // Toggle state for enter key.
    796         int action = mEditorInfo.imeOptions
    797                 & (EditorInfo.IME_MASK_ACTION | EditorInfo.IME_FLAG_NO_ENTER_ACTION);
    798 
    799         if (action == EditorInfo.IME_ACTION_GO) {
    800             states[statesNum] = mToggleStateGo;
    801             statesNum++;
    802             mEnterKeyNormal = false;
    803         } else if (action == EditorInfo.IME_ACTION_SEARCH) {
    804             states[statesNum] = mToggleStateSearch;
    805             statesNum++;
    806             mEnterKeyNormal = false;
    807         } else if (action == EditorInfo.IME_ACTION_SEND) {
    808             states[statesNum] = mToggleStateSend;
    809             statesNum++;
    810             mEnterKeyNormal = false;
    811         } else if (action == EditorInfo.IME_ACTION_NEXT) {
    812             int f = mEditorInfo.inputType & EditorInfo.TYPE_MASK_FLAGS;
    813             if (f != EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE) {
    814                 states[statesNum] = mToggleStateNext;
    815                 statesNum++;
    816                 mEnterKeyNormal = false;
    817             }
    818         } else if (action == EditorInfo.IME_ACTION_DONE) {
    819             states[statesNum] = mToggleStateDone;
    820             statesNum++;
    821             mEnterKeyNormal = false;
    822         }
    823         mToggleStates.mKeyStatesNum = statesNum;
    824     }
    825 }
    826