From 9bc29d78a6ce83f77869aa63748176241e29d43c Mon Sep 17 00:00:00 2001
From: Kurt Partridge <kep@google.com>
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);
+        }
+    }
 }