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 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 
     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 
     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 
    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.
    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 
    146     public static void acceptedTyped(CharSequence typedWord) {
    147         sWordNotInDictionaryCount++;
    148         sState = State.PICKED_SUGGESTION;
    149         displayState();
    150     }
    151 
    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 
    166     public static void selectedForCorrection() {
    167         sState = State.CORRECTING;
    168         displayState();
    169     }
    170 
    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 
    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 
    239     public static void reset() {
    240         sState = State.START;
    241         displayState();
    242     }
    243 
    244     public static State getState() {
    245         if (DBG) {
    246             Log.d(TAG, "Returning state = " + sState);
    247         }
    248         return sState;
    249     }
    250 
    251     public static boolean isCorrecting() {
    252         return sState == State.CORRECTING || sState == State.PICKED_CORRECTION;
    253     }
    254 
    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 
    272     private static void displayState() {
    273         if (DBG) {
    274             Log.d(TAG, "State = " + sState);
    275         }
    276     }
    277 }
    278 
    279