• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 android.content.Context;
20 import android.inputmethodservice.Keyboard.Key;
21 import android.text.format.DateFormat;
22 import android.util.Log;
23 
24 import java.io.FileOutputStream;
25 import java.io.IOException;
26 import java.util.Calendar;
27 
28 public class TextEntryState {
29 
30     private static final boolean DBG = false;
31 
32     private static final String TAG = "TextEntryState";
33 
34     private static boolean LOGGING = false;
35 
36     private static int sBackspaceCount = 0;
37 
38     private static int sAutoSuggestCount = 0;
39 
40     private static int sAutoSuggestUndoneCount = 0;
41 
42     private static int sManualSuggestCount = 0;
43 
44     private static int sWordNotInDictionaryCount = 0;
45 
46     private static int sSessionCount = 0;
47 
48     private static int sTypedChars;
49 
50     private static int sActualChars;
51 
52     public enum State {
53         UNKNOWN,
54         START,
55         IN_WORD,
56         ACCEPTED_DEFAULT,
57         PICKED_SUGGESTION,
58         PUNCTUATION_AFTER_WORD,
59         PUNCTUATION_AFTER_ACCEPTED,
60         SPACE_AFTER_ACCEPTED,
61         SPACE_AFTER_PICKED,
62         UNDO_COMMIT,
63         CORRECTING,
64         PICKED_CORRECTION;
65     }
66 
67     private static State sState = State.UNKNOWN;
68 
69     private static FileOutputStream sKeyLocationFile;
70     private static FileOutputStream sUserActionFile;
71 
newSession(Context context)72     public static void newSession(Context context) {
73         sSessionCount++;
74         sAutoSuggestCount = 0;
75         sBackspaceCount = 0;
76         sAutoSuggestUndoneCount = 0;
77         sManualSuggestCount = 0;
78         sWordNotInDictionaryCount = 0;
79         sTypedChars = 0;
80         sActualChars = 0;
81         sState = State.START;
82 
83         if (LOGGING) {
84             try {
85                 sKeyLocationFile = context.openFileOutput("key.txt", Context.MODE_APPEND);
86                 sUserActionFile = context.openFileOutput("action.txt", Context.MODE_APPEND);
87             } catch (IOException ioe) {
88                 Log.e("TextEntryState", "Couldn't open file for output: " + ioe);
89             }
90         }
91     }
92 
endSession()93     public static void endSession() {
94         if (sKeyLocationFile == null) {
95             return;
96         }
97         try {
98             sKeyLocationFile.close();
99             // Write to log file
100             // Write timestamp, settings,
101             String out = DateFormat.format("MM:dd hh:mm:ss", Calendar.getInstance().getTime())
102                     .toString()
103                     + " BS: " + sBackspaceCount
104                     + " auto: " + sAutoSuggestCount
105                     + " manual: " + sManualSuggestCount
106                     + " typed: " + sWordNotInDictionaryCount
107                     + " undone: " + sAutoSuggestUndoneCount
108                     + " saved: " + ((float) (sActualChars - sTypedChars) / sActualChars)
109                     + "\n";
110             sUserActionFile.write(out.getBytes());
111             sUserActionFile.close();
112             sKeyLocationFile = null;
113             sUserActionFile = null;
114         } catch (IOException ioe) {
115 
116         }
117     }
118 
acceptedDefault(CharSequence typedWord, CharSequence actualWord)119     public static void acceptedDefault(CharSequence typedWord, CharSequence actualWord) {
120         if (typedWord == null) return;
121         if (!typedWord.equals(actualWord)) {
122             sAutoSuggestCount++;
123         }
124         sTypedChars += typedWord.length();
125         sActualChars += actualWord.length();
126         sState = State.ACCEPTED_DEFAULT;
127         LatinImeLogger.logOnAutoSuggestion(typedWord.toString(), actualWord.toString());
128         displayState();
129     }
130 
131     // State.ACCEPTED_DEFAULT will be changed to other sub-states
132     // (see "case ACCEPTED_DEFAULT" in typedCharacter() below),
133     // and should be restored back to State.ACCEPTED_DEFAULT after processing for each sub-state.
backToAcceptedDefault(CharSequence typedWord)134     public static void backToAcceptedDefault(CharSequence typedWord) {
135         if (typedWord == null) return;
136         switch (sState) {
137             case SPACE_AFTER_ACCEPTED:
138             case PUNCTUATION_AFTER_ACCEPTED:
139             case IN_WORD:
140                 sState = State.ACCEPTED_DEFAULT;
141                 break;
142         }
143         displayState();
144     }
145 
acceptedTyped(CharSequence typedWord)146     public static void acceptedTyped(CharSequence typedWord) {
147         sWordNotInDictionaryCount++;
148         sState = State.PICKED_SUGGESTION;
149         displayState();
150     }
151 
acceptedSuggestion(CharSequence typedWord, CharSequence actualWord)152     public static void acceptedSuggestion(CharSequence typedWord, CharSequence actualWord) {
153         sManualSuggestCount++;
154         State oldState = sState;
155         if (typedWord.equals(actualWord)) {
156             acceptedTyped(typedWord);
157         }
158         if (oldState == State.CORRECTING || oldState == State.PICKED_CORRECTION) {
159             sState = State.PICKED_CORRECTION;
160         } else {
161             sState = State.PICKED_SUGGESTION;
162         }
163         displayState();
164     }
165 
selectedForCorrection()166     public static void selectedForCorrection() {
167         sState = State.CORRECTING;
168         displayState();
169     }
170 
typedCharacter(char c, boolean isSeparator)171     public static void typedCharacter(char c, boolean isSeparator) {
172         boolean isSpace = c == ' ';
173         switch (sState) {
174             case IN_WORD:
175                 if (isSpace || isSeparator) {
176                     sState = State.START;
177                 } else {
178                     // State hasn't changed.
179                 }
180                 break;
181             case ACCEPTED_DEFAULT:
182             case SPACE_AFTER_PICKED:
183                 if (isSpace) {
184                     sState = State.SPACE_AFTER_ACCEPTED;
185                 } else if (isSeparator) {
186                     sState = State.PUNCTUATION_AFTER_ACCEPTED;
187                 } else {
188                     sState = State.IN_WORD;
189                 }
190                 break;
191             case PICKED_SUGGESTION:
192             case PICKED_CORRECTION:
193                 if (isSpace) {
194                     sState = State.SPACE_AFTER_PICKED;
195                 } else if (isSeparator) {
196                     // Swap
197                     sState = State.PUNCTUATION_AFTER_ACCEPTED;
198                 } else {
199                     sState = State.IN_WORD;
200                 }
201                 break;
202             case START:
203             case UNKNOWN:
204             case SPACE_AFTER_ACCEPTED:
205             case PUNCTUATION_AFTER_ACCEPTED:
206             case PUNCTUATION_AFTER_WORD:
207                 if (!isSpace && !isSeparator) {
208                     sState = State.IN_WORD;
209                 } else {
210                     sState = State.START;
211                 }
212                 break;
213             case UNDO_COMMIT:
214                 if (isSpace || isSeparator) {
215                     sState = State.ACCEPTED_DEFAULT;
216                 } else {
217                     sState = State.IN_WORD;
218                 }
219                 break;
220             case CORRECTING:
221                 sState = State.START;
222                 break;
223         }
224         displayState();
225     }
226 
backspace()227     public static void backspace() {
228         if (sState == State.ACCEPTED_DEFAULT) {
229             sState = State.UNDO_COMMIT;
230             sAutoSuggestUndoneCount++;
231             LatinImeLogger.logOnAutoSuggestionCanceled();
232         } else if (sState == State.UNDO_COMMIT) {
233             sState = State.IN_WORD;
234         }
235         sBackspaceCount++;
236         displayState();
237     }
238 
reset()239     public static void reset() {
240         sState = State.START;
241         displayState();
242     }
243 
getState()244     public static State getState() {
245         if (DBG) {
246             Log.d(TAG, "Returning state = " + sState);
247         }
248         return sState;
249     }
250 
isCorrecting()251     public static boolean isCorrecting() {
252         return sState == State.CORRECTING || sState == State.PICKED_CORRECTION;
253     }
254 
keyPressedAt(Key key, int x, int y)255     public static void keyPressedAt(Key key, int x, int y) {
256         if (LOGGING && sKeyLocationFile != null && key.codes[0] >= 32) {
257             String out =
258                     "KEY: " + (char) key.codes[0]
259                     + " X: " + x
260                     + " Y: " + y
261                     + " MX: " + (key.x + key.width / 2)
262                     + " MY: " + (key.y + key.height / 2)
263                     + "\n";
264             try {
265                 sKeyLocationFile.write(out.getBytes());
266             } catch (IOException ioe) {
267                 // TODO: May run out of space
268             }
269         }
270     }
271 
displayState()272     private static void displayState() {
273         if (DBG) {
274             Log.d(TAG, "State = " + sState);
275         }
276     }
277 }
278 
279