Add a log for getting coordinates of keys

Change-Id: I57cc6fb6a9eeb65ce8c0c3c3262fd525726643e2
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index 0e6b18a..2753bb8 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -1073,7 +1073,7 @@
 
     // Implementation of KeyboardViewListener
 
-    public void onKey(int primaryCode, int[] keyCodes) {
+    public void onKey(int primaryCode, int[] keyCodes, int x, int y) {
         long when = SystemClock.uptimeMillis();
         if (primaryCode != Keyboard.KEYCODE_DELETE ||
                 when > mLastKeyTime + QUICK_PRESS) {
@@ -1121,7 +1121,7 @@
                 if (primaryCode != KEYCODE_ENTER) {
                     mJustAddedAutoSpace = false;
                 }
-                LatinImeLogger.logOnInputChar((char)primaryCode);
+                LatinImeLogger.logOnInputChar((char)primaryCode, x, y);
                 if (isWordSeparator(primaryCode)) {
                     handleSeparator(primaryCode);
                 } else {
@@ -1768,7 +1768,8 @@
             // So, LatinImeLogger logs "" as a user's input.
             LatinImeLogger.logOnManualSuggestion(
                     "", suggestion.toString(), index, suggestions);
-            onKey(suggestion.charAt(0), null);
+            onKey(suggestion.charAt(0), null, LatinKeyboardBaseView.NOT_A_TOUCH_COORDINATE,
+                    LatinKeyboardBaseView.NOT_A_TOUCH_COORDINATE);
             if (ic != null) {
                 ic.endBatchEdit();
             }
diff --git a/java/src/com/android/inputmethod/latin/LatinImeLogger.java b/java/src/com/android/inputmethod/latin/LatinImeLogger.java
index 19eead0..f9f0790 100644
--- a/java/src/com/android/inputmethod/latin/LatinImeLogger.java
+++ b/java/src/com/android/inputmethod/latin/LatinImeLogger.java
@@ -22,6 +22,7 @@
 import android.content.SharedPreferences;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager.NameNotFoundException;
+import android.inputmethodservice.Keyboard;
 import android.os.AsyncTask;
 import android.os.DropBoxManager;
 import android.preference.PreferenceManager;
@@ -54,11 +55,12 @@
     private static final char SEPARATER = ';';
     private static final char NULL_CHAR = '\uFFFC';
     private static final int EXCEPTION_MAX_LENGTH = 400;
+    private static final int INVALID_COORDINATE = -2;
 
     // ID_MANUALSUGGESTION has been replaced by ID_MANUALSUGGESTION_WITH_DATATYPE
     // private static final int ID_MANUALSUGGESTION = 0;
-    private static final int ID_AUTOSUGGESTIONCANCELLED = 1;
-    private static final int ID_AUTOSUGGESTION = 2;
+    // private static final int ID_AUTOSUGGESTIONCANCELLED = 1;
+    // private static final int ID_AUTOSUGGESTION = 2;
     private static final int ID_INPUT_COUNT = 3;
     private static final int ID_DELETE_COUNT = 4;
     private static final int ID_WORD_COUNT = 5;
@@ -72,6 +74,8 @@
     private static final int ID_AUTOSUGGESTIONCOUNT = 13;
     private static final int ID_LANGUAGES = 14;
     private static final int ID_MANUALSUGGESTION_WITH_DATATYPE = 15;
+    private static final int ID_AUTOSUGGESTIONCANCELLED_WITH_COORDINATES = 16;
+    private static final int ID_AUTOSUGGESTION_WITH_COORDINATES = 17;
 
     private static final String PREF_ENABLE_LOG = "enable_logging";
     private static final String PREF_DEBUG_MODE = "debug_mode";
@@ -84,6 +88,8 @@
     /* package */ static String sLastAutoSuggestBefore;
     /* package */ static String sLastAutoSuggestAfter;
     /* package */ static String sLastAutoSuggestSeparator;
+    private static int[] sLastAutoSuggestXCoordinates;
+    private static int[] sLastAutoSuggestYCoordinates;
     // This value holds MAIN, USER, AUTO, etc...
     private static int sLastAutoSuggestDicTypeId;
     // This value holds 0 (= unigram), 1 (= bigram) etc...
@@ -92,6 +98,8 @@
             = new HashMap<String, Pair<Integer, Integer>>();
     private static String[] sPreviousWords;
     private static DebugKeyEnabler sDebugKeyEnabler = new DebugKeyEnabler();
+    private static int sKeyboardWidth = 0;
+    private static int sKeyboardHeight = 0;
 
     private ArrayList<LogEntry> mLogBuffer = null;
     private ArrayList<LogEntry> mPrivacyLogBuffer = null;
@@ -362,7 +370,7 @@
                 mInputCount += (Integer)data;
                 break;
             case ID_MANUALSUGGESTION_WITH_DATATYPE:
-            case ID_AUTOSUGGESTION:
+            case ID_AUTOSUGGESTION_WITH_COORDINATES:
                 ++mWordCount;
                 String[] dataStrings = (String[]) data;
                 if (dataStrings.length < 2) {
@@ -381,7 +389,7 @@
                     }
                 }
                 break;
-            case ID_AUTOSUGGESTIONCANCELLED:
+            case ID_AUTOSUGGESTIONCANCELLED_WITH_COORDINATES:
                 --mWordCount;
                 dataStrings = (String[]) data;
                 if (dataStrings.length < 2) {
@@ -461,7 +469,7 @@
             } else if (s instanceof Integer) {
                 out += (Integer) s;
             }
-            Log.d(TAG, "SendLog: " + tag + ";" + out + ", will be sent after "
+            Log.d(TAG, "SendLog: " + tag + ";" + out + " -> will be sent after "
                     + (- (now - mLastTimeSend - MINIMUMSENDINTERVAL) / 1000) + " sec.");
         }
         if (now - mLastTimeActive > MINIMUMSENDINTERVAL) {
@@ -625,7 +633,8 @@
                 sLatinImeLogger.mAutoSuggestCountPerDic[sLastAutoSuggestDicTypeId]++;
                 if (sLastAutoSuggestDicTypeId != Suggest.DIC_MAIN) {
                     if (sDBG) {
-                        Log.d(TAG, "logOnAutoSuggestion was cancelled: not from main dic.");
+                        Log.d(TAG, "logOnAutoSuggestion was cancelled: not from main dic.:"
+                                + sLastAutoSuggestDicTypeId);
                     }
                     before = "";
                     after = "";
@@ -637,23 +646,46 @@
                         before = "";
                         after = "";
                     }
-                    int previousWordsLength = (sPreviousWords == null) ? 0 : sPreviousWords.length;
 
                     final int COLUMN_BEFORE_ID = 0;
                     final int COLUMN_AFTER_ID = 1;
                     final int COLUMN_SEPARATOR_ID = 2;
                     final int COLUMN_DATA_TYPE_ID = 3;
-                    final int BASE_COLUMN_SIZE = 4;
+                    final int COLUMN_KEYBOARD_SIZE_WIDTH = 4;
+                    final int COLUMN_KEYBOARD_SIZE_HEIGHT = 5;
+                    final int BASE_COLUMN_SIZE = 6;
 
-                    String[] strings = new String[4 + previousWordsLength];
+                    final int userTypedWordLength = before.length();
+                    final int previousWordsLength = (sPreviousWords == null) ? 0
+                            : sPreviousWords.length;
+                    String[] strings = new String[BASE_COLUMN_SIZE + userTypedWordLength * 2
+                                                  + previousWordsLength];
+                    sLastAutoSuggestXCoordinates = new int[userTypedWordLength];
+                    sLastAutoSuggestXCoordinates = new int[userTypedWordLength];
+
                     strings[COLUMN_BEFORE_ID] = before;
                     strings[COLUMN_AFTER_ID] = after;
                     strings[COLUMN_SEPARATOR_ID] = separator;
                     strings[COLUMN_DATA_TYPE_ID] = String.valueOf(sLastAutoSuggestDataType);
-                    for (int i = 0; i < previousWordsLength; ++i) {
-                        strings[BASE_COLUMN_SIZE + i] = sPreviousWords[i];
+                    strings[COLUMN_KEYBOARD_SIZE_WIDTH] = String.valueOf(sKeyboardWidth);
+                    strings[COLUMN_KEYBOARD_SIZE_HEIGHT] = String.valueOf(sKeyboardHeight);
+
+                    for (int i = 0; i < userTypedWordLength; ++i) {
+                        int x = sLatinImeLogger.mRingCharBuffer.getPreviousX(before.charAt(i),
+                                userTypedWordLength - i - 1);
+                        int y = sLatinImeLogger.mRingCharBuffer.getPreviousY(before.charAt(i),
+                                userTypedWordLength - i - 1);
+                        strings[BASE_COLUMN_SIZE + i * 2] = String.valueOf(x);
+                        strings[BASE_COLUMN_SIZE + i * 2 + 1] = String.valueOf(y);
+                        sLastAutoSuggestXCoordinates[i] = x;
+                        sLastAutoSuggestXCoordinates[i] = y;
                     }
-                    sLatinImeLogger.sendLogToDropBox(ID_AUTOSUGGESTION, strings);
+
+                    for (int i = 0; i < previousWordsLength; ++i) {
+                        strings[BASE_COLUMN_SIZE + userTypedWordLength * 2 + i] = sPreviousWords[i];
+                    }
+
+                    sLatinImeLogger.sendLogToDropBox(ID_AUTOSUGGESTION_WITH_COORDINATES, strings);
                 }
                 synchronized (LatinImeLogger.class) {
                     sLastAutoSuggestBefore = before;
@@ -669,9 +701,29 @@
         if (sLogEnabled) {
             sLatinImeLogger.mAutoCancelledCountPerDic[sLastAutoSuggestDicTypeId]++;
             if (sLastAutoSuggestBefore != null && sLastAutoSuggestAfter != null) {
-                String[] strings = new String[] {
-                        sLastAutoSuggestBefore, sLastAutoSuggestAfter, sLastAutoSuggestSeparator};
-                sLatinImeLogger.sendLogToDropBox(ID_AUTOSUGGESTIONCANCELLED, strings);
+                final int COLUMN_BEFORE_ID = 0;
+                final int COLUMN_AFTER_ID = 1;
+                final int COLUMN_SEPARATOR_ID = 2;
+                final int COLUMN_KEYBOARD_SIZE_WIDTH = 3;
+                final int COLUMN_KEYBOARD_SIZE_HEIGHT = 4;
+                final int BASE_COLUMN_SIZE = 5;
+
+                final int userTypedWordLength = sLastAutoSuggestBefore.length();
+
+                String[] strings = new String[BASE_COLUMN_SIZE + userTypedWordLength * 2];
+                strings[COLUMN_BEFORE_ID] = sLastAutoSuggestBefore;
+                strings[COLUMN_AFTER_ID] = sLastAutoSuggestAfter;
+                strings[COLUMN_SEPARATOR_ID] = sLastAutoSuggestSeparator;
+                strings[COLUMN_KEYBOARD_SIZE_WIDTH] = String.valueOf(sKeyboardWidth);
+                strings[COLUMN_KEYBOARD_SIZE_HEIGHT] = String.valueOf(sKeyboardHeight);
+                for (int i = 0; i < userTypedWordLength; ++i) {
+                    strings[BASE_COLUMN_SIZE + i * 2] = String.valueOf(
+                            sLastAutoSuggestXCoordinates);
+                    strings[BASE_COLUMN_SIZE + i * 2 + 1] = String.valueOf(
+                            sLastAutoSuggestYCoordinates);
+                }
+                sLatinImeLogger.sendLogToDropBox(
+                        ID_AUTOSUGGESTIONCANCELLED_WITH_COORDINATES, strings);
             }
             synchronized (LatinImeLogger.class) {
                 sLastAutoSuggestBefore = "";
@@ -693,9 +745,9 @@
         }
     }
 
-    public static void logOnInputChar(char c) {
+    public static void logOnInputChar(char c, int x, int y) {
         if (sLogEnabled) {
-            sLatinImeLogger.mRingCharBuffer.push(c);
+            sLatinImeLogger.mRingCharBuffer.push(c, x, y);
             sLatinImeLogger.sendLogToDropBox(ID_INPUT_COUNT, 1);
         }
     }
@@ -747,6 +799,13 @@
         }
     }
 
+    public static void onSetKeyboard(Keyboard kb) {
+        if (sLogEnabled) {
+            sKeyboardWidth = kb.getMinWidth();
+            sKeyboardHeight = kb.getHeight();
+        }
+    }
+
     private static class LogSerializer {
         private static void appendWithLength(StringBuffer sb, String data) {
             sb.append(data.length());
@@ -780,43 +839,64 @@
         final int BUFSIZE = 20;
         private Context mContext;
         private int mEnd = 0;
-        /* package */ int length = 0;
+        /* package */ int mLength = 0;
         private char[] mCharBuf = new char[BUFSIZE];
+        private int[] mXBuf = new int[BUFSIZE];
+        private int[] mYBuf = new int[BUFSIZE];
 
         public RingCharBuffer(Context context) {
             mContext = context;
         }
-
         private int normalize(int in) {
             int ret = in % BUFSIZE;
             return ret < 0 ? ret + BUFSIZE : ret;
         }
-        public void push(char c) {
+        public void push(char c, int x, int y) {
             mCharBuf[mEnd] = c;
+            mXBuf[mEnd] = x;
+            mYBuf[mEnd] = y;
             mEnd = normalize(mEnd + 1);
-            if (length < BUFSIZE) {
-                ++length;
+            if (mLength < BUFSIZE) {
+                ++mLength;
             }
         }
         public char pop() {
-            if (length < 1) {
+            if (mLength < 1) {
                 return NULL_CHAR;
             } else {
                 mEnd = normalize(mEnd - 1);
-                --length;
+                --mLength;
                 return mCharBuf[mEnd];
             }
         }
         public char getLastChar() {
-            if (length < 1) {
+            if (mLength < 1) {
                 return NULL_CHAR;
             } else {
                 return mCharBuf[normalize(mEnd - 1)];
             }
         }
+        public int getPreviousX(char c, int back) {
+            int index = normalize(mEnd - 2 - back);
+            if (mLength <= back
+                    || Character.toLowerCase(c) != Character.toLowerCase(mCharBuf[index])) {
+                return INVALID_COORDINATE;
+            } else {
+                return mXBuf[index];
+            }
+        }
+        public int getPreviousY(char c, int back) {
+            int index = normalize(mEnd - 2 - back);
+            if (mLength <= back
+                    || Character.toLowerCase(c) != Character.toLowerCase(mCharBuf[index])) {
+                return INVALID_COORDINATE;
+            } else {
+                return mYBuf[index];
+            }
+        }
         public String getLastString() {
             StringBuffer sb = new StringBuffer();
-            for (int i = 0; i < length; ++i) {
+            for (int i = 0; i < mLength; ++i) {
                 char c = mCharBuf[normalize(mEnd - 1 - i)];
                 if (!((LatinIME)mContext).isWordSeparator(c)) {
                     sb.append(c);
@@ -827,7 +907,7 @@
             return sb.reverse().toString();
         }
         public void reset() {
-            length = 0;
+            mLength = 0;
         }
     }
 
diff --git a/java/src/com/android/inputmethod/latin/LatinKeyboardBaseView.java b/java/src/com/android/inputmethod/latin/LatinKeyboardBaseView.java
index 8a8a12c..7247632 100644
--- a/java/src/com/android/inputmethod/latin/LatinKeyboardBaseView.java
+++ b/java/src/com/android/inputmethod/latin/LatinKeyboardBaseView.java
@@ -100,8 +100,14 @@
          *            keys. These codes are useful to correct for
          *            accidental presses of a key adjacent to the intended
          *            key.
+         * @param x
+         *            x-coordinate pixel of touched event. If onKey is not called by onTouchEvent,
+         *            the value should be NOT_A_TOUCH_COORDINATE.
+         * @param y
+         *            y-coordinate pixel of touched event. If onKey is not called by onTouchEvent,
+         *            the value should be NOT_A_TOUCH_COORDINATE.
          */
-        void onKey(int primaryCode, int[] keyCodes);
+        void onKey(int primaryCode, int[] keyCodes, int x, int y);
 
         /**
          * Sends a sequence of characters to the listener.
@@ -134,6 +140,8 @@
         void swipeUp();
     }
 
+    public static final int NOT_A_TOUCH_COORDINATE = -1;
+
     private static final boolean DEBUG = false;
     private static final int NOT_A_KEY = -1;
     private static final int[] KEY_DELETE = { Keyboard.KEYCODE_DELETE };
@@ -614,6 +622,7 @@
         mHandler.cancelKeyTimers();
         mHandler.cancelPopupPreview();
         mKeyboard = keyboard;
+        LatinImeLogger.onSetKeyboard(mKeyboard);
         List<Key> keys = mKeyboard.getKeys();
         mKeys = keys.toArray(new Key[keys.size()]);
         requestLayout();
@@ -975,7 +984,7 @@
                 // Multi-tap
                 if (mInMultiTap) {
                     if (mTapCount != -1) {
-                        mKeyboardActionListener.onKey(Keyboard.KEYCODE_DELETE, KEY_DELETE);
+                        mKeyboardActionListener.onKey(Keyboard.KEYCODE_DELETE, KEY_DELETE, x, y);
                     } else {
                         mTapCount = 0;
                     }
@@ -990,7 +999,7 @@
                     codes[1] = codes[0];
                     codes[0] = code;
                 }
-                mKeyboardActionListener.onKey(code, codes);
+                mKeyboardActionListener.onKey(code, codes, x, y);
                 mKeyboardActionListener.onRelease(code);
             }
             mLastSentIndex = index;
@@ -1198,8 +1207,8 @@
                         R.id.closeButton);
                 if (closeButton != null) closeButton.setOnClickListener(this);
                 mMiniKeyboard.setOnKeyboardActionListener(new OnKeyboardActionListener() {
-                    public void onKey(int primaryCode, int[] keyCodes) {
-                        mKeyboardActionListener.onKey(primaryCode, keyCodes);
+                    public void onKey(int primaryCode, int[] keyCodes, int x, int y) {
+                        mKeyboardActionListener.onKey(primaryCode, keyCodes, x, y);
                         dismissPopupKeyboard();
                     }
 
diff --git a/java/src/com/android/inputmethod/latin/LatinKeyboardView.java b/java/src/com/android/inputmethod/latin/LatinKeyboardView.java
index 38d9cef..e57abd2 100644
--- a/java/src/com/android/inputmethod/latin/LatinKeyboardView.java
+++ b/java/src/com/android/inputmethod/latin/LatinKeyboardView.java
@@ -96,15 +96,21 @@
     @Override
     protected boolean onLongPress(Key key) {
         if (key.codes[0] == Keyboard.KEYCODE_MODE_CHANGE) {
-            getOnKeyboardActionListener().onKey(KEYCODE_OPTIONS, null);
+            getOnKeyboardActionListener().onKey(KEYCODE_OPTIONS, null,
+                    LatinKeyboardBaseView.NOT_A_TOUCH_COORDINATE,
+                    LatinKeyboardBaseView.NOT_A_TOUCH_COORDINATE);
             return true;
         } else if (key.codes[0] == Keyboard.KEYCODE_SHIFT) {
-            getOnKeyboardActionListener().onKey(KEYCODE_SHIFT_LONGPRESS, null);
+            getOnKeyboardActionListener().onKey(KEYCODE_SHIFT_LONGPRESS, null,
+                    LatinKeyboardBaseView.NOT_A_TOUCH_COORDINATE,
+                    LatinKeyboardBaseView.NOT_A_TOUCH_COORDINATE);
             invalidateAllKeys();
             return true;
         } else if (key.codes[0] == '0' && getKeyboard() == mPhoneKeyboard) {
             // Long pressing on 0 in phone number keypad gives you a '+'.
-            getOnKeyboardActionListener().onKey('+', null);
+            getOnKeyboardActionListener().onKey(
+                    '+', null, LatinKeyboardBaseView.NOT_A_TOUCH_COORDINATE,
+                    LatinKeyboardBaseView.NOT_A_TOUCH_COORDINATE);
             return true;
         } else {
             return super.onLongPress(key);
@@ -235,7 +241,7 @@
             if (languageDirection != 0) {
                 getOnKeyboardActionListener().onKey(
                         languageDirection == 1 ? KEYCODE_NEXT_LANGUAGE : KEYCODE_PREV_LANGUAGE,
-                        null);
+                        null, mLastX, mLastY);
                 me.setAction(MotionEvent.ACTION_CANCEL);
                 keyboard.keyReleased();
                 return super.onTouchEvent(me);
@@ -366,8 +372,8 @@
         ExtensionKeyboardListener(OnKeyboardActionListener target) {
             mTarget = target;
         }
-        public void onKey(int primaryCode, int[] keyCodes) {
-            mTarget.onKey(primaryCode, keyCodes);
+        public void onKey(int primaryCode, int[] keyCodes, int x, int y) {
+            mTarget.onKey(primaryCode, keyCodes, x, y);
         }
         public void onPress(int primaryCode) {
             mTarget.onPress(primaryCode);