2009-03-13 22:11:42 +00:00
|
|
|
/*
|
2010-03-26 22:07:10 +00:00
|
|
|
* Copyright (C) 2008 The Android Open Source Project
|
2009-03-13 22:11:42 +00:00
|
|
|
*
|
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
|
|
|
* use this file except in compliance with the License. You may obtain a copy of
|
|
|
|
* the License at
|
|
|
|
*
|
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
*
|
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
|
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
|
|
* License for the specific language governing permissions and limitations under
|
|
|
|
* the License.
|
|
|
|
*/
|
|
|
|
|
|
|
|
package com.android.inputmethod.latin;
|
|
|
|
|
2010-12-02 09:46:21 +00:00
|
|
|
import com.android.inputmethod.keyboard.Key;
|
2010-10-01 10:40:44 +00:00
|
|
|
|
2009-03-13 22:11:42 +00:00
|
|
|
import android.content.Context;
|
|
|
|
import android.text.format.DateFormat;
|
|
|
|
import android.util.Log;
|
|
|
|
|
|
|
|
import java.io.FileOutputStream;
|
|
|
|
import java.io.IOException;
|
|
|
|
import java.util.Calendar;
|
|
|
|
|
|
|
|
public class TextEntryState {
|
|
|
|
|
2010-08-13 20:29:49 +00:00
|
|
|
private static final boolean DBG = false;
|
|
|
|
|
|
|
|
private static final String TAG = "TextEntryState";
|
|
|
|
|
2009-03-13 22:11:42 +00:00
|
|
|
private static boolean LOGGING = false;
|
2010-08-13 20:29:49 +00:00
|
|
|
|
2009-03-13 22:11:42 +00:00
|
|
|
private static int sBackspaceCount = 0;
|
|
|
|
|
|
|
|
private static int sAutoSuggestCount = 0;
|
|
|
|
|
|
|
|
private static int sAutoSuggestUndoneCount = 0;
|
|
|
|
|
|
|
|
private static int sManualSuggestCount = 0;
|
|
|
|
|
|
|
|
private static int sWordNotInDictionaryCount = 0;
|
|
|
|
|
|
|
|
private static int sSessionCount = 0;
|
|
|
|
|
|
|
|
private static int sTypedChars;
|
2010-07-23 09:56:42 +00:00
|
|
|
|
2009-03-13 22:11:42 +00:00
|
|
|
private static int sActualChars;
|
2010-07-23 09:56:42 +00:00
|
|
|
|
2010-08-13 20:29:49 +00:00
|
|
|
public enum State {
|
|
|
|
UNKNOWN,
|
|
|
|
START,
|
|
|
|
IN_WORD,
|
|
|
|
ACCEPTED_DEFAULT,
|
|
|
|
PICKED_SUGGESTION,
|
|
|
|
PUNCTUATION_AFTER_WORD,
|
|
|
|
PUNCTUATION_AFTER_ACCEPTED,
|
|
|
|
SPACE_AFTER_ACCEPTED,
|
|
|
|
SPACE_AFTER_PICKED,
|
|
|
|
UNDO_COMMIT,
|
|
|
|
CORRECTING,
|
2010-11-11 04:37:18 +00:00
|
|
|
PICKED_CORRECTION,
|
2010-08-13 20:29:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
private static State sState = State.UNKNOWN;
|
2010-02-27 15:53:56 +00:00
|
|
|
|
2009-03-13 22:11:42 +00:00
|
|
|
private static FileOutputStream sKeyLocationFile;
|
|
|
|
private static FileOutputStream sUserActionFile;
|
|
|
|
|
|
|
|
public static void newSession(Context context) {
|
|
|
|
sSessionCount++;
|
|
|
|
sAutoSuggestCount = 0;
|
|
|
|
sBackspaceCount = 0;
|
|
|
|
sAutoSuggestUndoneCount = 0;
|
|
|
|
sManualSuggestCount = 0;
|
|
|
|
sWordNotInDictionaryCount = 0;
|
|
|
|
sTypedChars = 0;
|
|
|
|
sActualChars = 0;
|
2010-08-13 20:29:49 +00:00
|
|
|
sState = State.START;
|
2009-03-13 22:11:42 +00:00
|
|
|
|
|
|
|
if (LOGGING) {
|
|
|
|
try {
|
|
|
|
sKeyLocationFile = context.openFileOutput("key.txt", Context.MODE_APPEND);
|
|
|
|
sUserActionFile = context.openFileOutput("action.txt", Context.MODE_APPEND);
|
|
|
|
} catch (IOException ioe) {
|
|
|
|
Log.e("TextEntryState", "Couldn't open file for output: " + ioe);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public static void endSession() {
|
|
|
|
if (sKeyLocationFile == null) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
try {
|
|
|
|
sKeyLocationFile.close();
|
2010-11-11 04:37:18 +00:00
|
|
|
// Write to log file
|
2009-03-13 22:11:42 +00:00
|
|
|
// Write timestamp, settings,
|
|
|
|
String out = DateFormat.format("MM:dd hh:mm:ss", Calendar.getInstance().getTime())
|
|
|
|
.toString()
|
|
|
|
+ " BS: " + sBackspaceCount
|
|
|
|
+ " auto: " + sAutoSuggestCount
|
|
|
|
+ " manual: " + sManualSuggestCount
|
|
|
|
+ " typed: " + sWordNotInDictionaryCount
|
|
|
|
+ " undone: " + sAutoSuggestUndoneCount
|
|
|
|
+ " saved: " + ((float) (sActualChars - sTypedChars) / sActualChars)
|
|
|
|
+ "\n";
|
|
|
|
sUserActionFile.write(out.getBytes());
|
|
|
|
sUserActionFile.close();
|
|
|
|
sKeyLocationFile = null;
|
|
|
|
sUserActionFile = null;
|
|
|
|
} catch (IOException ioe) {
|
2010-12-10 06:24:28 +00:00
|
|
|
// ignore
|
2009-03-13 22:11:42 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public static void acceptedDefault(CharSequence typedWord, CharSequence actualWord) {
|
2010-01-30 04:09:49 +00:00
|
|
|
if (typedWord == null) return;
|
2009-03-13 22:11:42 +00:00
|
|
|
if (!typedWord.equals(actualWord)) {
|
|
|
|
sAutoSuggestCount++;
|
|
|
|
}
|
|
|
|
sTypedChars += typedWord.length();
|
|
|
|
sActualChars += actualWord.length();
|
2010-08-13 20:29:49 +00:00
|
|
|
sState = State.ACCEPTED_DEFAULT;
|
2010-05-07 17:03:29 +00:00
|
|
|
LatinImeLogger.logOnAutoSuggestion(typedWord.toString(), actualWord.toString());
|
2010-08-13 20:29:49 +00:00
|
|
|
displayState();
|
2009-03-13 22:11:42 +00:00
|
|
|
}
|
2010-05-31 08:47:33 +00:00
|
|
|
|
2010-08-13 20:29:49 +00:00
|
|
|
// State.ACCEPTED_DEFAULT will be changed to other sub-states
|
|
|
|
// (see "case ACCEPTED_DEFAULT" in typedCharacter() below),
|
|
|
|
// and should be restored back to State.ACCEPTED_DEFAULT after processing for each sub-state.
|
2010-07-01 21:36:02 +00:00
|
|
|
public static void backToAcceptedDefault(CharSequence typedWord) {
|
|
|
|
if (typedWord == null) return;
|
2010-05-31 08:47:33 +00:00
|
|
|
switch (sState) {
|
2010-12-10 06:24:28 +00:00
|
|
|
case SPACE_AFTER_ACCEPTED:
|
|
|
|
case PUNCTUATION_AFTER_ACCEPTED:
|
|
|
|
case IN_WORD:
|
|
|
|
sState = State.ACCEPTED_DEFAULT;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
2010-05-31 08:47:33 +00:00
|
|
|
}
|
2010-08-13 20:29:49 +00:00
|
|
|
displayState();
|
2010-05-31 08:47:33 +00:00
|
|
|
}
|
|
|
|
|
2010-12-10 06:24:28 +00:00
|
|
|
public static void acceptedTyped(@SuppressWarnings("unused") CharSequence typedWord) {
|
2009-03-13 22:11:42 +00:00
|
|
|
sWordNotInDictionaryCount++;
|
2010-08-13 20:29:49 +00:00
|
|
|
sState = State.PICKED_SUGGESTION;
|
|
|
|
displayState();
|
2009-03-13 22:11:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public static void acceptedSuggestion(CharSequence typedWord, CharSequence actualWord) {
|
|
|
|
sManualSuggestCount++;
|
2010-08-13 20:29:49 +00:00
|
|
|
State oldState = sState;
|
2009-03-13 22:11:42 +00:00
|
|
|
if (typedWord.equals(actualWord)) {
|
|
|
|
acceptedTyped(typedWord);
|
|
|
|
}
|
2010-08-13 20:29:49 +00:00
|
|
|
if (oldState == State.CORRECTING || oldState == State.PICKED_CORRECTION) {
|
|
|
|
sState = State.PICKED_CORRECTION;
|
|
|
|
} else {
|
|
|
|
sState = State.PICKED_SUGGESTION;
|
|
|
|
}
|
|
|
|
displayState();
|
2009-03-13 22:11:42 +00:00
|
|
|
}
|
2010-02-27 15:53:56 +00:00
|
|
|
|
|
|
|
public static void selectedForCorrection() {
|
2010-08-13 20:29:49 +00:00
|
|
|
sState = State.CORRECTING;
|
|
|
|
displayState();
|
2010-02-27 15:53:56 +00:00
|
|
|
}
|
|
|
|
|
2010-11-11 04:37:18 +00:00
|
|
|
public static void onAbortCorrection() {
|
|
|
|
if (isCorrecting()) {
|
|
|
|
sState = State.START;
|
|
|
|
}
|
|
|
|
displayState();
|
|
|
|
}
|
|
|
|
|
2009-03-13 22:11:42 +00:00
|
|
|
public static void typedCharacter(char c, boolean isSeparator) {
|
|
|
|
boolean isSpace = c == ' ';
|
|
|
|
switch (sState) {
|
2010-08-13 20:29:49 +00:00
|
|
|
case IN_WORD:
|
2009-03-13 22:11:42 +00:00
|
|
|
if (isSpace || isSeparator) {
|
2010-08-13 20:29:49 +00:00
|
|
|
sState = State.START;
|
2009-03-13 22:11:42 +00:00
|
|
|
} else {
|
|
|
|
// State hasn't changed.
|
|
|
|
}
|
|
|
|
break;
|
2010-08-13 20:29:49 +00:00
|
|
|
case ACCEPTED_DEFAULT:
|
|
|
|
case SPACE_AFTER_PICKED:
|
2009-03-13 22:11:42 +00:00
|
|
|
if (isSpace) {
|
2010-08-13 20:29:49 +00:00
|
|
|
sState = State.SPACE_AFTER_ACCEPTED;
|
2009-03-13 22:11:42 +00:00
|
|
|
} else if (isSeparator) {
|
2010-08-13 20:29:49 +00:00
|
|
|
sState = State.PUNCTUATION_AFTER_ACCEPTED;
|
2009-03-13 22:11:42 +00:00
|
|
|
} else {
|
2010-08-13 20:29:49 +00:00
|
|
|
sState = State.IN_WORD;
|
2009-03-13 22:11:42 +00:00
|
|
|
}
|
|
|
|
break;
|
2010-08-13 20:29:49 +00:00
|
|
|
case PICKED_SUGGESTION:
|
|
|
|
case PICKED_CORRECTION:
|
2009-03-13 22:11:42 +00:00
|
|
|
if (isSpace) {
|
2010-08-13 20:29:49 +00:00
|
|
|
sState = State.SPACE_AFTER_PICKED;
|
2009-03-13 22:11:42 +00:00
|
|
|
} else if (isSeparator) {
|
|
|
|
// Swap
|
2010-08-13 20:29:49 +00:00
|
|
|
sState = State.PUNCTUATION_AFTER_ACCEPTED;
|
2009-03-13 22:11:42 +00:00
|
|
|
} else {
|
2010-08-13 20:29:49 +00:00
|
|
|
sState = State.IN_WORD;
|
2009-03-13 22:11:42 +00:00
|
|
|
}
|
|
|
|
break;
|
2010-08-13 20:29:49 +00:00
|
|
|
case START:
|
|
|
|
case UNKNOWN:
|
|
|
|
case SPACE_AFTER_ACCEPTED:
|
|
|
|
case PUNCTUATION_AFTER_ACCEPTED:
|
|
|
|
case PUNCTUATION_AFTER_WORD:
|
2009-03-13 22:11:42 +00:00
|
|
|
if (!isSpace && !isSeparator) {
|
2010-08-13 20:29:49 +00:00
|
|
|
sState = State.IN_WORD;
|
2009-03-13 22:11:42 +00:00
|
|
|
} else {
|
2010-08-13 20:29:49 +00:00
|
|
|
sState = State.START;
|
2009-03-13 22:11:42 +00:00
|
|
|
}
|
|
|
|
break;
|
2010-08-13 20:29:49 +00:00
|
|
|
case UNDO_COMMIT:
|
2009-03-13 22:11:42 +00:00
|
|
|
if (isSpace || isSeparator) {
|
2010-08-13 20:29:49 +00:00
|
|
|
sState = State.ACCEPTED_DEFAULT;
|
2009-03-13 22:11:42 +00:00
|
|
|
} else {
|
2010-08-13 20:29:49 +00:00
|
|
|
sState = State.IN_WORD;
|
2009-03-13 22:11:42 +00:00
|
|
|
}
|
2010-02-27 15:53:56 +00:00
|
|
|
break;
|
2010-08-13 20:29:49 +00:00
|
|
|
case CORRECTING:
|
|
|
|
sState = State.START;
|
2010-02-27 15:53:56 +00:00
|
|
|
break;
|
2009-03-13 22:11:42 +00:00
|
|
|
}
|
2010-08-13 20:29:49 +00:00
|
|
|
displayState();
|
2009-03-13 22:11:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public static void backspace() {
|
2010-08-13 20:29:49 +00:00
|
|
|
if (sState == State.ACCEPTED_DEFAULT) {
|
|
|
|
sState = State.UNDO_COMMIT;
|
2009-03-13 22:11:42 +00:00
|
|
|
sAutoSuggestUndoneCount++;
|
2010-05-07 17:03:29 +00:00
|
|
|
LatinImeLogger.logOnAutoSuggestionCanceled();
|
2010-08-13 20:29:49 +00:00
|
|
|
} else if (sState == State.UNDO_COMMIT) {
|
|
|
|
sState = State.IN_WORD;
|
2009-03-13 22:11:42 +00:00
|
|
|
}
|
|
|
|
sBackspaceCount++;
|
2010-08-13 20:29:49 +00:00
|
|
|
displayState();
|
2009-03-13 22:11:42 +00:00
|
|
|
}
|
2010-08-13 20:29:49 +00:00
|
|
|
|
2009-03-13 22:11:42 +00:00
|
|
|
public static void reset() {
|
2010-08-13 20:29:49 +00:00
|
|
|
sState = State.START;
|
|
|
|
displayState();
|
2009-03-13 22:11:42 +00:00
|
|
|
}
|
2010-08-13 20:29:49 +00:00
|
|
|
|
|
|
|
public static State getState() {
|
|
|
|
if (DBG) {
|
|
|
|
Log.d(TAG, "Returning state = " + sState);
|
|
|
|
}
|
2009-03-13 22:11:42 +00:00
|
|
|
return sState;
|
|
|
|
}
|
2010-02-27 15:53:56 +00:00
|
|
|
|
|
|
|
public static boolean isCorrecting() {
|
2010-08-13 20:29:49 +00:00
|
|
|
return sState == State.CORRECTING || sState == State.PICKED_CORRECTION;
|
2010-02-27 15:53:56 +00:00
|
|
|
}
|
|
|
|
|
2009-03-13 22:11:42 +00:00
|
|
|
public static void keyPressedAt(Key key, int x, int y) {
|
2010-12-02 11:54:32 +00:00
|
|
|
if (LOGGING && sKeyLocationFile != null && key.mCodes[0] >= 32) {
|
|
|
|
String out =
|
|
|
|
"KEY: " + (char) key.mCodes[0]
|
|
|
|
+ " X: " + x
|
2009-03-13 22:11:42 +00:00
|
|
|
+ " Y: " + y
|
2010-12-02 11:54:32 +00:00
|
|
|
+ " MX: " + (key.mX + key.mWidth / 2)
|
|
|
|
+ " MY: " + (key.mY + key.mHeight / 2)
|
2009-03-13 22:11:42 +00:00
|
|
|
+ "\n";
|
|
|
|
try {
|
|
|
|
sKeyLocationFile.write(out.getBytes());
|
|
|
|
} catch (IOException ioe) {
|
|
|
|
// TODO: May run out of space
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2010-08-13 20:29:49 +00:00
|
|
|
|
|
|
|
private static void displayState() {
|
|
|
|
if (DBG) {
|
|
|
|
Log.d(TAG, "State = " + sState);
|
|
|
|
}
|
|
|
|
}
|
2009-03-13 22:11:42 +00:00
|
|
|
}
|
|
|
|
|