From 9bc29d78a6ce83f77869aa63748176241e29d43c Mon Sep 17 00:00:00 2001 From: Kurt Partridge Date: Fri, 30 Mar 2012 13:15:46 -0700 Subject: [PATCH] add more data collection points to ResearchLogger (attempt #2) the new points are all at Log.x() positions; only those appearing directly related to user input were added. multi-project change with I159f5de2 this CL is the same as I618bcd07, which was reverted because of incompatibilities with vendor branches. Bug: 6188932 Change-Id: I999249dceb0c04f5a4ffbfff25caed09d24a2c52 --- .../keyboard/LatinKeyboardView.java | 25 +- .../inputmethod/keyboard/PointerTracker.java | 23 + .../SuddenJumpingTouchEventHandler.java | 5 + .../keyboard/internal/AlphabetShiftState.java | 12 + .../keyboard/internal/KeyboardState.java | 45 ++ .../inputmethod/latin/AutoCorrection.java | 11 + .../android/inputmethod/latin/LatinIME.java | 27 +- .../inputmethod/latin/ResearchLogger.java | 439 ++++++++++++++++-- 8 files changed, 512 insertions(+), 75 deletions(-) diff --git a/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java b/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java index 2689e6e13..98da1eb65 100644 --- a/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java +++ b/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java @@ -555,6 +555,9 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke * method on the base class if the subclass doesn't wish to handle the call. */ protected boolean onLongPress(Key parentKey, PointerTracker tracker) { + if (ProductionFlag.IS_EXPERIMENTAL) { + ResearchLogger.latinKeyboardView_onLongPress(); + } final int primaryCode = parentKey.mCode; if (parentKey.hasEmbeddedMoreKey()) { final int embeddedCode = KeySpecParser.getCode(getResources(), parentKey.mMoreKeys[0]); @@ -695,17 +698,8 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke } } if (ProductionFlag.IS_EXPERIMENTAL) { - if (ResearchLogger.sIsLogging) { - // TODO: remove redundant calculations of size and pressure by - // removing UsabilityStudyLog code once the ResearchLogger is mature enough - final float size = me.getSize(index); - final float pressure = me.getPressure(index); - if (action != MotionEvent.ACTION_MOVE) { - // Skip ACTION_MOVE events as they are logged below - ResearchLogger.getInstance().logMotionEvent(action, eventTime, id, x, y, - size, pressure); - } - } + ResearchLogger.latinKeyboardView_processMotionEvent(me, action, eventTime, index, id, + x, y); } if (mKeyTimerHandler.isInKeyRepeat()) { @@ -773,13 +767,8 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke + pointerSize + "," + pointerPressure); } if (ProductionFlag.IS_EXPERIMENTAL) { - if (ResearchLogger.sIsLogging) { - // TODO: earlier comment about redundant calculations applies here too - final float pointerSize = me.getSize(i); - final float pointerPressure = me.getPressure(i); - ResearchLogger.getInstance().logMotionEvent(action, eventTime, pointerId, - px, py, pointerSize, pointerPressure); - } + ResearchLogger.latinKeyboardView_processMotionEvent(me, action, eventTime, + i, pointerId, px, py); } } } else { diff --git a/java/src/com/android/inputmethod/keyboard/PointerTracker.java b/java/src/com/android/inputmethod/keyboard/PointerTracker.java index ec9081681..24ab54730 100644 --- a/java/src/com/android/inputmethod/keyboard/PointerTracker.java +++ b/java/src/com/android/inputmethod/keyboard/PointerTracker.java @@ -23,6 +23,8 @@ import android.widget.TextView; import com.android.inputmethod.keyboard.internal.PointerTrackerQueue; import com.android.inputmethod.latin.LatinImeLogger; +import com.android.inputmethod.latin.ResearchLogger; +import com.android.inputmethod.latin.define.ProductionFlag; import java.util.ArrayList; @@ -235,6 +237,10 @@ public class PointerTracker { + " ignoreModifier=" + ignoreModifierKey + " enabled=" + key.isEnabled()); } + if (ProductionFlag.IS_EXPERIMENTAL) { + ResearchLogger.pointerTracker_callListenerOnPressAndCheckKeyboardLayoutChange(key, + ignoreModifierKey); + } if (ignoreModifierKey) { return false; } @@ -259,6 +265,10 @@ public class PointerTracker { + " ignoreModifier=" + ignoreModifierKey + " altersCode=" + altersCode + " enabled=" + key.isEnabled()); } + if (ProductionFlag.IS_EXPERIMENTAL) { + ResearchLogger.pointerTracker_callListenerOnCodeInput(key, x, y, ignoreModifierKey, + altersCode, code); + } if (ignoreModifierKey) { return; } @@ -284,6 +294,10 @@ public class PointerTracker { + " sliding=" + withSliding + " ignoreModifier=" + ignoreModifierKey + " enabled="+ key.isEnabled()); } + if (ProductionFlag.IS_EXPERIMENTAL) { + ResearchLogger.pointerTracker_callListenerOnRelease(key, primaryCode, withSliding, + ignoreModifierKey); + } if (ignoreModifierKey) { return; } @@ -295,6 +309,9 @@ public class PointerTracker { private void callListenerOnCancelInput() { if (DEBUG_LISTENER) Log.d(TAG, "onCancelInput"); + if (ProductionFlag.IS_EXPERIMENTAL) { + ResearchLogger.pointerTracker_callListenerOnCancelInput(); + } mListener.onCancelInput(); } @@ -479,6 +496,9 @@ public class PointerTracker { if (DEBUG_MODE) Log.w(TAG, "onDownEvent: ignore potential noise: time=" + deltaT + " distance=" + distanceSquared); + if (ProductionFlag.IS_EXPERIMENTAL) { + ResearchLogger.pointerTracker_onDownEvent(deltaT, distanceSquared); + } mKeyAlreadyProcessed = true; return; } @@ -583,6 +603,9 @@ public class PointerTracker { if (DEBUG_MODE) Log.w(TAG, String.format("onMoveEvent: sudden move is translated to " + "up[%d,%d]/down[%d,%d] events", lastX, lastY, x, y)); + if (ProductionFlag.IS_EXPERIMENTAL) { + ResearchLogger.pointerTracker_onMoveEvent(x, y, lastX, lastY); + } onUpEventInternal(lastX, lastY, eventTime); onDownEventInternal(x, y, eventTime); } else { diff --git a/java/src/com/android/inputmethod/keyboard/SuddenJumpingTouchEventHandler.java b/java/src/com/android/inputmethod/keyboard/SuddenJumpingTouchEventHandler.java index 347383f95..107138395 100644 --- a/java/src/com/android/inputmethod/keyboard/SuddenJumpingTouchEventHandler.java +++ b/java/src/com/android/inputmethod/keyboard/SuddenJumpingTouchEventHandler.java @@ -22,7 +22,9 @@ import android.view.MotionEvent; import com.android.inputmethod.latin.LatinImeLogger; import com.android.inputmethod.latin.R; +import com.android.inputmethod.latin.ResearchLogger; import com.android.inputmethod.latin.Utils; +import com.android.inputmethod.latin.define.ProductionFlag; public class SuddenJumpingTouchEventHandler { private static final String TAG = SuddenJumpingTouchEventHandler.class.getSimpleName(); @@ -141,6 +143,9 @@ public class SuddenJumpingTouchEventHandler { if (handleSuddenJumping(me)) { if (DEBUG_MODE) Log.w(TAG, "onTouchEvent: ignore sudden jump " + me); + if (ProductionFlag.IS_EXPERIMENTAL) { + ResearchLogger.suddenJumpingTouchEventHandler_onTouchEvent(me); + } return true; } return mView.processMotionEvent(me); diff --git a/java/src/com/android/inputmethod/keyboard/internal/AlphabetShiftState.java b/java/src/com/android/inputmethod/keyboard/internal/AlphabetShiftState.java index 5712df1fc..392afca97 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/AlphabetShiftState.java +++ b/java/src/com/android/inputmethod/keyboard/internal/AlphabetShiftState.java @@ -18,6 +18,9 @@ package com.android.inputmethod.keyboard.internal; import android.util.Log; +import com.android.inputmethod.latin.ResearchLogger; +import com.android.inputmethod.latin.define.ProductionFlag; + public class AlphabetShiftState { private static final String TAG = AlphabetShiftState.class.getSimpleName(); private static final boolean DEBUG = false; @@ -59,6 +62,9 @@ public class AlphabetShiftState { } if (DEBUG) Log.d(TAG, "setShifted(" + newShiftState + "): " + toString(oldState) + " > " + this); + if (ProductionFlag.IS_EXPERIMENTAL) { + ResearchLogger.alphabetShiftState_setShifted(newShiftState, oldState, this); + } } public void setShiftLocked(boolean newShiftLockState) { @@ -78,6 +84,9 @@ public class AlphabetShiftState { if (DEBUG) Log.d(TAG, "setShiftLocked(" + newShiftLockState + "): " + toString(oldState) + " > " + this); + if (ProductionFlag.IS_EXPERIMENTAL) { + ResearchLogger.alphabetShiftState_setShiftLocked(newShiftLockState, oldState, this); + } } public void setAutomaticShifted() { @@ -85,6 +94,9 @@ public class AlphabetShiftState { mState = AUTOMATIC_SHIFTED; if (DEBUG) Log.d(TAG, "setAutomaticShifted: " + toString(oldState) + " > " + this); + if (ProductionFlag.IS_EXPERIMENTAL) { + ResearchLogger.alphabetShiftState_setAutomaticShifted(oldState, this); + } } public boolean isShiftedOrShiftLocked() { diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java index 18a3f9794..6949c9d12 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java +++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java @@ -20,6 +20,8 @@ import android.text.TextUtils; import android.util.Log; import com.android.inputmethod.keyboard.Keyboard; +import com.android.inputmethod.latin.ResearchLogger; +import com.android.inputmethod.latin.define.ProductionFlag; /** * Keyboard state machine. @@ -139,6 +141,9 @@ public class KeyboardState { if (DEBUG_EVENT) { Log.d(TAG, "onSaveKeyboardState: saved=" + state + " " + this); } + if (ProductionFlag.IS_EXPERIMENTAL) { + ResearchLogger.keyboardState_onSaveKeyboardState(this, state.toString()); + } } private void onRestoreKeyboardState() { @@ -146,6 +151,9 @@ public class KeyboardState { if (DEBUG_EVENT) { Log.d(TAG, "onRestoreKeyboardState: saved=" + state + " " + this); } + if (ProductionFlag.IS_EXPERIMENTAL) { + ResearchLogger.keyboardState_onRestoreKeyboardState(this, state.toString()); + } if (!state.mIsValid || state.mIsAlphabetMode) { setAlphabetKeyboard(); } else { @@ -178,6 +186,9 @@ public class KeyboardState { if (DEBUG_ACTION) { Log.d(TAG, "setShifted: shiftMode=" + shiftModeToString(shiftMode) + " " + this); } + if (ProductionFlag.IS_EXPERIMENTAL) { + ResearchLogger.keyboardState_setShifted(this, shiftModeToString(shiftMode)); + } if (!mIsAlphabetMode) return; final int prevShiftMode; if (mAlphabetShiftState.isAutomaticShifted()) { @@ -217,6 +228,9 @@ public class KeyboardState { if (DEBUG_ACTION) { Log.d(TAG, "setShiftLocked: shiftLocked=" + shiftLocked + " " + this); } + if (ProductionFlag.IS_EXPERIMENTAL) { + ResearchLogger.keyboardState_setShiftLocked(this, shiftLocked); + } if (!mIsAlphabetMode) return; if (shiftLocked && (!mAlphabetShiftState.isShiftLocked() || mAlphabetShiftState.isShiftLockShifted())) { @@ -232,6 +246,9 @@ public class KeyboardState { if (DEBUG_ACTION) { Log.d(TAG, "toggleAlphabetAndSymbols: " + this); } + if (ProductionFlag.IS_EXPERIMENTAL) { + ResearchLogger.keyboardState_toggleAlphabetAndSymbols(this); + } if (mIsAlphabetMode) { mPrevMainKeyboardWasShiftLocked = mAlphabetShiftState.isShiftLocked(); if (mPrevSymbolsKeyboardWasShifted) { @@ -262,6 +279,10 @@ public class KeyboardState { if (DEBUG_ACTION) { Log.d(TAG, "setAlphabetKeyboard"); } + + if (ProductionFlag.IS_EXPERIMENTAL) { + ResearchLogger.keyboardState_setAlphabetKeyboard(); + } mSwitchActions.setAlphabetKeyboard(); mIsAlphabetMode = true; mIsSymbolShifted = false; @@ -273,6 +294,9 @@ public class KeyboardState { if (DEBUG_ACTION) { Log.d(TAG, "setSymbolsKeyboard"); } + if (ProductionFlag.IS_EXPERIMENTAL) { + ResearchLogger.keyboardState_setSymbolsKeyboard(); + } mSwitchActions.setSymbolsKeyboard(); mIsAlphabetMode = false; mIsSymbolShifted = false; @@ -285,6 +309,9 @@ public class KeyboardState { if (DEBUG_ACTION) { Log.d(TAG, "setSymbolsShiftedKeyboard"); } + if (ProductionFlag.IS_EXPERIMENTAL) { + ResearchLogger.keyboardState_setSymbolsShiftedKeyboard(); + } mSwitchActions.setSymbolsShiftedKeyboard(); mIsAlphabetMode = false; mIsSymbolShifted = true; @@ -297,6 +324,9 @@ public class KeyboardState { if (DEBUG_EVENT) { Log.d(TAG, "onPressKey: code=" + Keyboard.printableCode(code) + " " + this); } + if (ProductionFlag.IS_EXPERIMENTAL) { + ResearchLogger.keyboardState_onPressKey(code, this); + } if (code == Keyboard.CODE_SHIFT) { onPressShift(); } else if (code == Keyboard.CODE_SWITCH_ALPHA_SYMBOL) { @@ -314,6 +344,9 @@ public class KeyboardState { Log.d(TAG, "onReleaseKey: code=" + Keyboard.printableCode(code) + " sliding=" + withSliding + " " + this); } + if (ProductionFlag.IS_EXPERIMENTAL) { + ResearchLogger.keyboardState_onReleaseKey(this, code, withSliding); + } if (code == Keyboard.CODE_SHIFT) { onReleaseShift(withSliding); } else if (code == Keyboard.CODE_SWITCH_ALPHA_SYMBOL) { @@ -345,6 +378,9 @@ public class KeyboardState { if (DEBUG_EVENT) { Log.d(TAG, "onLongPressTimeout: code=" + Keyboard.printableCode(code) + " " + this); } + if (ProductionFlag.IS_EXPERIMENTAL) { + ResearchLogger.keyboardState_onLongPressTimeout(code, this); + } if (mIsAlphabetMode && code == Keyboard.CODE_SHIFT) { if (mAlphabetShiftState.isShiftLocked()) { setShiftLocked(false); @@ -363,6 +399,9 @@ public class KeyboardState { if (DEBUG_EVENT) { Log.d(TAG, "onUpdateShiftState: autoCaps=" + autoCaps + " " + this); } + if (ProductionFlag.IS_EXPERIMENTAL) { + ResearchLogger.keyboardState_onUpdateShiftState(this, autoCaps); + } updateAlphabetShiftState(autoCaps); } @@ -481,6 +520,9 @@ public class KeyboardState { if (DEBUG_EVENT) { Log.d(TAG, "onCancelInput: single=" + isSinglePointer + " " + this); } + if (ProductionFlag.IS_EXPERIMENTAL) { + ResearchLogger.keyboardState_onCancelInput(isSinglePointer, this); + } // Switch back to the previous keyboard mode if the user cancels sliding input. if (isSinglePointer) { if (mSwitchState == SWITCH_STATE_MOMENTARY_ALPHA_AND_SYMBOL) { @@ -512,6 +554,9 @@ public class KeyboardState { + " single=" + isSinglePointer + " autoCaps=" + autoCaps + " " + this); } + if (ProductionFlag.IS_EXPERIMENTAL) { + ResearchLogger.keyboardState_onCodeInput(code, isSinglePointer, autoCaps, this); + } switch (mSwitchState) { case SWITCH_STATE_MOMENTARY_ALPHA_AND_SYMBOL: diff --git a/java/src/com/android/inputmethod/latin/AutoCorrection.java b/java/src/com/android/inputmethod/latin/AutoCorrection.java index 38444a10c..520177afe 100644 --- a/java/src/com/android/inputmethod/latin/AutoCorrection.java +++ b/java/src/com/android/inputmethod/latin/AutoCorrection.java @@ -21,6 +21,8 @@ import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; import android.text.TextUtils; import android.util.Log; +import com.android.inputmethod.latin.define.ProductionFlag; + import java.util.ArrayList; import java.util.HashMap; @@ -115,10 +117,19 @@ public class AutoCorrection { + autoCorrectionSuggestionScore + ", " + normalizedScore + "(" + autoCorrectionThreshold + ")"); } + if (ProductionFlag.IS_EXPERIMENTAL) { + ResearchLogger.autoCorrection_hasAutoCorrectionForBinaryDictionary(consideredWord, + autoCorrectionThreshold, autoCorrectionSuggestion.toString(), + autoCorrectionSuggestionScore, normalizedScore); + } if (normalizedScore >= autoCorrectionThreshold) { if (DBG) { Log.d(TAG, "Auto corrected by S-threshold."); } + if (ProductionFlag.IS_EXPERIMENTAL) { + ResearchLogger + .autoCorrection_hasAutoCorrectionForBinaryDictionary_bySthreshold(); + } return true; } } diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index f5c09974e..e0fa2f838 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -665,6 +665,9 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen + String.format("inputType=0x%08x imeOptions=0x%08x", editorInfo.inputType, editorInfo.imeOptions)); } + if (ProductionFlag.IS_EXPERIMENTAL) { + ResearchLogger.latinIME_onStartInputViewInternal(editorInfo); + } if (StringUtils.inPrivateImeOptions(null, IME_OPTION_NO_MICROPHONE_COMPAT, editorInfo)) { Log.w(TAG, "Deprecated private IME option specified: " + editorInfo.privateImeOptions); @@ -762,19 +765,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen super.onUpdateSelection(oldSelStart, oldSelEnd, newSelStart, newSelEnd, composingSpanStart, composingSpanEnd); - if (ProductionFlag.IS_EXPERIMENTAL) { - if (ResearchLogger.UnsLogGroup.ON_UPDATE_SELECTION.isEnabled) { - final String s = "onUpdateSelection: oss=" + oldSelStart - + ", ose=" + oldSelEnd - + ", lss=" + mLastSelectionStart - + ", lse=" + mLastSelectionEnd - + ", nss=" + newSelStart - + ", nse=" + newSelEnd - + ", cs=" + composingSpanStart - + ", ce=" + composingSpanEnd; - ResearchLogger.logUnstructured(ResearchLogger.UnsLogGroup.ON_UPDATE_SELECTION, s); - } - } if (DEBUG) { Log.i(TAG, "onUpdateSelection: oss=" + oldSelStart + ", ose=" + oldSelEnd @@ -785,6 +775,11 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen + ", cs=" + composingSpanStart + ", ce=" + composingSpanEnd); } + if (ProductionFlag.IS_EXPERIMENTAL) { + ResearchLogger.latinIME_onUpdateSelection(mLastSelectionStart, mLastSelectionEnd, + oldSelStart, oldSelEnd, newSelStart, newSelEnd, composingSpanStart, + composingSpanEnd); + } // TODO: refactor the following code to be less contrived. // "newSelStart != composingSpanEnd" || "newSelEnd != composingSpanEnd" means @@ -886,6 +881,9 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen } } } + if (ProductionFlag.IS_EXPERIMENTAL) { + ResearchLogger.latinIME_onDisplayCompletions(applicationSpecifiedCompletions); + } if (mInputAttributes.mApplicationSpecifiedCompletionOn) { mApplicationSpecifiedCompletions = applicationSpecifiedCompletions; if (applicationSpecifiedCompletions == null) { @@ -1660,6 +1658,9 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen if (DEBUG) { Log.d(TAG, "Switch to keyboard view."); } + if (ProductionFlag.IS_EXPERIMENTAL) { + ResearchLogger.latinIME_switchToKeyboardView(); + } View v = mKeyboardSwitcher.getKeyboardView(); if (v != null) { // Confirms that the keyboard view doesn't have parent view. diff --git a/java/src/com/android/inputmethod/latin/ResearchLogger.java b/java/src/com/android/inputmethod/latin/ResearchLogger.java index c5fb61f78..182a7bc3e 100644 --- a/java/src/com/android/inputmethod/latin/ResearchLogger.java +++ b/java/src/com/android/inputmethod/latin/ResearchLogger.java @@ -25,15 +25,20 @@ import android.os.SystemClock; import android.text.TextUtils; import android.util.Log; import android.view.MotionEvent; +import android.view.inputmethod.CompletionInfo; +import android.view.inputmethod.EditorInfo; +import com.android.inputmethod.keyboard.Key; +import com.android.inputmethod.keyboard.KeyDetector; import com.android.inputmethod.keyboard.Keyboard; +import com.android.inputmethod.keyboard.internal.AlphabetShiftState; +import com.android.inputmethod.keyboard.internal.KeyboardState; +import com.android.inputmethod.latin.define.ProductionFlag; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.PrintWriter; -import java.text.SimpleDateFormat; -import java.util.Date; /** * Logs the use of the LatinIME keyboard. @@ -46,13 +51,12 @@ import java.util.Date; public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChangeListener { private static final String TAG = ResearchLogger.class.getSimpleName(); private static final String PREF_USABILITY_STUDY_MODE = "usability_study_mode"; + private static final boolean DEBUG = false; private static final ResearchLogger sInstance = new ResearchLogger(new LogFileManager()); public static boolean sIsLogging = false; /* package */ final Handler mLoggingHandler; private InputMethodService mIms; - private final Date mDate; - private final SimpleDateFormat mDateFormat; /** * Isolates management of files. This variable should never be null, but can be changed @@ -79,35 +83,36 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang /* package */ LogFileManager() { } - public void init(InputMethodService ims) { + public void init(final InputMethodService ims) { mIms = ims; } - public synchronized void createLogFile() { + public synchronized boolean createLogFile() { try { - createLogFile(DEFAULT_LOG_DIRECTORY, DEFAULT_FILENAME); - } catch (FileNotFoundException e) { + return createLogFile(DEFAULT_LOG_DIRECTORY, DEFAULT_FILENAME); + } catch (final FileNotFoundException e) { Log.w(TAG, e); + return false; } } - public synchronized void createLogFile(String dir, String filename) + public synchronized boolean createLogFile(final String dir, final String filename) throws FileNotFoundException { if (mIms == null) { Log.w(TAG, "InputMethodService is not configured. Logging is off."); - return; + return false; } - File filesDir = mIms.getFilesDir(); + final File filesDir = mIms.getFilesDir(); if (filesDir == null || !filesDir.exists()) { Log.w(TAG, "Storage directory does not exist. Logging is off."); - return; + return false; } - File directory = new File(filesDir, dir); + final File directory = new File(filesDir, dir); if (!directory.exists()) { - boolean wasCreated = directory.mkdirs(); + final boolean wasCreated = directory.mkdirs(); if (!wasCreated) { Log.w(TAG, "Log directory cannot be created. Logging is off."); - return; + return false; } } @@ -120,16 +125,23 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang append = false; } mPrintWriter = new PrintWriter(new FileOutputStream(mFile, append), true); + return true; } - public synchronized boolean append(String s) { + public synchronized boolean append(final String s) { if (mPrintWriter == null) { - Log.w(TAG, "PrintWriter is null"); - return false; - } else { - mPrintWriter.print(s); - return !mPrintWriter.checkError(); + if (DEBUG) { + Log.w(TAG, "PrintWriter is null... attempting to create default log file"); + } + if (!createLogFile()) { + if (DEBUG) { + Log.w(TAG, "Failed to create log file. Not logging."); + return false; + } + } } + mPrintWriter.print(s); + return !mPrintWriter.checkError(); } public synchronized void reset() { @@ -152,11 +164,8 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang } } - private ResearchLogger(LogFileManager logFileManager) { - mDate = new Date(); - mDateFormat = new SimpleDateFormat("yyyyMMdd-HHmmss.SSSZ"); - - HandlerThread handlerThread = new HandlerThread("ResearchLogger logging task", + private ResearchLogger(final LogFileManager logFileManager) { + final HandlerThread handlerThread = new HandlerThread("ResearchLogger logging task", Process.THREAD_PRIORITY_BACKGROUND); handlerThread.start(); mLoggingHandler = new Handler(handlerThread.getLooper()); @@ -167,11 +176,11 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang return sInstance; } - public static void init(InputMethodService ims, SharedPreferences prefs) { + public static void init(final InputMethodService ims, final SharedPreferences prefs) { sInstance.initInternal(ims, prefs); } - public void initInternal(InputMethodService ims, SharedPreferences prefs) { + public void initInternal(final InputMethodService ims, final SharedPreferences prefs) { mIms = ims; if (mLogFileManager != null) { mLogFileManager.init(ims); @@ -188,7 +197,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang * * @throws IllegalArgumentException if logFileManager is null */ - void setLogFileManager(LogFileManager manager) { + void setLogFileManager(final LogFileManager manager) { if (manager == null) { throw new IllegalArgumentException("warning: trying to set null logFileManager"); } else { @@ -203,11 +212,12 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang MOTION_EVENT("m"), KEY("k"), CORRECTION("c"), - STATE_CHANGE("s"); + STATE_CHANGE("s"), + UNSTRUCTURED("u"); private final String mLogString; - private LogGroup(String logString) { + private LogGroup(final String logString) { mLogString = logString; } } @@ -226,7 +236,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang default: eventTag = "[Action" + action + "]"; break; } if (!TextUtils.isEmpty(eventTag)) { - StringBuilder sb = new StringBuilder(); + final StringBuilder sb = new StringBuilder(); sb.append(eventTag); sb.append('\t'); sb.append(eventTime); sb.append('\t'); sb.append(id); @@ -238,7 +248,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang } } - public void logKeyEvent(int code, int x, int y) { + public void logKeyEvent(final int code, final int x, final int y) { final StringBuilder sb = new StringBuilder(); sb.append(Keyboard.printableCode(code)); sb.append('\t'); sb.append(x); @@ -246,7 +256,8 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang write(LogGroup.KEY, sb.toString()); } - public void logCorrection(String subgroup, String before, String after, int position) { + public void logCorrection(final String subgroup, final String before, final String after, + final int position) { final StringBuilder sb = new StringBuilder(); sb.append(subgroup); sb.append('\t'); sb.append(before); @@ -255,19 +266,62 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang write(LogGroup.CORRECTION, sb.toString()); } - public void logStateChange(String subgroup, String details) { + public void logStateChange(final String subgroup, final String details) { write(LogGroup.STATE_CHANGE, subgroup + "\t" + details); } - public static enum UnsLogGroup { - // TODO: expand to include one flag per log point - // TODO: support selective enabling of flags - ON_UPDATE_SELECTION; + public static class UnsLogGroup { + private static final boolean DEFAULT_ENABLED = true; - public boolean isEnabled = true; + private static final boolean ALPHABETSHIFTSTATE_SETSHIFTED_ENABLED = DEFAULT_ENABLED; + private static final boolean ALPHABETSHIFTSTATE_SETSHIFTLOCKED_ENABLED = DEFAULT_ENABLED; + private static final boolean ALPHABETSHIFTSTATE_SETAUTOMATICSHIFTED_ENABLED + = DEFAULT_ENABLED; + private static final boolean AUTOCORRECTION_HASAUTOCORRECTIONFORBINARYDICTIONARY_ENABLED + = DEFAULT_ENABLED; + private static final boolean + AUTOCORRECTION_HASAUTOCORRECTIONFORBINARYDICTIONARY_BYSTHRESHOLD_ENABLED + = DEFAULT_ENABLED; + private static final boolean KEYBOARDSTATE_ONCANCELINPUT_ENABLED = DEFAULT_ENABLED; + private static final boolean KEYBOARDSTATE_ONCODEINPUT_ENABLED = DEFAULT_ENABLED; + private static final boolean KEYBOARDSTATE_ONLONGPRESSTIMEOUT_ENABLED = DEFAULT_ENABLED; + private static final boolean KEYBOARDSTATE_ONPRESSKEY_ENABLED = DEFAULT_ENABLED; + private static final boolean KEYBOARDSTATE_ONRELEASEKEY_ENABLED = DEFAULT_ENABLED; + private static final boolean KEYBOARDSTATE_ONRESTOREKEYBOARDSTATE_ENABLED = DEFAULT_ENABLED; + private static final boolean KEYBOARDSTATE_ONSAVEKEYBOARDSTATE_ENABLED = DEFAULT_ENABLED; + private static final boolean KEYBOARDSTATE_ONUPDATESHIFTSTATE_ENABLED = DEFAULT_ENABLED; + private static final boolean KEYBOARDSTATE_SETALPHABETKEYBOARD_ENABLED = DEFAULT_ENABLED; + private static final boolean KEYBOARDSTATE_SETSHIFTED_ENABLED = DEFAULT_ENABLED; + private static final boolean KEYBOARDSTATE_SETSHIFTLOCKED_ENABLED = DEFAULT_ENABLED; + private static final boolean KEYBOARDSTATE_SETSYMBOLSKEYBOARD_ENABLED = DEFAULT_ENABLED; + private static final boolean KEYBOARDSTATE_SETSYMBOLSSHIFTEDKEYBOARD_ENABLED + = DEFAULT_ENABLED; + private static final boolean KEYBOARDSTATE_TOGGLEALPHABETANDSYMBOLS_ENABLED + = DEFAULT_ENABLED; + private static final boolean LATINIME_ONDISPLAYCOMPLETIONS_ENABLED = DEFAULT_ENABLED; + private static final boolean LATINIME_ONSTARTINPUTVIEWINTERNAL_ENABLED = DEFAULT_ENABLED; + private static final boolean LATINIME_ONUPDATESELECTION_ENABLED = DEFAULT_ENABLED; + private static final boolean LATINIME_SWITCHTOKEYBOARDVIEW_ENABLED = DEFAULT_ENABLED; + private static final boolean LATINKEYBOARDVIEW_ONLONGPRESS_ENABLED = DEFAULT_ENABLED; + private static final boolean LATINKEYBOARDVIEW_ONPROCESSMOTIONEVENT_ENABLED + = DEFAULT_ENABLED; + private static final boolean POINTERTRACKER_CALLLISTENERONCANCELINPUT_ENABLED + = DEFAULT_ENABLED; + private static final boolean POINTERTRACKER_CALLLISTENERONCODEINPUT_ENABLED + = DEFAULT_ENABLED; + private static final boolean + POINTERTRACKER_CALLLISTENERONPRESSANDCHECKKEYBOARDLAYOUTCHANGE_ENABLED + = DEFAULT_ENABLED; + private static final boolean POINTERTRACKER_CALLLISTENERONRELEASE_ENABLED = DEFAULT_ENABLED; + private static final boolean POINTERTRACKER_ONDOWNEVENT_ENABLED = DEFAULT_ENABLED; + private static final boolean POINTERTRACKER_ONMOVEEVENT_ENABLED = DEFAULT_ENABLED; + private static final boolean SUDDENJUMPINGTOUCHEVENTHANDLER_ONTOUCHEVENT_ENABLED + = DEFAULT_ENABLED; } - public static void logUnstructured(UnsLogGroup logGroup, String details) { + public static void logUnstructured(String logGroup, final String details) { + // TODO: improve performance by making entire class static and/or implementing natively + getInstance().write(LogGroup.UNSTRUCTURED, logGroup + "\t" + details); } private void write(final LogGroup logGroup, final String log) { @@ -282,13 +336,14 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang builder.append('\t'); builder.append(upTime); builder.append('\t'); builder.append(logGroup.mLogString); builder.append('\t'); builder.append(log); - if (LatinImeLogger.sDBG) { + builder.append('\n'); + if (DEBUG) { Log.d(TAG, "Write: " + '[' + logGroup.mLogString + ']' + log); } if (mLogFileManager.append(builder.toString())) { // success } else { - if (LatinImeLogger.sDBG) { + if (DEBUG) { Log.w(TAG, "Unable to write to log."); } } @@ -300,7 +355,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang mLoggingHandler.post(new Runnable() { @Override public void run() { - if (LatinImeLogger.sDBG) { + if (DEBUG) { Log.d(TAG, "Delete log file."); } mLogFileManager.reset(); @@ -315,4 +370,300 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang } sIsLogging = prefs.getBoolean(PREF_USABILITY_STUDY_MODE, false); } + + public static void alphabetShiftState_setShifted(final boolean newShiftState, + final int oldState, final AlphabetShiftState alphabetShiftState) { + if (UnsLogGroup.ALPHABETSHIFTSTATE_SETSHIFTED_ENABLED) { + final String s = "setShifted(" + newShiftState + "): " + oldState + + " > " + alphabetShiftState; + logUnstructured("AlphabetShiftState_setShifted", s); + } + } + + public static void alphabetShiftState_setShiftLocked(final boolean newShiftLockState, + final int oldState, final AlphabetShiftState alphabetShiftState) { + if (UnsLogGroup.ALPHABETSHIFTSTATE_SETSHIFTLOCKED_ENABLED) { + final String s = "setShiftLocked(" + newShiftLockState + "): " + + oldState + " > " + alphabetShiftState; + logUnstructured("AlphabetShiftState_setShiftLocked", s); + } + } + + public static void alphabetShiftState_setAutomaticShifted(final int oldState, + final AlphabetShiftState alphabetShiftState) { + if (UnsLogGroup.ALPHABETSHIFTSTATE_SETAUTOMATICSHIFTED_ENABLED) { + final String s = "setAutomaticShifted: " + oldState + " > " + alphabetShiftState; + logUnstructured("AlphabetShiftState_setAutomaticShifted", s); + } + } + + public static void autoCorrection_hasAutoCorrectionForBinaryDictionary( + final CharSequence consideredWord, final double autoCorrectionThreshold, + final CharSequence autoCorrectionSuggestion, final int autoCorrectionSuggestionScore, + final double normalizedScore) { + if (UnsLogGroup.AUTOCORRECTION_HASAUTOCORRECTIONFORBINARYDICTIONARY_ENABLED) { + final String s = "Normalized " + consideredWord + "," + + autoCorrectionSuggestion + "," + autoCorrectionSuggestionScore + + ", " + normalizedScore + "(" + autoCorrectionThreshold + ")"; + logUnstructured("AutoCorrection_hasAutoCorrectionForBinaryDictionary", s); + } + } + + public static void autoCorrection_hasAutoCorrectionForBinaryDictionary_bySthreshold() { + if (UnsLogGroup.AUTOCORRECTION_HASAUTOCORRECTIONFORBINARYDICTIONARY_BYSTHRESHOLD_ENABLED) { + final String s = "Auto corrected by S-threshold."; + logUnstructured("AutoCorrection_hasAutoCorrectionForBinaryDictionar_bySthreshold", s); + } + } + + public static void keyboardState_onCancelInput(final boolean isSinglePointer, + final KeyboardState keyboardState) { + if (UnsLogGroup.KEYBOARDSTATE_ONCANCELINPUT_ENABLED) { + final String s = "onCancelInput: single=" + isSinglePointer + " " + keyboardState; + logUnstructured("KeyboardState_onCancelInput", s); + } + } + + public static void keyboardState_onCodeInput( + final int code, final boolean isSinglePointer, final boolean autoCaps, + final KeyboardState keyboardState) { + if (UnsLogGroup.KEYBOARDSTATE_ONCODEINPUT_ENABLED) { + final String s = "onCodeInput: code=" + Keyboard.printableCode(code) + + " single=" + isSinglePointer + + " autoCaps=" + autoCaps + " " + keyboardState; + logUnstructured("KeyboardState_onCodeInput", s); + } + } + + public static void keyboardState_onLongPressTimeout(final int code, + final KeyboardState keyboardState) { + if (UnsLogGroup.KEYBOARDSTATE_ONLONGPRESSTIMEOUT_ENABLED) { + final String s = "onLongPressTimeout: code=" + Keyboard.printableCode(code) + " " + + keyboardState; + logUnstructured("KeyboardState_onLongPressTimeout", s); + } + } + + public static void keyboardState_onPressKey(final int code, + final KeyboardState keyboardState) { + if (UnsLogGroup.KEYBOARDSTATE_ONPRESSKEY_ENABLED) { + final String s = "onPressKey: code=" + Keyboard.printableCode(code) + " " + + keyboardState; + logUnstructured("KeyboardState_onPressKey", s); + } + } + + public static void keyboardState_onReleaseKey(final KeyboardState keyboardState, final int code, + final boolean withSliding) { + if (UnsLogGroup.KEYBOARDSTATE_ONRELEASEKEY_ENABLED) { + final String s = "onReleaseKey: code=" + Keyboard.printableCode(code) + + " sliding=" + withSliding + " " + keyboardState; + logUnstructured("KeyboardState_onReleaseKey", s); + } + } + + public static void keyboardState_onRestoreKeyboardState(final KeyboardState keyboardState, + final String savedKeyboardState) { + if (UnsLogGroup.KEYBOARDSTATE_ONRESTOREKEYBOARDSTATE_ENABLED) { + final String s = "onRestoreKeyboardState: saved=" + savedKeyboardState + " " + + keyboardState; + logUnstructured("KeyboardState_onRestoreKeyboardState", s); + } + } + + public static void keyboardState_onSaveKeyboardState(final KeyboardState keyboardState, + final String savedKeyboardState) { + if (UnsLogGroup.KEYBOARDSTATE_ONSAVEKEYBOARDSTATE_ENABLED) { + final String s = "onSaveKeyboardState: saved=" + savedKeyboardState + " " + + keyboardState; + logUnstructured("KeyboardState_onSaveKeyboardState", s); + } + } + + public static void keyboardState_onUpdateShiftState(final KeyboardState keyboardState, + final boolean autoCaps) { + if (UnsLogGroup.KEYBOARDSTATE_ONUPDATESHIFTSTATE_ENABLED) { + final String s = "onUpdateShiftState: autoCaps=" + autoCaps + " " + keyboardState; + logUnstructured("KeyboardState_onUpdateShiftState", s); + } + } + + public static void keyboardState_setAlphabetKeyboard() { + if (UnsLogGroup.KEYBOARDSTATE_SETALPHABETKEYBOARD_ENABLED) { + final String s = "setAlphabetKeyboard"; + logUnstructured("KeyboardState_setAlphabetKeyboard", s); + } + } + + public static void keyboardState_setShifted(final KeyboardState keyboardState, + final String shiftMode) { + if (UnsLogGroup.KEYBOARDSTATE_SETSHIFTED_ENABLED) { + final String s = "setShifted: shiftMode=" + shiftMode + " " + keyboardState; + logUnstructured("KeyboardState_setShifted", s); + } + } + + public static void keyboardState_setShiftLocked(final KeyboardState keyboardState, + final boolean shiftLocked) { + if (UnsLogGroup.KEYBOARDSTATE_SETSHIFTLOCKED_ENABLED) { + final String s = "setShiftLocked: shiftLocked=" + shiftLocked + " " + keyboardState; + logUnstructured("KeyboardState_setShiftLocked", s); + } + } + + public static void keyboardState_setSymbolsKeyboard() { + if (UnsLogGroup.KEYBOARDSTATE_SETSYMBOLSKEYBOARD_ENABLED) { + final String s = "setSymbolsKeyboard"; + logUnstructured("KeyboardState_setSymbolsKeyboard", s); + } + } + + public static void keyboardState_setSymbolsShiftedKeyboard() { + if (UnsLogGroup.KEYBOARDSTATE_SETSYMBOLSSHIFTEDKEYBOARD_ENABLED) { + final String s = "setSymbolsShiftedKeyboard"; + logUnstructured("KeyboardState_setSymbolsShiftedKeyboard", s); + } + } + + public static void keyboardState_toggleAlphabetAndSymbols(final KeyboardState keyboardState) { + if (UnsLogGroup.KEYBOARDSTATE_TOGGLEALPHABETANDSYMBOLS_ENABLED) { + final String s = "toggleAlphabetAndSymbols: " + keyboardState; + logUnstructured("KeyboardState_toggleAlphabetAndSymbols", s); + } + } + + public static void latinIME_onDisplayCompletions( + final CompletionInfo[] applicationSpecifiedCompletions) { + if (UnsLogGroup.LATINIME_ONDISPLAYCOMPLETIONS_ENABLED) { + final StringBuilder builder = new StringBuilder(); + builder.append("Received completions:"); + if (applicationSpecifiedCompletions != null) { + for (int i = 0; i < applicationSpecifiedCompletions.length; i++) { + builder.append(" #"); + builder.append(i); + builder.append(": "); + builder.append(applicationSpecifiedCompletions[i]); + builder.append("\n"); + } + } + logUnstructured("LatinIME_onDisplayCompletions", builder.toString()); + } + } + + public static void latinIME_onStartInputViewInternal(final EditorInfo editorInfo) { + if (UnsLogGroup.LATINIME_ONSTARTINPUTVIEWINTERNAL_ENABLED) { + final StringBuilder builder = new StringBuilder(); + builder.append("onStartInputView: editorInfo:"); + builder.append("inputType="); + builder.append(editorInfo.inputType); + builder.append("imeOptions="); + builder.append(editorInfo.imeOptions); + logUnstructured("LatinIME_onStartInputViewInternal", builder.toString()); + } + } + + public static void latinIME_onUpdateSelection(final int lastSelectionStart, + final int lastSelectionEnd, final int oldSelStart, final int oldSelEnd, + final int newSelStart, final int newSelEnd, final int composingSpanStart, + final int composingSpanEnd) { + if (UnsLogGroup.LATINIME_ONUPDATESELECTION_ENABLED) { + final String s = "onUpdateSelection: oss=" + oldSelStart + + ", ose=" + oldSelEnd + + ", lss=" + lastSelectionStart + + ", lse=" + lastSelectionEnd + + ", nss=" + newSelStart + + ", nse=" + newSelEnd + + ", cs=" + composingSpanStart + + ", ce=" + composingSpanEnd; + logUnstructured("LatinIME_onUpdateSelection", s); + } + } + + public static void latinIME_switchToKeyboardView() { + if (UnsLogGroup.LATINIME_SWITCHTOKEYBOARDVIEW_ENABLED) { + final String s = "Switch to keyboard view."; + logUnstructured("LatinIME_switchToKeyboardView", s); + } + } + + public static void latinKeyboardView_onLongPress() { + if (UnsLogGroup.LATINKEYBOARDVIEW_ONLONGPRESS_ENABLED) { + final String s = "long press detected"; + logUnstructured("LatinKeyboardView_onLongPress", s); + } + } + + public static void latinKeyboardView_processMotionEvent(MotionEvent me, int action, + long eventTime, int index, int id, int x, int y) { + if (UnsLogGroup.LATINKEYBOARDVIEW_ONPROCESSMOTIONEVENT_ENABLED) { + final float size = me.getSize(index); + final float pressure = me.getPressure(index); + if (action != MotionEvent.ACTION_MOVE) { + getInstance().logMotionEvent(action, eventTime, id, x, y, size, pressure); + } + } + } + + public static void pointerTracker_callListenerOnCancelInput() { + final String s = "onCancelInput"; + if (UnsLogGroup.POINTERTRACKER_CALLLISTENERONCANCELINPUT_ENABLED) { + logUnstructured("PointerTracker_callListenerOnCancelInput", s); + } + } + + public static void pointerTracker_callListenerOnCodeInput(final Key key, final int x, + final int y, final boolean ignoreModifierKey, final boolean altersCode, + final int code) { + if (UnsLogGroup.POINTERTRACKER_CALLLISTENERONCODEINPUT_ENABLED) { + final String s = "onCodeInput: " + Keyboard.printableCode(code) + + " text=" + key.mOutputText + " x=" + x + " y=" + y + + " ignoreModifier=" + ignoreModifierKey + " altersCode=" + altersCode + + " enabled=" + key.isEnabled(); + logUnstructured("PointerTracker_callListenerOnCodeInput", s); + } + } + + public static void pointerTracker_callListenerOnPressAndCheckKeyboardLayoutChange( + final Key key, final boolean ignoreModifierKey) { + if (UnsLogGroup.POINTERTRACKER_CALLLISTENERONPRESSANDCHECKKEYBOARDLAYOUTCHANGE_ENABLED) { + final String s = "onPress : " + KeyDetector.printableCode(key) + + " ignoreModifier=" + ignoreModifierKey + + " enabled=" + key.isEnabled(); + logUnstructured("PointerTracker_callListenerOnPressAndCheckKeyboardLayoutChange", s); + } + } + + public static void pointerTracker_callListenerOnRelease(final Key key, final int primaryCode, + final boolean withSliding, final boolean ignoreModifierKey) { + if (UnsLogGroup.POINTERTRACKER_CALLLISTENERONRELEASE_ENABLED) { + final String s = "onRelease : " + Keyboard.printableCode(primaryCode) + + " sliding=" + withSliding + " ignoreModifier=" + ignoreModifierKey + + " enabled="+ key.isEnabled(); + logUnstructured("PointerTracker_callListenerOnRelease", s); + } + } + + public static void pointerTracker_onDownEvent(long deltaT, int distanceSquared) { + if (UnsLogGroup.POINTERTRACKER_ONDOWNEVENT_ENABLED) { + final String s = "onDownEvent: ignore potential noise: time=" + deltaT + + " distance=" + distanceSquared; + logUnstructured("PointerTracker_onDownEvent", s); + } + } + + public static void pointerTracker_onMoveEvent(final int x, final int y, final int lastX, + final int lastY) { + if (UnsLogGroup.POINTERTRACKER_ONMOVEEVENT_ENABLED) { + final String s = String.format("onMoveEvent: sudden move is translated to " + + "up[%d,%d]/down[%d,%d] events", lastX, lastY, x, y); + logUnstructured("PointerTracker_onMoveEvent", s); + } + } + + public static void suddenJumpingTouchEventHandler_onTouchEvent(final MotionEvent me) { + if (UnsLogGroup.SUDDENJUMPINGTOUCHEVENTHANDLER_ONTOUCHEVENT_ENABLED) { + final String s = "onTouchEvent: ignore sudden jump " + me; + logUnstructured("SuddenJumpingTouchEventHandler_onTouchEvent", s); + } + } }