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