Home | History | Annotate | Download | only in latin
      1 /*
      2  * Copyright (C) 2008 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
      5  * use this file except in compliance with the License. You may obtain a copy of
      6  * 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, WITHOUT
     12  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
     13  * License for the specific language governing permissions and limitations under
     14  * the License.
     15  */
     16 
     17 package com.android.inputmethod.latin;
     18 
     19 import com.android.inputmethod.keyboard.Keyboard;
     20 import com.android.inputmethod.latin.Utils.RingCharBuffer;
     21 
     22 import android.util.Log;
     23 
     24 public class TextEntryState {
     25     private static final String TAG = TextEntryState.class.getSimpleName();
     26     private static final boolean DEBUG = false;
     27 
     28     private static final int UNKNOWN = 0;
     29     private static final int START = 1;
     30     private static final int IN_WORD = 2;
     31     private static final int ACCEPTED_DEFAULT = 3;
     32     private static final int PICKED_SUGGESTION = 4;
     33     private static final int PUNCTUATION_AFTER_WORD = 5;
     34     private static final int PUNCTUATION_AFTER_ACCEPTED = 6;
     35     private static final int SPACE_AFTER_ACCEPTED = 7;
     36     private static final int SPACE_AFTER_PICKED = 8;
     37     private static final int UNDO_COMMIT = 9;
     38     private static final int RECORRECTING = 10;
     39     private static final int PICKED_RECORRECTION = 11;
     40 
     41     private static int sState = UNKNOWN;
     42     private static int sPreviousState = UNKNOWN;
     43 
     44     private static void setState(final int newState) {
     45         sPreviousState = sState;
     46         sState = newState;
     47     }
     48 
     49     public static void acceptedDefault(CharSequence typedWord, CharSequence actualWord,
     50             int separatorCode) {
     51         if (typedWord == null) return;
     52         setState(ACCEPTED_DEFAULT);
     53         LatinImeLogger.logOnAutoCorrection(
     54                 typedWord.toString(), actualWord.toString(), separatorCode);
     55         if (DEBUG)
     56             displayState("acceptedDefault", "typedWord", typedWord, "actualWord", actualWord);
     57     }
     58 
     59     // State.ACCEPTED_DEFAULT will be changed to other sub-states
     60     // (see "case ACCEPTED_DEFAULT" in typedCharacter() below),
     61     // and should be restored back to State.ACCEPTED_DEFAULT after processing for each sub-state.
     62     public static void backToAcceptedDefault(CharSequence typedWord) {
     63         if (typedWord == null) return;
     64         switch (sState) {
     65         case SPACE_AFTER_ACCEPTED:
     66         case PUNCTUATION_AFTER_ACCEPTED:
     67         case IN_WORD:
     68             setState(ACCEPTED_DEFAULT);
     69             break;
     70         default:
     71             break;
     72         }
     73         if (DEBUG) displayState("backToAcceptedDefault", "typedWord", typedWord);
     74     }
     75 
     76     public static void acceptedTyped(CharSequence typedWord) {
     77         setState(PICKED_SUGGESTION);
     78         if (DEBUG) displayState("acceptedTyped", "typedWord", typedWord);
     79     }
     80 
     81     public static void acceptedSuggestion(CharSequence typedWord, CharSequence actualWord) {
     82         if (sState == RECORRECTING || sState == PICKED_RECORRECTION) {
     83             setState(PICKED_RECORRECTION);
     84         } else {
     85             setState(PICKED_SUGGESTION);
     86         }
     87         if (DEBUG)
     88             displayState("acceptedSuggestion", "typedWord", typedWord, "actualWord", actualWord);
     89     }
     90 
     91     public static void selectedForRecorrection() {
     92         setState(RECORRECTING);
     93         if (DEBUG) displayState("selectedForRecorrection");
     94     }
     95 
     96     public static void onAbortRecorrection() {
     97         if (sState == RECORRECTING || sState == PICKED_RECORRECTION) {
     98             setState(START);
     99         }
    100         if (DEBUG) displayState("onAbortRecorrection");
    101     }
    102 
    103     public static void typedCharacter(char c, boolean isSeparator, int x, int y) {
    104         final boolean isSpace = (c == Keyboard.CODE_SPACE);
    105         switch (sState) {
    106         case IN_WORD:
    107             if (isSpace || isSeparator) {
    108                 setState(START);
    109             } else {
    110                 // State hasn't changed.
    111             }
    112             break;
    113         case ACCEPTED_DEFAULT:
    114         case SPACE_AFTER_PICKED:
    115         case PUNCTUATION_AFTER_ACCEPTED:
    116             if (isSpace) {
    117                 setState(SPACE_AFTER_ACCEPTED);
    118             } else if (isSeparator) {
    119                 // Swap
    120                 setState(PUNCTUATION_AFTER_ACCEPTED);
    121             } else {
    122                 setState(IN_WORD);
    123             }
    124             break;
    125         case PICKED_SUGGESTION:
    126         case PICKED_RECORRECTION:
    127             if (isSpace) {
    128                 setState(SPACE_AFTER_PICKED);
    129             } else if (isSeparator) {
    130                 // Swap
    131                 setState(PUNCTUATION_AFTER_ACCEPTED);
    132             } else {
    133                 setState(IN_WORD);
    134             }
    135             break;
    136         case START:
    137         case UNKNOWN:
    138         case SPACE_AFTER_ACCEPTED:
    139         case PUNCTUATION_AFTER_WORD:
    140             if (!isSpace && !isSeparator) {
    141                 setState(IN_WORD);
    142             } else {
    143                 setState(START);
    144             }
    145             break;
    146         case UNDO_COMMIT:
    147             if (isSpace || isSeparator) {
    148                 setState(START);
    149             } else {
    150                 setState(IN_WORD);
    151             }
    152             break;
    153         case RECORRECTING:
    154             setState(START);
    155             break;
    156         }
    157         RingCharBuffer.getInstance().push(c, x, y);
    158         if (isSeparator) {
    159             LatinImeLogger.logOnInputSeparator();
    160         } else {
    161             LatinImeLogger.logOnInputChar();
    162         }
    163         if (DEBUG) displayState("typedCharacter", "char", c, "isSeparator", isSeparator);
    164     }
    165 
    166     public static void backspace() {
    167         if (sState == ACCEPTED_DEFAULT) {
    168             setState(UNDO_COMMIT);
    169             LatinImeLogger.logOnAutoCorrectionCancelled();
    170         } else if (sState == UNDO_COMMIT) {
    171             setState(IN_WORD);
    172         }
    173         if (DEBUG) displayState("backspace");
    174     }
    175 
    176     public static void reset() {
    177         setState(START);
    178         if (DEBUG) displayState("reset");
    179     }
    180 
    181     public static boolean isAcceptedDefault() {
    182         return sState == ACCEPTED_DEFAULT;
    183     }
    184 
    185     public static boolean isSpaceAfterPicked() {
    186         return sState == SPACE_AFTER_PICKED;
    187     }
    188 
    189     public static boolean isUndoCommit() {
    190         return sState == UNDO_COMMIT;
    191     }
    192 
    193     public static boolean isPunctuationAfterAccepted() {
    194         return sState == PUNCTUATION_AFTER_ACCEPTED;
    195     }
    196 
    197     public static boolean isRecorrecting() {
    198         return sState == RECORRECTING || sState == PICKED_RECORRECTION;
    199     }
    200 
    201     public static String getState() {
    202         return stateName(sState);
    203     }
    204 
    205     private static String stateName(int state) {
    206         switch (state) {
    207         case START: return "START";
    208         case IN_WORD: return "IN_WORD";
    209         case ACCEPTED_DEFAULT: return "ACCEPTED_DEFAULT";
    210         case PICKED_SUGGESTION: return "PICKED_SUGGESTION";
    211         case PUNCTUATION_AFTER_WORD: return "PUNCTUATION_AFTER_WORD";
    212         case PUNCTUATION_AFTER_ACCEPTED: return "PUNCTUATION_AFTER_ACCEPTED";
    213         case SPACE_AFTER_ACCEPTED: return "SPACE_AFTER_ACCEPTED";
    214         case SPACE_AFTER_PICKED: return "SPACE_AFTER_PICKED";
    215         case UNDO_COMMIT: return "UNDO_COMMIT";
    216         case RECORRECTING: return "RECORRECTING";
    217         case PICKED_RECORRECTION: return "PICKED_RECORRECTION";
    218         default: return "UNKNOWN";
    219         }
    220     }
    221 
    222     private static void displayState(String title, Object ... args) {
    223         final StringBuilder sb = new StringBuilder(title);
    224         sb.append(':');
    225         for (int i = 0; i < args.length; i += 2) {
    226             sb.append(' ');
    227             sb.append(args[i]);
    228             sb.append('=');
    229             sb.append(args[i+1].toString());
    230         }
    231         sb.append(" state=");
    232         sb.append(stateName(sState));
    233         sb.append(" previous=");
    234         sb.append(stateName(sPreviousState));
    235         Log.d(TAG, sb.toString());
    236     }
    237 }
    238