1d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge/*
2d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge * Copyright (C) 2012 The Android Open Source Project
3d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge *
4d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge * use this file except in compliance with the License. You may obtain a copy of
6d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge * the License at
7d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge *
8d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge * http://www.apache.org/licenses/LICENSE-2.0
9d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge *
10d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge * Unless required by applicable law or agreed to in writing, software
11d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge * License for the specific language governing permissions and limitations under
14d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge * the License.
15d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge */
16d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge
176b966160ac8570271547bf63217efa5e228d4accKurt Partridgepackage com.android.inputmethod.research;
18d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge
1986fcadde5d1ca69e4d93dc7cf5e72c763a32ac84Kurt Partridgeimport static com.android.inputmethod.latin.Constants.Subtype.ExtraValue.KEYBOARD_LAYOUT_SET;
2086fcadde5d1ca69e4d93dc7cf5e72c763a32ac84Kurt Partridge
21b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridgeimport android.app.AlarmManager;
22724bc479f7d796d6ce5d5e200216bea855b818b2Kurt Partridgeimport android.app.AlertDialog;
234331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridgeimport android.app.Dialog;
24b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridgeimport android.app.PendingIntent;
2573c5dbd9d262159af3475273b79babe292c75d76Kurt Partridgeimport android.content.Context;
26724bc479f7d796d6ce5d5e200216bea855b818b2Kurt Partridgeimport android.content.DialogInterface;
274331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridgeimport android.content.DialogInterface.OnCancelListener;
28b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridgeimport android.content.Intent;
29d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridgeimport android.content.SharedPreferences;
3077814c4bb0670c3a20c5e636890d70ea1a144409Kurt Partridgeimport android.content.SharedPreferences.Editor;
3173c5dbd9d262159af3475273b79babe292c75d76Kurt Partridgeimport android.content.pm.PackageInfo;
3273c5dbd9d262159af3475273b79babe292c75d76Kurt Partridgeimport android.content.pm.PackageManager.NameNotFoundException;
334fa6e5726041a22db4f15d99521ea06419401946Kurt Partridgeimport android.graphics.Canvas;
344fa6e5726041a22db4f15d99521ea06419401946Kurt Partridgeimport android.graphics.Color;
354fa6e5726041a22db4f15d99521ea06419401946Kurt Partridgeimport android.graphics.Paint;
364fa6e5726041a22db4f15d99521ea06419401946Kurt Partridgeimport android.graphics.Paint.Style;
37c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaokaimport android.inputmethodservice.InputMethodService;
3825405eafb05d6f2096922b04e5d9ff2ac2bd1a10Kurt Partridgeimport android.net.Uri;
3948a7681e064ae259b840f0e757da2d716043d893Kurt Partridgeimport android.os.Build;
404331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridgeimport android.os.IBinder;
410a30688080864e59b12196664e7b3cac10d0a8daKurt Partridgeimport android.os.SystemClock;
42d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridgeimport android.text.TextUtils;
4381dae8d015f63834b2ded44424636b625ece7736Kurt Partridgeimport android.text.format.DateUtils;
44d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridgeimport android.util.Log;
4594e7f4bef970431f509a806d1b92b19fc3b5ce7dKurt Partridgeimport android.view.KeyEvent;
46d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridgeimport android.view.MotionEvent;
474331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridgeimport android.view.Window;
484331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridgeimport android.view.WindowManager;
499bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridgeimport android.view.inputmethod.CompletionInfo;
5094e7f4bef970431f509a806d1b92b19fc3b5ce7dKurt Partridgeimport android.view.inputmethod.CorrectionInfo;
519bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridgeimport android.view.inputmethod.EditorInfo;
52d67a248de45a698d1009757c9f4e750c77bf35f1Kurt Partridgeimport android.view.inputmethod.InputConnection;
53724bc479f7d796d6ce5d5e200216bea855b818b2Kurt Partridgeimport android.widget.Toast;
54d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge
559bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridgeimport com.android.inputmethod.keyboard.Key;
56d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridgeimport com.android.inputmethod.keyboard.Keyboard;
5786fcadde5d1ca69e4d93dc7cf5e72c763a32ac84Kurt Partridgeimport com.android.inputmethod.keyboard.KeyboardId;
584fa6e5726041a22db4f15d99521ea06419401946Kurt Partridgeimport com.android.inputmethod.keyboard.KeyboardView;
59c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaokaimport com.android.inputmethod.keyboard.MainKeyboardView;
605f282ea9e4a4590fcbab6e27d5fca7dacbb40a6aTadashi G. Takaokaimport com.android.inputmethod.latin.CollectionUtils;
61ac78633be28e8990fc3b3a8de192c80966e746e3Tadashi G. Takaokaimport com.android.inputmethod.latin.Constants;
626b966160ac8570271547bf63217efa5e228d4accKurt Partridgeimport com.android.inputmethod.latin.Dictionary;
636b966160ac8570271547bf63217efa5e228d4accKurt Partridgeimport com.android.inputmethod.latin.LatinIME;
646b966160ac8570271547bf63217efa5e228d4accKurt Partridgeimport com.android.inputmethod.latin.R;
656b966160ac8570271547bf63217efa5e228d4accKurt Partridgeimport com.android.inputmethod.latin.RichInputConnection;
6665fc909e13134d34e87d5d75ff4cdd46fb9cebf0Kurt Partridgeimport com.android.inputmethod.latin.RichInputConnection.Range;
676b966160ac8570271547bf63217efa5e228d4accKurt Partridgeimport com.android.inputmethod.latin.Suggest;
686b966160ac8570271547bf63217efa5e228d4accKurt Partridgeimport com.android.inputmethod.latin.SuggestedWords;
699bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridgeimport com.android.inputmethod.latin.define.ProductionFlag;
70d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge
71d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridgeimport java.io.File;
7207cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridgeimport java.text.SimpleDateFormat;
7307cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridgeimport java.util.Date;
7407cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridgeimport java.util.Locale;
7577814c4bb0670c3a20c5e636890d70ea1a144409Kurt Partridgeimport java.util.UUID;
76d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge
77d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge/**
78d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge * Logs the use of the LatinIME keyboard.
79d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge *
80d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge * This class logs operations on the IME keyboard, including what the user has typed.
81d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge * Data is stored locally in a file in app-specific storage.
82d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge *
8393ebf74bae44728e0d5f7e738ea28376187a876eTadashi G. Takaoka * This functionality is off by default. See {@link ProductionFlag#IS_EXPERIMENTAL}.
84d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge */
85d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridgepublic class ResearchLogger implements SharedPreferences.OnSharedPreferenceChangeListener {
86d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge    private static final String TAG = ResearchLogger.class.getSimpleName();
87fe05b881342645f75428cc51849f7326cb76a408Kurt Partridge    private static final boolean DEBUG = false;
886080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge    private static final boolean OUTPUT_ENTIRE_BUFFER = false;  // true may disclose private info
896b966160ac8570271547bf63217efa5e228d4accKurt Partridge    public static final boolean DEFAULT_USABILITY_STUDY_MODE = false;
9007cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    /* package */ static boolean sIsLogging = false;
9158caa775a700e99d18cdca922861f1882bf8d1f4Kurt Partridge    private static final int OUTPUT_FORMAT_VERSION = 1;
9207cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    private static final String PREF_USABILITY_STUDY_MODE = "usability_study_mode";
934331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge    private static final String PREF_RESEARCH_HAS_SEEN_SPLASH = "pref_research_has_seen_splash";
940df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge    /* package */ static final String FILENAME_PREFIX = "researchLog";
9507cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    private static final String FILENAME_SUFFIX = ".txt";
9607cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    private static final SimpleDateFormat TIMESTAMP_DATEFORMAT =
97223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge            new SimpleDateFormat("yyyyMMddHHmmssS", Locale.US);
984fa6e5726041a22db4f15d99521ea06419401946Kurt Partridge    private static final boolean IS_SHOWING_INDICATOR = true;
994fa6e5726041a22db4f15d99521ea06419401946Kurt Partridge    private static final boolean IS_SHOWING_INDICATOR_CLEARLY = false;
100bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge    public static final int FEEDBACK_WORD_BUFFER_SIZE = 5;
10107cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge
10207cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    // constants related to specific log points
103aec44d50a7534d8704a7006b4f90f5e8040a931bKurt Partridge    private static final String WHITESPACE_SEPARATORS = " \t\n\r";
104d67a248de45a698d1009757c9f4e750c77bf35f1Kurt Partridge    private static final int MAX_INPUTVIEW_LENGTH_TO_CAPTURE = 8192; // must be >=1
10507cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    private static final String PREF_RESEARCH_LOGGER_UUID_STRING = "pref_research_logger_uuid";
106d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge
10707cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    private static final ResearchLogger sInstance = new ResearchLogger();
10807cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    // to write to a different filename, e.g., for testing, set mFile before calling start()
109223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge    /* package */ File mFilesDir;
110223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge    /* package */ String mUUIDString;
111223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge    /* package */ ResearchLog mMainResearchLog;
112bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge    // mFeedbackLog records all events for the session, private or not (excepting
113223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge    // passwords).  It is written to permanent storage only if the user explicitly commands
114223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge    // the system to do so.
115bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge    // LogUnits are queued in the LogBuffers and published to the ResearchLogs when words are
116bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge    // complete.
117bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge    /* package */ ResearchLog mFeedbackLog;
118bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge    /* package */ MainLogBuffer mMainLogBuffer;
119bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge    /* package */ LogBuffer mFeedbackLogBuffer;
120223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge
1211cef91e4818790ea5419a6ad9ff6e36ac535c763Kurt Partridge    private boolean mIsPasswordView = false;
122223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge    private boolean mIsLoggingSuspended = false;
1230df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge    private SharedPreferences mPrefs;
124d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge
125a696781c2b18d8002275aa89e07fa7379661d025Kurt Partridge    // digits entered by the user are replaced with this codepoint.
126a696781c2b18d8002275aa89e07fa7379661d025Kurt Partridge    /* package for test */ static final int DIGIT_REPLACEMENT_CODEPOINT =
127a696781c2b18d8002275aa89e07fa7379661d025Kurt Partridge            Character.codePointAt("\uE000", 0);  // U+E000 is in the "private-use area"
1286080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge    // U+E001 is in the "private-use area"
1296080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge    /* package for test */ static final String WORD_REPLACEMENT_STRING = "\uE001";
13081dae8d015f63834b2ded44424636b625ece7736Kurt Partridge    private static final String PREF_LAST_CLEANUP_TIME = "pref_last_cleanup_time";
13181dae8d015f63834b2ded44424636b625ece7736Kurt Partridge    private static final long DURATION_BETWEEN_DIR_CLEANUP_IN_MS = DateUtils.DAY_IN_MILLIS;
13281dae8d015f63834b2ded44424636b625ece7736Kurt Partridge    private static final long MAX_LOGFILE_AGE_IN_MS = DateUtils.DAY_IN_MILLIS;
1330df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge    protected static final int SUSPEND_DURATION_IN_MINUTES = 1;
13407cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    // set when LatinIME should ignore an onUpdateSelection() callback that
13507cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    // arises from operations in this class
13607cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    private static boolean sLatinIMEExpectingUpdateSelection = false;
137d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge
1386080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge    // used to check whether words are not unique
1396080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge    private Suggest mSuggest;
1406080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge    private Dictionary mDictionary;
141c3f78c9057a5710898feaf8027659484477e5821Tadashi G. Takaoka    private MainKeyboardView mMainKeyboardView;
1424331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge    private InputMethodService mInputMethodService;
1430a30688080864e59b12196664e7b3cac10d0a8daKurt Partridge    private final Statistics mStatistics;
144b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge
145b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge    private Intent mUploadIntent;
146b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge    private PendingIntent mUploadPendingIntent;
1479c539d5a5c8e9b36be482fd7ebb2a71a22ef6af0Kurt Partridge
148bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge    private LogUnit mCurrentLogUnit = new LogUnit();
149bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge
15007cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    private ResearchLogger() {
1510a30688080864e59b12196664e7b3cac10d0a8daKurt Partridge        mStatistics = Statistics.getInstance();
15207cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    }
153d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge
15407cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    public static ResearchLogger getInstance() {
15507cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge        return sInstance;
15607cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    }
157d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge
158c3f78c9057a5710898feaf8027659484477e5821Tadashi G. Takaoka    public void init(final InputMethodService ims, final SharedPreferences prefs) {
15907cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge        assert ims != null;
16007cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge        if (ims == null) {
16107cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge            Log.w(TAG, "IMS is null; logging is off");
16207cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge        } else {
16307cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge            mFilesDir = ims.getFilesDir();
16407cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge            if (mFilesDir == null || !mFilesDir.exists()) {
16507cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge                Log.w(TAG, "IME storage directory does not exist.");
166d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge            }
167d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge        }
16807cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge        if (prefs != null) {
169223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge            mUUIDString = getUUID(prefs);
1700df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge            if (!prefs.contains(PREF_USABILITY_STUDY_MODE)) {
1710df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge                Editor e = prefs.edit();
1720df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge                e.putBoolean(PREF_USABILITY_STUDY_MODE, DEFAULT_USABILITY_STUDY_MODE);
1730df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge                e.apply();
1740df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge            }
17507cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge            sIsLogging = prefs.getBoolean(PREF_USABILITY_STUDY_MODE, false);
176724bc479f7d796d6ce5d5e200216bea855b818b2Kurt Partridge            prefs.registerOnSharedPreferenceChangeListener(this);
17781dae8d015f63834b2ded44424636b625ece7736Kurt Partridge
17881dae8d015f63834b2ded44424636b625ece7736Kurt Partridge            final long lastCleanupTime = prefs.getLong(PREF_LAST_CLEANUP_TIME, 0L);
17981dae8d015f63834b2ded44424636b625ece7736Kurt Partridge            final long now = System.currentTimeMillis();
18081dae8d015f63834b2ded44424636b625ece7736Kurt Partridge            if (lastCleanupTime + DURATION_BETWEEN_DIR_CLEANUP_IN_MS < now) {
18181dae8d015f63834b2ded44424636b625ece7736Kurt Partridge                final long timeHorizon = now - MAX_LOGFILE_AGE_IN_MS;
18281dae8d015f63834b2ded44424636b625ece7736Kurt Partridge                cleanupLoggingDir(mFilesDir, timeHorizon);
18381dae8d015f63834b2ded44424636b625ece7736Kurt Partridge                Editor e = prefs.edit();
18481dae8d015f63834b2ded44424636b625ece7736Kurt Partridge                e.putLong(PREF_LAST_CLEANUP_TIME, now);
18581dae8d015f63834b2ded44424636b625ece7736Kurt Partridge                e.apply();
18681dae8d015f63834b2ded44424636b625ece7736Kurt Partridge            }
187d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge        }
1884331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge        mInputMethodService = ims;
1890df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge        mPrefs = prefs;
190b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge        mUploadIntent = new Intent(mInputMethodService, UploaderService.class);
191b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge        mUploadPendingIntent = PendingIntent.getService(mInputMethodService, 0, mUploadIntent, 0);
192b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge
193b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge        if (ProductionFlag.IS_EXPERIMENTAL) {
194b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge            scheduleUploadingService(mInputMethodService);
195b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge        }
196b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge    }
197b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge
198b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge    /**
199b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge     * Arrange for the UploaderService to be run on a regular basis.
200b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge     *
201b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge     * Any existing scheduled invocation of UploaderService is removed and rescheduled.  This may
202b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge     * cause problems if this method is called often and frequent updates are required, but since
203b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge     * the user will likely be sleeping at some point, if the interval is less that the expected
204b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge     * sleep duration and this method is not called during that time, the service should be invoked
205b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge     * at some point.
206b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge     */
207b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge    public static void scheduleUploadingService(Context context) {
208b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge        final Intent intent = new Intent(context, UploaderService.class);
209b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge        final PendingIntent pendingIntent = PendingIntent.getService(context, 0, intent, 0);
210b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge        final AlarmManager manager =
211b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge                (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
212b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge        manager.cancel(pendingIntent);
213b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge        manager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
214b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge                UploaderService.RUN_INTERVAL, UploaderService.RUN_INTERVAL, pendingIntent);
215223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge    }
216223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge
21781dae8d015f63834b2ded44424636b625ece7736Kurt Partridge    private void cleanupLoggingDir(final File dir, final long time) {
21881dae8d015f63834b2ded44424636b625ece7736Kurt Partridge        for (File file : dir.listFiles()) {
21981dae8d015f63834b2ded44424636b625ece7736Kurt Partridge            if (file.getName().startsWith(ResearchLogger.FILENAME_PREFIX) &&
22081dae8d015f63834b2ded44424636b625ece7736Kurt Partridge                    file.lastModified() < time) {
22181dae8d015f63834b2ded44424636b625ece7736Kurt Partridge                file.delete();
22281dae8d015f63834b2ded44424636b625ece7736Kurt Partridge            }
22381dae8d015f63834b2ded44424636b625ece7736Kurt Partridge        }
22481dae8d015f63834b2ded44424636b625ece7736Kurt Partridge    }
22581dae8d015f63834b2ded44424636b625ece7736Kurt Partridge
226c3f78c9057a5710898feaf8027659484477e5821Tadashi G. Takaoka    public void mainKeyboardView_onAttachedToWindow(final MainKeyboardView mainKeyboardView) {
227c3f78c9057a5710898feaf8027659484477e5821Tadashi G. Takaoka        mMainKeyboardView = mainKeyboardView;
2284331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge        maybeShowSplashScreen();
2294331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge    }
2304331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge
231c3f78c9057a5710898feaf8027659484477e5821Tadashi G. Takaoka    public void mainKeyboardView_onDetachedFromWindow() {
232c3f78c9057a5710898feaf8027659484477e5821Tadashi G. Takaoka        mMainKeyboardView = null;
233c3f78c9057a5710898feaf8027659484477e5821Tadashi G. Takaoka    }
234c3f78c9057a5710898feaf8027659484477e5821Tadashi G. Takaoka
2354331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge    private boolean hasSeenSplash() {
2364331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge        return mPrefs.getBoolean(PREF_RESEARCH_HAS_SEEN_SPLASH, false);
2374331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge    }
2384331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge
2394331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge    private Dialog mSplashDialog = null;
2404331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge
2414331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge    private void maybeShowSplashScreen() {
2424331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge        if (hasSeenSplash()) {
2434331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge            return;
2444331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge        }
2454331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge        if (mSplashDialog != null && mSplashDialog.isShowing()) {
2464331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge            return;
2474331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge        }
248c3f78c9057a5710898feaf8027659484477e5821Tadashi G. Takaoka        final IBinder windowToken = mMainKeyboardView != null
249c3f78c9057a5710898feaf8027659484477e5821Tadashi G. Takaoka                ? mMainKeyboardView.getWindowToken() : null;
2504331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge        if (windowToken == null) {
2514331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge            return;
2524331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge        }
25325405eafb05d6f2096922b04e5d9ff2ac2bd1a10Kurt Partridge        final AlertDialog.Builder builder = new AlertDialog.Builder(mInputMethodService)
25425405eafb05d6f2096922b04e5d9ff2ac2bd1a10Kurt Partridge                .setTitle(R.string.research_splash_title)
25525405eafb05d6f2096922b04e5d9ff2ac2bd1a10Kurt Partridge                .setMessage(R.string.research_splash_content)
25625405eafb05d6f2096922b04e5d9ff2ac2bd1a10Kurt Partridge                .setPositiveButton(android.R.string.yes,
25725405eafb05d6f2096922b04e5d9ff2ac2bd1a10Kurt Partridge                        new DialogInterface.OnClickListener() {
25825405eafb05d6f2096922b04e5d9ff2ac2bd1a10Kurt Partridge                            @Override
25925405eafb05d6f2096922b04e5d9ff2ac2bd1a10Kurt Partridge                            public void onClick(DialogInterface dialog, int which) {
26025405eafb05d6f2096922b04e5d9ff2ac2bd1a10Kurt Partridge                                onUserLoggingConsent();
26125405eafb05d6f2096922b04e5d9ff2ac2bd1a10Kurt Partridge                                mSplashDialog.dismiss();
26225405eafb05d6f2096922b04e5d9ff2ac2bd1a10Kurt Partridge                            }
26325405eafb05d6f2096922b04e5d9ff2ac2bd1a10Kurt Partridge                })
26425405eafb05d6f2096922b04e5d9ff2ac2bd1a10Kurt Partridge                .setNegativeButton(android.R.string.no,
26525405eafb05d6f2096922b04e5d9ff2ac2bd1a10Kurt Partridge                        new DialogInterface.OnClickListener() {
26625405eafb05d6f2096922b04e5d9ff2ac2bd1a10Kurt Partridge                            @Override
26725405eafb05d6f2096922b04e5d9ff2ac2bd1a10Kurt Partridge                            public void onClick(DialogInterface dialog, int which) {
26825405eafb05d6f2096922b04e5d9ff2ac2bd1a10Kurt Partridge                                final String packageName = mInputMethodService.getPackageName();
26925405eafb05d6f2096922b04e5d9ff2ac2bd1a10Kurt Partridge                                final Uri packageUri = Uri.parse("package:" + packageName);
27025405eafb05d6f2096922b04e5d9ff2ac2bd1a10Kurt Partridge                                final Intent intent = new Intent(Intent.ACTION_UNINSTALL_PACKAGE,
27125405eafb05d6f2096922b04e5d9ff2ac2bd1a10Kurt Partridge                                        packageUri);
27225405eafb05d6f2096922b04e5d9ff2ac2bd1a10Kurt Partridge                                intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
27325405eafb05d6f2096922b04e5d9ff2ac2bd1a10Kurt Partridge                                mInputMethodService.startActivity(intent);
27425405eafb05d6f2096922b04e5d9ff2ac2bd1a10Kurt Partridge                            }
27525405eafb05d6f2096922b04e5d9ff2ac2bd1a10Kurt Partridge                })
27625405eafb05d6f2096922b04e5d9ff2ac2bd1a10Kurt Partridge                .setCancelable(true)
27725405eafb05d6f2096922b04e5d9ff2ac2bd1a10Kurt Partridge                .setOnCancelListener(
27825405eafb05d6f2096922b04e5d9ff2ac2bd1a10Kurt Partridge                        new OnCancelListener() {
27925405eafb05d6f2096922b04e5d9ff2ac2bd1a10Kurt Partridge                            @Override
28025405eafb05d6f2096922b04e5d9ff2ac2bd1a10Kurt Partridge                            public void onCancel(DialogInterface dialog) {
28125405eafb05d6f2096922b04e5d9ff2ac2bd1a10Kurt Partridge                                mInputMethodService.requestHideSelf(0);
28225405eafb05d6f2096922b04e5d9ff2ac2bd1a10Kurt Partridge                            }
28325405eafb05d6f2096922b04e5d9ff2ac2bd1a10Kurt Partridge                });
28425405eafb05d6f2096922b04e5d9ff2ac2bd1a10Kurt Partridge        mSplashDialog = builder.create();
2854331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge        final Window w = mSplashDialog.getWindow();
2864331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge        final WindowManager.LayoutParams lp = w.getAttributes();
2874331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge        lp.token = windowToken;
2884331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge        lp.type = WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
2894331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge        w.setAttributes(lp);
2904331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge        w.addFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
2914331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge        mSplashDialog.show();
2924331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge    }
2934331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge
29425405eafb05d6f2096922b04e5d9ff2ac2bd1a10Kurt Partridge    public void onUserLoggingConsent() {
29525405eafb05d6f2096922b04e5d9ff2ac2bd1a10Kurt Partridge        setLoggingAllowed(true);
2964331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge        if (mPrefs == null) {
2974331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge            return;
2984331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge        }
2994331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge        final Editor e = mPrefs.edit();
3004331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge        e.putBoolean(PREF_RESEARCH_HAS_SEEN_SPLASH, true);
3014331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge        e.apply();
302b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge        restart();
3034331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge    }
3044331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge
305bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge    private void setLoggingAllowed(boolean enableLogging) {
306bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge        if (mPrefs == null) {
307bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge            return;
308bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge        }
309bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge        Editor e = mPrefs.edit();
310bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge        e.putBoolean(PREF_USABILITY_STUDY_MODE, enableLogging);
311bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge        e.apply();
312bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge        sIsLogging = enableLogging;
313bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge    }
314bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge
315223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge    private File createLogFile(File filesDir) {
316223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge        final StringBuilder sb = new StringBuilder();
317223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge        sb.append(FILENAME_PREFIX).append('-');
318223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge        sb.append(mUUIDString).append('-');
319223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge        sb.append(TIMESTAMP_DATEFORMAT.format(new Date()));
320223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge        sb.append(FILENAME_SUFFIX);
321223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge        return new File(filesDir, sb.toString());
32207cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    }
323b8e2ae3bc312269897057fccc34cd736c05bcc90Kurt Partridge
3240a30688080864e59b12196664e7b3cac10d0a8daKurt Partridge    private void checkForEmptyEditor() {
3250a30688080864e59b12196664e7b3cac10d0a8daKurt Partridge        if (mInputMethodService == null) {
3260a30688080864e59b12196664e7b3cac10d0a8daKurt Partridge            return;
3270a30688080864e59b12196664e7b3cac10d0a8daKurt Partridge        }
3280a30688080864e59b12196664e7b3cac10d0a8daKurt Partridge        final InputConnection ic = mInputMethodService.getCurrentInputConnection();
3290a30688080864e59b12196664e7b3cac10d0a8daKurt Partridge        if (ic == null) {
3300a30688080864e59b12196664e7b3cac10d0a8daKurt Partridge            return;
3310a30688080864e59b12196664e7b3cac10d0a8daKurt Partridge        }
3320a30688080864e59b12196664e7b3cac10d0a8daKurt Partridge        final CharSequence textBefore = ic.getTextBeforeCursor(1, 0);
3330a30688080864e59b12196664e7b3cac10d0a8daKurt Partridge        if (!TextUtils.isEmpty(textBefore)) {
3340a30688080864e59b12196664e7b3cac10d0a8daKurt Partridge            mStatistics.setIsEmptyUponStarting(false);
3350a30688080864e59b12196664e7b3cac10d0a8daKurt Partridge            return;
3360a30688080864e59b12196664e7b3cac10d0a8daKurt Partridge        }
3370a30688080864e59b12196664e7b3cac10d0a8daKurt Partridge        final CharSequence textAfter = ic.getTextAfterCursor(1, 0);
3380a30688080864e59b12196664e7b3cac10d0a8daKurt Partridge        if (!TextUtils.isEmpty(textAfter)) {
3390a30688080864e59b12196664e7b3cac10d0a8daKurt Partridge            mStatistics.setIsEmptyUponStarting(false);
3400a30688080864e59b12196664e7b3cac10d0a8daKurt Partridge            return;
3410a30688080864e59b12196664e7b3cac10d0a8daKurt Partridge        }
3420a30688080864e59b12196664e7b3cac10d0a8daKurt Partridge        if (textBefore != null && textAfter != null) {
3430a30688080864e59b12196664e7b3cac10d0a8daKurt Partridge            mStatistics.setIsEmptyUponStarting(true);
3440a30688080864e59b12196664e7b3cac10d0a8daKurt Partridge        }
3450a30688080864e59b12196664e7b3cac10d0a8daKurt Partridge    }
3460a30688080864e59b12196664e7b3cac10d0a8daKurt Partridge
3470df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge    private void start() {
348fe05b881342645f75428cc51849f7326cb76a408Kurt Partridge        if (DEBUG) {
349fe05b881342645f75428cc51849f7326cb76a408Kurt Partridge            Log.d(TAG, "start called");
350fe05b881342645f75428cc51849f7326cb76a408Kurt Partridge        }
3514331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge        maybeShowSplashScreen();
3520df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge        updateSuspendedState();
3530df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge        requestIndicatorRedraw();
3540a30688080864e59b12196664e7b3cac10d0a8daKurt Partridge        mStatistics.reset();
3550a30688080864e59b12196664e7b3cac10d0a8daKurt Partridge        checkForEmptyEditor();
3560df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge        if (!isAllowedToLog()) {
357724bc479f7d796d6ce5d5e200216bea855b818b2Kurt Partridge            // Log.w(TAG, "not in usability mode; not logging");
358724bc479f7d796d6ce5d5e200216bea855b818b2Kurt Partridge            return;
359724bc479f7d796d6ce5d5e200216bea855b818b2Kurt Partridge        }
36007cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge        if (mFilesDir == null || !mFilesDir.exists()) {
36107cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge            Log.w(TAG, "IME storage directory does not exist.  Cannot start logging.");
362223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge            return;
363223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge        }
364bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge        if (mMainLogBuffer == null) {
365bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge            mMainResearchLog = new ResearchLog(createLogFile(mFilesDir));
366bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge            mMainLogBuffer = new MainLogBuffer(mMainResearchLog);
367bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge            mMainLogBuffer.setSuggest(mSuggest);
368bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge        }
369bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge        if (mFeedbackLogBuffer == null) {
370bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge            mFeedbackLog = new ResearchLog(createLogFile(mFilesDir));
371bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge            // LogBuffer is one more than FEEDBACK_WORD_BUFFER_SIZE, because it must also hold
372bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge            // the feedback LogUnit itself.
373bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge            mFeedbackLogBuffer = new LogBuffer(FEEDBACK_WORD_BUFFER_SIZE + 1);
374b8e2ae3bc312269897057fccc34cd736c05bcc90Kurt Partridge        }
375d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge    }
376d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge
3770df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge    /* package */ void stop() {
378fe05b881342645f75428cc51849f7326cb76a408Kurt Partridge        if (DEBUG) {
379fe05b881342645f75428cc51849f7326cb76a408Kurt Partridge            Log.d(TAG, "stop called");
380fe05b881342645f75428cc51849f7326cb76a408Kurt Partridge        }
3810a30688080864e59b12196664e7b3cac10d0a8daKurt Partridge        logStatistics();
382bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge        commitCurrentLogUnit();
3830a30688080864e59b12196664e7b3cac10d0a8daKurt Partridge
384bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge        if (mMainLogBuffer != null) {
385bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge            publishLogBuffer(mMainLogBuffer, mMainResearchLog, false /* isIncludingPrivateData */);
38617114054e91d9172f0432171862a72e832838e96Kurt Partridge            mMainResearchLog.close(null /* callback */);
387bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge            mMainLogBuffer = null;
3880df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge        }
389bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge        if (mFeedbackLogBuffer != null) {
39017114054e91d9172f0432171862a72e832838e96Kurt Partridge            mFeedbackLog.close(null /* callback */);
391bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge            mFeedbackLogBuffer = null;
3920df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge        }
393223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge    }
394223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge
395223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge    public boolean abort() {
396fe05b881342645f75428cc51849f7326cb76a408Kurt Partridge        if (DEBUG) {
397fe05b881342645f75428cc51849f7326cb76a408Kurt Partridge            Log.d(TAG, "abort called");
398fe05b881342645f75428cc51849f7326cb76a408Kurt Partridge        }
399223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge        boolean didAbortMainLog = false;
400bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge        if (mMainLogBuffer != null) {
401bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge            mMainLogBuffer.clear();
40248a7681e064ae259b840f0e757da2d716043d893Kurt Partridge            try {
403bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge                didAbortMainLog = mMainResearchLog.blockingAbort();
40407cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge            } catch (InterruptedException e) {
405bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge                // Don't know whether this succeeded or not.  We assume not; this is reported
406bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge                // to the caller.
40748a7681e064ae259b840f0e757da2d716043d893Kurt Partridge            }
408bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge            mMainLogBuffer = null;
409d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge        }
410bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge        boolean didAbortFeedbackLog = false;
411bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge        if (mFeedbackLogBuffer != null) {
412bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge            mFeedbackLogBuffer.clear();
413724bc479f7d796d6ce5d5e200216bea855b818b2Kurt Partridge            try {
414bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge                didAbortFeedbackLog = mFeedbackLog.blockingAbort();
415223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge            } catch (InterruptedException e) {
416bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge                // Don't know whether this succeeded or not.  We assume not; this is reported
417bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge                // to the caller.
418223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge            }
419bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge            mFeedbackLogBuffer = null;
420223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge        }
421bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge        return didAbortMainLog && didAbortFeedbackLog;
422223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge    }
423223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge
4240df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge    private void restart() {
4250df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge        stop();
4260df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge        start();
4270df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge    }
4280df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge
4290df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge    private long mResumeTime = 0L;
4300df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge    private void suspendLoggingUntil(long time) {
4310df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge        mIsLoggingSuspended = true;
4320df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge        mResumeTime = time;
4330df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge        requestIndicatorRedraw();
4340df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge    }
4350df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge
4360df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge    private void resumeLogging() {
4370df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge        mResumeTime = 0L;
4380df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge        updateSuspendedState();
4390df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge        requestIndicatorRedraw();
4400df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge        if (isAllowedToLog()) {
4410df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge            restart();
4420df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge        }
4430df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge    }
4440df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge
4450df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge    private void updateSuspendedState() {
4460df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge        final long time = System.currentTimeMillis();
4470df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge        if (time > mResumeTime) {
4480df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge            mIsLoggingSuspended = false;
4490df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge        }
4500df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge    }
4510df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge
45207cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    @Override
45307cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
45407cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge        if (key == null || prefs == null) {
45507cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge            return;
456d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge        }
45707cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge        sIsLogging = prefs.getBoolean(PREF_USABILITY_STUDY_MODE, false);
458724bc479f7d796d6ce5d5e200216bea855b818b2Kurt Partridge        if (sIsLogging == false) {
459724bc479f7d796d6ce5d5e200216bea855b818b2Kurt Partridge            abort();
460724bc479f7d796d6ce5d5e200216bea855b818b2Kurt Partridge        }
4610df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge        requestIndicatorRedraw();
462fa0bac9057e2dbb0b1aacc6d748a8bcf12ac1462Kurt Partridge        mPrefs = prefs;
463fa0bac9057e2dbb0b1aacc6d748a8bcf12ac1462Kurt Partridge        prefsChanged(prefs);
464724bc479f7d796d6ce5d5e200216bea855b818b2Kurt Partridge    }
465724bc479f7d796d6ce5d5e200216bea855b818b2Kurt Partridge
46658eb4d9f27595202927150766d198a0bff15efadKurt Partridge    public void onResearchKeySelected(final LatinIME latinIME) {
4673c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge        if (mInFeedbackDialog) {
4683c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge            Toast.makeText(latinIME, R.string.research_please_exit_feedback_form,
4693c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge                    Toast.LENGTH_LONG).show();
4703c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge            return;
4713c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge        }
47258eb4d9f27595202927150766d198a0bff15efadKurt Partridge        presentFeedbackDialog(latinIME);
47358eb4d9f27595202927150766d198a0bff15efadKurt Partridge    }
47458eb4d9f27595202927150766d198a0bff15efadKurt Partridge
47558eb4d9f27595202927150766d198a0bff15efadKurt Partridge    // TODO: currently unreachable.  Remove after being sure no menu is needed.
47658eb4d9f27595202927150766d198a0bff15efadKurt Partridge    /*
47758eb4d9f27595202927150766d198a0bff15efadKurt Partridge    public void presentResearchDialog(final LatinIME latinIME) {
478724bc479f7d796d6ce5d5e200216bea855b818b2Kurt Partridge        final CharSequence title = latinIME.getString(R.string.english_ime_research_log);
4790df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge        final boolean showEnable = mIsLoggingSuspended || !sIsLogging;
480724bc479f7d796d6ce5d5e200216bea855b818b2Kurt Partridge        final CharSequence[] items = new CharSequence[] {
4813c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge                latinIME.getString(R.string.research_feedback_menu_option),
4823c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge                showEnable ? latinIME.getString(R.string.research_enable_session_logging) :
4833c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge                        latinIME.getString(R.string.research_do_not_log_this_session)
484724bc479f7d796d6ce5d5e200216bea855b818b2Kurt Partridge        };
485724bc479f7d796d6ce5d5e200216bea855b818b2Kurt Partridge        final DialogInterface.OnClickListener listener = new DialogInterface.OnClickListener() {
486724bc479f7d796d6ce5d5e200216bea855b818b2Kurt Partridge            @Override
487724bc479f7d796d6ce5d5e200216bea855b818b2Kurt Partridge            public void onClick(DialogInterface di, int position) {
488724bc479f7d796d6ce5d5e200216bea855b818b2Kurt Partridge                di.dismiss();
489724bc479f7d796d6ce5d5e200216bea855b818b2Kurt Partridge                switch (position) {
490724bc479f7d796d6ce5d5e200216bea855b818b2Kurt Partridge                    case 0:
4913c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge                        presentFeedbackDialog(latinIME);
492724bc479f7d796d6ce5d5e200216bea855b818b2Kurt Partridge                        break;
493724bc479f7d796d6ce5d5e200216bea855b818b2Kurt Partridge                    case 1:
49458eb4d9f27595202927150766d198a0bff15efadKurt Partridge                        enableOrDisable(showEnable, latinIME);
495223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge                        break;
496724bc479f7d796d6ce5d5e200216bea855b818b2Kurt Partridge                }
497724bc479f7d796d6ce5d5e200216bea855b818b2Kurt Partridge            }
498223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge
499724bc479f7d796d6ce5d5e200216bea855b818b2Kurt Partridge        };
500724bc479f7d796d6ce5d5e200216bea855b818b2Kurt Partridge        final AlertDialog.Builder builder = new AlertDialog.Builder(latinIME)
501724bc479f7d796d6ce5d5e200216bea855b818b2Kurt Partridge                .setItems(items, listener)
502724bc479f7d796d6ce5d5e200216bea855b818b2Kurt Partridge                .setTitle(title);
503724bc479f7d796d6ce5d5e200216bea855b818b2Kurt Partridge        latinIME.showOptionDialog(builder.create());
504d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge    }
50558eb4d9f27595202927150766d198a0bff15efadKurt Partridge    */
506d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge
5073c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge    private boolean mInFeedbackDialog = false;
5083c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge    public void presentFeedbackDialog(LatinIME latinIME) {
5093c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge        mInFeedbackDialog = true;
5103c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge        latinIME.launchKeyboardedDialogActivity(FeedbackActivity.class);
5113c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge    }
5123c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge
51358eb4d9f27595202927150766d198a0bff15efadKurt Partridge    // TODO: currently unreachable.  Remove after being sure enable/disable is
51458eb4d9f27595202927150766d198a0bff15efadKurt Partridge    // not needed.
51558eb4d9f27595202927150766d198a0bff15efadKurt Partridge    /*
51658eb4d9f27595202927150766d198a0bff15efadKurt Partridge    public void enableOrDisable(final boolean showEnable, final LatinIME latinIME) {
51758eb4d9f27595202927150766d198a0bff15efadKurt Partridge        if (showEnable) {
51858eb4d9f27595202927150766d198a0bff15efadKurt Partridge            if (!sIsLogging) {
51958eb4d9f27595202927150766d198a0bff15efadKurt Partridge                setLoggingAllowed(true);
52058eb4d9f27595202927150766d198a0bff15efadKurt Partridge            }
52158eb4d9f27595202927150766d198a0bff15efadKurt Partridge            resumeLogging();
52258eb4d9f27595202927150766d198a0bff15efadKurt Partridge            Toast.makeText(latinIME,
52358eb4d9f27595202927150766d198a0bff15efadKurt Partridge                    R.string.research_notify_session_logging_enabled,
52458eb4d9f27595202927150766d198a0bff15efadKurt Partridge                    Toast.LENGTH_LONG).show();
52558eb4d9f27595202927150766d198a0bff15efadKurt Partridge        } else {
52658eb4d9f27595202927150766d198a0bff15efadKurt Partridge            Toast toast = Toast.makeText(latinIME,
52758eb4d9f27595202927150766d198a0bff15efadKurt Partridge                    R.string.research_notify_session_log_deleting,
52858eb4d9f27595202927150766d198a0bff15efadKurt Partridge                    Toast.LENGTH_LONG);
52958eb4d9f27595202927150766d198a0bff15efadKurt Partridge            toast.show();
53058eb4d9f27595202927150766d198a0bff15efadKurt Partridge            boolean isLogDeleted = abort();
53158eb4d9f27595202927150766d198a0bff15efadKurt Partridge            final long currentTime = System.currentTimeMillis();
53258eb4d9f27595202927150766d198a0bff15efadKurt Partridge            final long resumeTime = currentTime + 1000 * 60 *
53358eb4d9f27595202927150766d198a0bff15efadKurt Partridge                    SUSPEND_DURATION_IN_MINUTES;
53458eb4d9f27595202927150766d198a0bff15efadKurt Partridge            suspendLoggingUntil(resumeTime);
53558eb4d9f27595202927150766d198a0bff15efadKurt Partridge            toast.cancel();
53658eb4d9f27595202927150766d198a0bff15efadKurt Partridge            Toast.makeText(latinIME, R.string.research_notify_logging_suspended,
53758eb4d9f27595202927150766d198a0bff15efadKurt Partridge                    Toast.LENGTH_LONG).show();
53858eb4d9f27595202927150766d198a0bff15efadKurt Partridge        }
53958eb4d9f27595202927150766d198a0bff15efadKurt Partridge    }
54058eb4d9f27595202927150766d198a0bff15efadKurt Partridge    */
54158eb4d9f27595202927150766d198a0bff15efadKurt Partridge
542bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge    private static final String[] EVENTKEYS_FEEDBACK = {
543bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge        "UserTimestamp", "contents"
544bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge    };
5453c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge    public void sendFeedback(final String feedbackContents, final boolean includeHistory) {
546bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge        if (mFeedbackLogBuffer == null) {
547bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge            return;
548bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge        }
549b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge        if (includeHistory) {
550b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge            commitCurrentLogUnit();
551b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge        } else {
552bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge            mFeedbackLogBuffer.clear();
5533c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge        }
554bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge        final LogUnit feedbackLogUnit = new LogUnit();
555bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge        final Object[] values = {
556bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge            feedbackContents
557bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge        };
558bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge        feedbackLogUnit.addLogStatement(EVENTKEYS_FEEDBACK, values,
559bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge                false /* isPotentiallyPrivate */);
560bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge        mFeedbackLogBuffer.shiftIn(feedbackLogUnit);
561bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge        publishLogBuffer(mFeedbackLogBuffer, mFeedbackLog, true /* isIncludingPrivateData */);
56217114054e91d9172f0432171862a72e832838e96Kurt Partridge        mFeedbackLog.close(new Runnable() {
56317114054e91d9172f0432171862a72e832838e96Kurt Partridge            @Override
56417114054e91d9172f0432171862a72e832838e96Kurt Partridge            public void run() {
56517114054e91d9172f0432171862a72e832838e96Kurt Partridge                uploadNow();
56617114054e91d9172f0432171862a72e832838e96Kurt Partridge            }
56717114054e91d9172f0432171862a72e832838e96Kurt Partridge        });
568bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge        mFeedbackLog = new ResearchLog(createLogFile(mFilesDir));
5693c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge    }
5703c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge
571b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge    public void uploadNow() {
572fe05b881342645f75428cc51849f7326cb76a408Kurt Partridge        if (DEBUG) {
573fe05b881342645f75428cc51849f7326cb76a408Kurt Partridge            Log.d(TAG, "calling uploadNow()");
574fe05b881342645f75428cc51849f7326cb76a408Kurt Partridge        }
575b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge        mInputMethodService.startService(mUploadIntent);
576b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge    }
577b5ace11a2e7b88e6b89b6297d5d540f351e48a4aKurt Partridge
5783c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge    public void onLeavingSendFeedbackDialog() {
5793c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge        mInFeedbackDialog = false;
5803c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge    }
5813c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge
5826080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge    public void initSuggest(Suggest suggest) {
5836080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge        mSuggest = suggest;
584bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge        if (mMainLogBuffer != null) {
585bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge            mMainLogBuffer.setSuggest(mSuggest);
586bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge        }
5876080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge    }
5886080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge
5891cef91e4818790ea5419a6ad9ff6e36ac535c763Kurt Partridge    private void setIsPasswordView(boolean isPasswordView) {
5901cef91e4818790ea5419a6ad9ff6e36ac535c763Kurt Partridge        mIsPasswordView = isPasswordView;
5911cef91e4818790ea5419a6ad9ff6e36ac535c763Kurt Partridge    }
5921cef91e4818790ea5419a6ad9ff6e36ac535c763Kurt Partridge
5931cef91e4818790ea5419a6ad9ff6e36ac535c763Kurt Partridge    private boolean isAllowedToLog() {
594fe05b881342645f75428cc51849f7326cb76a408Kurt Partridge        if (DEBUG) {
595fe05b881342645f75428cc51849f7326cb76a408Kurt Partridge            Log.d(TAG, "iatl: " +
596fe05b881342645f75428cc51849f7326cb76a408Kurt Partridge                "mipw=" + mIsPasswordView +
597fe05b881342645f75428cc51849f7326cb76a408Kurt Partridge                ", mils=" + mIsLoggingSuspended +
598fe05b881342645f75428cc51849f7326cb76a408Kurt Partridge                ", sil=" + sIsLogging +
599fe05b881342645f75428cc51849f7326cb76a408Kurt Partridge                ", mInFeedbackDialog=" + mInFeedbackDialog);
600fe05b881342645f75428cc51849f7326cb76a408Kurt Partridge        }
601bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge        return !mIsPasswordView && !mIsLoggingSuspended && sIsLogging && !mInFeedbackDialog;
602223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge    }
603223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge
604223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge    public void requestIndicatorRedraw() {
6054fa6e5726041a22db4f15d99521ea06419401946Kurt Partridge        if (!IS_SHOWING_INDICATOR) {
6064fa6e5726041a22db4f15d99521ea06419401946Kurt Partridge            return;
6074fa6e5726041a22db4f15d99521ea06419401946Kurt Partridge        }
608c3f78c9057a5710898feaf8027659484477e5821Tadashi G. Takaoka        if (mMainKeyboardView == null) {
6094fa6e5726041a22db4f15d99521ea06419401946Kurt Partridge            return;
6104fa6e5726041a22db4f15d99521ea06419401946Kurt Partridge        }
611c3f78c9057a5710898feaf8027659484477e5821Tadashi G. Takaoka        mMainKeyboardView.invalidateAllKeys();
6124fa6e5726041a22db4f15d99521ea06419401946Kurt Partridge    }
6134fa6e5726041a22db4f15d99521ea06419401946Kurt Partridge
6144fa6e5726041a22db4f15d99521ea06419401946Kurt Partridge
6154fa6e5726041a22db4f15d99521ea06419401946Kurt Partridge    public void paintIndicator(KeyboardView view, Paint paint, Canvas canvas, int width,
6164fa6e5726041a22db4f15d99521ea06419401946Kurt Partridge            int height) {
6174fa6e5726041a22db4f15d99521ea06419401946Kurt Partridge        // TODO: Reimplement using a keyboard background image specific to the ResearchLogger
6184fa6e5726041a22db4f15d99521ea06419401946Kurt Partridge        // and remove this method.
619c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka        // The check for MainKeyboardView ensures that a red border is only placed around
6204fa6e5726041a22db4f15d99521ea06419401946Kurt Partridge        // the main keyboard, not every keyboard.
621c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka        if (IS_SHOWING_INDICATOR && isAllowedToLog() && view instanceof MainKeyboardView) {
6224fa6e5726041a22db4f15d99521ea06419401946Kurt Partridge            final int savedColor = paint.getColor();
6234fa6e5726041a22db4f15d99521ea06419401946Kurt Partridge            paint.setColor(Color.RED);
6244fa6e5726041a22db4f15d99521ea06419401946Kurt Partridge            final Style savedStyle = paint.getStyle();
6254fa6e5726041a22db4f15d99521ea06419401946Kurt Partridge            paint.setStyle(Style.STROKE);
6264fa6e5726041a22db4f15d99521ea06419401946Kurt Partridge            final float savedStrokeWidth = paint.getStrokeWidth();
6274fa6e5726041a22db4f15d99521ea06419401946Kurt Partridge            if (IS_SHOWING_INDICATOR_CLEARLY) {
6284fa6e5726041a22db4f15d99521ea06419401946Kurt Partridge                paint.setStrokeWidth(5);
6294fa6e5726041a22db4f15d99521ea06419401946Kurt Partridge                canvas.drawRect(0, 0, width, height, paint);
6304fa6e5726041a22db4f15d99521ea06419401946Kurt Partridge            } else {
6314fa6e5726041a22db4f15d99521ea06419401946Kurt Partridge                // Put a tiny red dot on the screen so a knowledgeable user can check whether
6324fa6e5726041a22db4f15d99521ea06419401946Kurt Partridge                // it is enabled.  The dot is actually a zero-width, zero-height rectangle,
6334fa6e5726041a22db4f15d99521ea06419401946Kurt Partridge                // placed at the lower-right corner of the canvas, painted with a non-zero border
6344fa6e5726041a22db4f15d99521ea06419401946Kurt Partridge                // width.
6354fa6e5726041a22db4f15d99521ea06419401946Kurt Partridge                paint.setStrokeWidth(3);
6364fa6e5726041a22db4f15d99521ea06419401946Kurt Partridge                canvas.drawRect(width, height, width, height, paint);
6370df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge            }
6384fa6e5726041a22db4f15d99521ea06419401946Kurt Partridge            paint.setColor(savedColor);
6394fa6e5726041a22db4f15d99521ea06419401946Kurt Partridge            paint.setStyle(savedStyle);
6404fa6e5726041a22db4f15d99521ea06419401946Kurt Partridge            paint.setStrokeWidth(savedStrokeWidth);
641223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge        }
6421cef91e4818790ea5419a6ad9ff6e36ac535c763Kurt Partridge    }
6431cef91e4818790ea5419a6ad9ff6e36ac535c763Kurt Partridge
64407cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    private static final Object[] EVENTKEYS_NULLVALUES = {};
645d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge
64607cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    /**
6476080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge     * Buffer a research log event, flagging it as privacy-sensitive.
64807cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge     *
6496080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge     * This event contains potentially private information.  If the word that this event is a part
6506080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge     * of is determined to be privacy-sensitive, then this event should not be included in the
6516080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge     * output log.  The system waits to output until the containing word is known.
65207cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge     *
65307cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge     * @param keys an array containing a descriptive name for the event, followed by the keys
65407cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge     * @param values an array of values, either a String or Number.  length should be one
65507cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge     * less than the keys array
65607cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge     */
6576080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge    private synchronized void enqueuePotentiallyPrivateEvent(final String[] keys,
6586080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge            final Object[] values) {
65907cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge        assert values.length + 1 == keys.length;
660223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge        if (isAllowedToLog()) {
661bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge            mCurrentLogUnit.addLogStatement(keys, values, true /* isPotentiallyPrivate */);
662223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge        }
6636080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge    }
6646080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge
665bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge    private void setCurrentLogUnitContainsDigitFlag() {
666bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge        mCurrentLogUnit.setContainsDigit();
667bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge    }
668bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge
6696080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge    /**
6706080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge     * Buffer a research log event, flaggint it as not privacy-sensitive.
6716080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge     *
6726080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge     * This event contains no potentially private information.  Even if the word that this event
6736080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge     * is privacy-sensitive, this event can still safely be sent to the output log.  The system
6746080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge     * waits until the containing word is known so that this event can be written in the proper
6756080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge     * temporal order with other events that may be privacy sensitive.
6766080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge     *
6776080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge     * @param keys an array containing a descriptive name for the event, followed by the keys
6786080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge     * @param values an array of values, either a String or Number.  length should be one
6796080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge     * less than the keys array
6806080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge     */
6816080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge    private synchronized void enqueueEvent(final String[] keys, final Object[] values) {
6826080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge        assert values.length + 1 == keys.length;
683223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge        if (isAllowedToLog()) {
684bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge            mCurrentLogUnit.addLogStatement(keys, values, false /* isPotentiallyPrivate */);
685223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge        }
6866080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge    }
6876080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge
688bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge    /* package for test */ void commitCurrentLogUnit() {
689fe05b881342645f75428cc51849f7326cb76a408Kurt Partridge        if (DEBUG) {
690fe05b881342645f75428cc51849f7326cb76a408Kurt Partridge            Log.d(TAG, "commitCurrentLogUnit");
691fe05b881342645f75428cc51849f7326cb76a408Kurt Partridge        }
692bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge        if (!mCurrentLogUnit.isEmpty()) {
693bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge            if (mMainLogBuffer != null) {
694bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge                mMainLogBuffer.shiftIn(mCurrentLogUnit);
695bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge                if (mMainLogBuffer.isSafeToLog() && mMainResearchLog != null) {
696bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge                    publishLogBuffer(mMainLogBuffer, mMainResearchLog,
697bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge                            true /* isIncludingPrivateData */);
698bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge                    mMainLogBuffer.resetWordCounter();
699bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge                }
700bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge            }
701bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge            if (mFeedbackLogBuffer != null) {
702bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge                mFeedbackLogBuffer.shiftIn(mCurrentLogUnit);
703e961188e9fd4f4365c6c745c8d3d838dd7dfe6a0Kurt Partridge            }
704bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge            mCurrentLogUnit = new LogUnit();
705bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge            Log.d(TAG, "commitCurrentLogUnit");
706e961188e9fd4f4365c6c745c8d3d838dd7dfe6a0Kurt Partridge        }
707bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge    }
708e961188e9fd4f4365c6c745c8d3d838dd7dfe6a0Kurt Partridge
709bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge    /* package for test */ void publishLogBuffer(final LogBuffer logBuffer,
710bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge            final ResearchLog researchLog, final boolean isIncludingPrivateData) {
711bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge        LogUnit logUnit;
712bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge        while ((logUnit = logBuffer.shiftOut()) != null) {
713bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge            researchLog.publish(logUnit, isIncludingPrivateData);
714e961188e9fd4f4365c6c745c8d3d838dd7dfe6a0Kurt Partridge        }
715e961188e9fd4f4365c6c745c8d3d838dd7dfe6a0Kurt Partridge    }
716e961188e9fd4f4365c6c745c8d3d838dd7dfe6a0Kurt Partridge
717bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge    private boolean hasOnlyLetters(final String word) {
71833d9f9b6dbafba97d5f46b021727b9d797906baaKurt Partridge        final int length = word.length();
71933d9f9b6dbafba97d5f46b021727b9d797906baaKurt Partridge        for (int i = 0; i < length; i = word.offsetByCodePoints(i, 1)) {
720bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge            final int codePoint = word.codePointAt(i);
721bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge            if (!Character.isLetter(codePoint)) {
722bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge                return false;
72333d9f9b6dbafba97d5f46b021727b9d797906baaKurt Partridge            }
724e961188e9fd4f4365c6c745c8d3d838dd7dfe6a0Kurt Partridge        }
725bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge        return true;
726e961188e9fd4f4365c6c745c8d3d838dd7dfe6a0Kurt Partridge    }
727e961188e9fd4f4365c6c745c8d3d838dd7dfe6a0Kurt Partridge
728bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge    private void onWordComplete(final String word) {
729bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge        Log.d(TAG, "onWordComplete: " + word);
730bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge        if (word != null && word.length() > 0 && hasOnlyLetters(word)) {
731bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge            mCurrentLogUnit.setWord(word);
732bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge            mStatistics.recordWordEntered();
73307cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge        }
734bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge        commitCurrentLogUnit();
73507cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    }
73607cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge
737a696781c2b18d8002275aa89e07fa7379661d025Kurt Partridge    private static int scrubDigitFromCodePoint(int codePoint) {
738a696781c2b18d8002275aa89e07fa7379661d025Kurt Partridge        return Character.isDigit(codePoint) ? DIGIT_REPLACEMENT_CODEPOINT : codePoint;
739a696781c2b18d8002275aa89e07fa7379661d025Kurt Partridge    }
740a696781c2b18d8002275aa89e07fa7379661d025Kurt Partridge
741a696781c2b18d8002275aa89e07fa7379661d025Kurt Partridge    /* package for test */ static String scrubDigitsFromString(String s) {
742a696781c2b18d8002275aa89e07fa7379661d025Kurt Partridge        StringBuilder sb = null;
743a696781c2b18d8002275aa89e07fa7379661d025Kurt Partridge        final int length = s.length();
744a696781c2b18d8002275aa89e07fa7379661d025Kurt Partridge        for (int i = 0; i < length; i = s.offsetByCodePoints(i, 1)) {
74533d9f9b6dbafba97d5f46b021727b9d797906baaKurt Partridge            final int codePoint = Character.codePointAt(s, i);
746a696781c2b18d8002275aa89e07fa7379661d025Kurt Partridge            if (Character.isDigit(codePoint)) {
747a696781c2b18d8002275aa89e07fa7379661d025Kurt Partridge                if (sb == null) {
748a696781c2b18d8002275aa89e07fa7379661d025Kurt Partridge                    sb = new StringBuilder(length);
749a696781c2b18d8002275aa89e07fa7379661d025Kurt Partridge                    sb.append(s.substring(0, i));
750a696781c2b18d8002275aa89e07fa7379661d025Kurt Partridge                }
751a696781c2b18d8002275aa89e07fa7379661d025Kurt Partridge                sb.appendCodePoint(DIGIT_REPLACEMENT_CODEPOINT);
752a696781c2b18d8002275aa89e07fa7379661d025Kurt Partridge            } else {
753a696781c2b18d8002275aa89e07fa7379661d025Kurt Partridge                if (sb != null) {
754a696781c2b18d8002275aa89e07fa7379661d025Kurt Partridge                    sb.appendCodePoint(codePoint);
755a696781c2b18d8002275aa89e07fa7379661d025Kurt Partridge                }
756a696781c2b18d8002275aa89e07fa7379661d025Kurt Partridge            }
757a696781c2b18d8002275aa89e07fa7379661d025Kurt Partridge        }
758a696781c2b18d8002275aa89e07fa7379661d025Kurt Partridge        if (sb == null) {
759a696781c2b18d8002275aa89e07fa7379661d025Kurt Partridge            return s;
760a696781c2b18d8002275aa89e07fa7379661d025Kurt Partridge        } else {
761a696781c2b18d8002275aa89e07fa7379661d025Kurt Partridge            return sb.toString();
762a696781c2b18d8002275aa89e07fa7379661d025Kurt Partridge        }
763a696781c2b18d8002275aa89e07fa7379661d025Kurt Partridge    }
764a696781c2b18d8002275aa89e07fa7379661d025Kurt Partridge
7650df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge    private static String getUUID(final SharedPreferences prefs) {
7660df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge        String uuidString = prefs.getString(PREF_RESEARCH_LOGGER_UUID_STRING, null);
7670df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge        if (null == uuidString) {
7680df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge            UUID uuid = UUID.randomUUID();
7690df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge            uuidString = uuid.toString();
7700df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge            Editor editor = prefs.edit();
7710df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge            editor.putString(PREF_RESEARCH_LOGGER_UUID_STRING, uuidString);
7720df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge            editor.apply();
7730df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge        }
7740df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge        return uuidString;
7750df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge    }
7760df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge
7776080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge    private String scrubWord(String word) {
7786080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge        if (mDictionary == null) {
7796080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge            return WORD_REPLACEMENT_STRING;
7806080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge        }
7816080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge        if (mDictionary.isValidWord(word)) {
7826080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge            return word;
7836080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge        }
7846080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge        return WORD_REPLACEMENT_STRING;
7856080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge    }
7866080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge
7870df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge    private static final String[] EVENTKEYS_LATINIME_ONSTARTINPUTVIEWINTERNAL = {
7880df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge        "LatinIMEOnStartInputViewInternal", "uuid", "packageName", "inputType", "imeOptions",
7890df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge        "fieldId", "display", "model", "prefs", "versionCode", "versionName", "outputFormatVersion"
7900df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge    };
7910df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge    public static void latinIME_onStartInputViewInternal(final EditorInfo editorInfo,
7920df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge            final SharedPreferences prefs) {
7930df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge        final ResearchLogger researchLogger = getInstance();
7940df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge        researchLogger.start();
7950df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge        if (editorInfo != null) {
7964331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge            final Context context = researchLogger.mInputMethodService;
7970df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge            try {
7980df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge                final PackageInfo packageInfo;
7990df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge                packageInfo = context.getPackageManager().getPackageInfo(context.getPackageName(),
8000df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge                        0);
8010df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge                final Integer versionCode = packageInfo.versionCode;
8020df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge                final String versionName = packageInfo.versionName;
8030df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge                final Object[] values = {
8040df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge                        researchLogger.mUUIDString, editorInfo.packageName,
8050df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge                        Integer.toHexString(editorInfo.inputType),
8060df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge                        Integer.toHexString(editorInfo.imeOptions), editorInfo.fieldId,
8070df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge                        Build.DISPLAY, Build.MODEL, prefs, versionCode, versionName,
8080df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge                        OUTPUT_FORMAT_VERSION
8090df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge                };
8100df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge                researchLogger.enqueueEvent(EVENTKEYS_LATINIME_ONSTARTINPUTVIEWINTERNAL, values);
8110df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge            } catch (NameNotFoundException e) {
8120df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge                e.printStackTrace();
8130df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge            }
8140df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge        }
8150df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge    }
8160df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge
8170df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge    public void latinIME_onFinishInputInternal() {
8180df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge        stop();
8190df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge    }
8200df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge
8213c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge    private static final String[] EVENTKEYS_USER_FEEDBACK = {
8223c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge        "UserFeedback", "FeedbackContents"
8233c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge    };
8243c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge
825fa0bac9057e2dbb0b1aacc6d748a8bcf12ac1462Kurt Partridge    private static final String[] EVENTKEYS_PREFS_CHANGED = {
826fa0bac9057e2dbb0b1aacc6d748a8bcf12ac1462Kurt Partridge        "PrefsChanged", "prefs"
827fa0bac9057e2dbb0b1aacc6d748a8bcf12ac1462Kurt Partridge    };
828fa0bac9057e2dbb0b1aacc6d748a8bcf12ac1462Kurt Partridge    public static void prefsChanged(final SharedPreferences prefs) {
829fa0bac9057e2dbb0b1aacc6d748a8bcf12ac1462Kurt Partridge        final ResearchLogger researchLogger = getInstance();
830fa0bac9057e2dbb0b1aacc6d748a8bcf12ac1462Kurt Partridge        final Object[] values = {
831fa0bac9057e2dbb0b1aacc6d748a8bcf12ac1462Kurt Partridge            prefs
832fa0bac9057e2dbb0b1aacc6d748a8bcf12ac1462Kurt Partridge        };
833fa0bac9057e2dbb0b1aacc6d748a8bcf12ac1462Kurt Partridge        researchLogger.enqueueEvent(EVENTKEYS_PREFS_CHANGED, values);
834fa0bac9057e2dbb0b1aacc6d748a8bcf12ac1462Kurt Partridge    }
835fa0bac9057e2dbb0b1aacc6d748a8bcf12ac1462Kurt Partridge
8360df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge    // Regular logging methods
8370df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge
838c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka    private static final String[] EVENTKEYS_MAINKEYBOARDVIEW_PROCESSMOTIONEVENT = {
839c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka        "MainKeyboardViewProcessMotionEvent", "action", "eventTime", "id", "x", "y", "size",
84007cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge        "pressure"
84107cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    };
842c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka    public static void mainKeyboardView_processMotionEvent(final MotionEvent me, final int action,
84307cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge            final long eventTime, final int index, final int id, final int x, final int y) {
84407cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge        if (me != null) {
84507cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge            final String actionString;
84607cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge            switch (action) {
84707cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge                case MotionEvent.ACTION_CANCEL: actionString = "CANCEL"; break;
84807cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge                case MotionEvent.ACTION_UP: actionString = "UP"; break;
84907cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge                case MotionEvent.ACTION_DOWN: actionString = "DOWN"; break;
85007cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge                case MotionEvent.ACTION_POINTER_UP: actionString = "POINTER_UP"; break;
85107cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge                case MotionEvent.ACTION_POINTER_DOWN: actionString = "POINTER_DOWN"; break;
85207cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge                case MotionEvent.ACTION_MOVE: actionString = "MOVE"; break;
85307cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge                case MotionEvent.ACTION_OUTSIDE: actionString = "OUTSIDE"; break;
85407cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge                default: actionString = "ACTION_" + action; break;
855d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge            }
85607cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge            final float size = me.getSize(index);
85707cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge            final float pressure = me.getPressure(index);
85807cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge            final Object[] values = {
85907cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge                actionString, eventTime, id, x, y, size, pressure
86007cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge            };
8616080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge            getInstance().enqueuePotentiallyPrivateEvent(
862c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka                    EVENTKEYS_MAINKEYBOARDVIEW_PROCESSMOTIONEVENT, values);
86307cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge        }
864d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge    }
865d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge
86607cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    private static final String[] EVENTKEYS_LATINIME_ONCODEINPUT = {
867f739119f3ff54d7c37b67b873373b236a45e47e4Kurt Partridge        "LatinIMEOnCodeInput", "code", "x", "y"
86807cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    };
86907cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    public static void latinIME_onCodeInput(final int code, final int x, final int y) {
870bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge        final long time = SystemClock.uptimeMillis();
871bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge        final ResearchLogger researchLogger = getInstance();
87207cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge        final Object[] values = {
873a696781c2b18d8002275aa89e07fa7379661d025Kurt Partridge            Keyboard.printableCode(scrubDigitFromCodePoint(code)), x, y
87407cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge        };
8750a30688080864e59b12196664e7b3cac10d0a8daKurt Partridge        researchLogger.enqueuePotentiallyPrivateEvent(EVENTKEYS_LATINIME_ONCODEINPUT, values);
876bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge        if (Character.isDigit(code)) {
877bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge            researchLogger.setCurrentLogUnitContainsDigitFlag();
878bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge        }
879bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge        researchLogger.mStatistics.recordChar(code, time);
880d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge    }
881d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge
88207cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    private static final String[] EVENTKEYS_LATINIME_ONDISPLAYCOMPLETIONS = {
883f739119f3ff54d7c37b67b873373b236a45e47e4Kurt Partridge        "LatinIMEOnDisplayCompletions", "applicationSpecifiedCompletions"
88407cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    };
8859bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge    public static void latinIME_onDisplayCompletions(
8869bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge            final CompletionInfo[] applicationSpecifiedCompletions) {
88707cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge        final Object[] values = {
88807cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge            applicationSpecifiedCompletions
88907cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge        };
8906080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge        getInstance().enqueuePotentiallyPrivateEvent(EVENTKEYS_LATINIME_ONDISPLAYCOMPLETIONS,
8916080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge                values);
8929bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge    }
8939bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge
8946b966160ac8570271547bf63217efa5e228d4accKurt Partridge    public static boolean getAndClearLatinIMEExpectingUpdateSelection() {
89507cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge        boolean returnValue = sLatinIMEExpectingUpdateSelection;
89607cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge        sLatinIMEExpectingUpdateSelection = false;
897d67a248de45a698d1009757c9f4e750c77bf35f1Kurt Partridge        return returnValue;
898d67a248de45a698d1009757c9f4e750c77bf35f1Kurt Partridge    }
899d67a248de45a698d1009757c9f4e750c77bf35f1Kurt Partridge
90007cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    private static final String[] EVENTKEYS_LATINIME_ONWINDOWHIDDEN = {
901f739119f3ff54d7c37b67b873373b236a45e47e4Kurt Partridge        "LatinIMEOnWindowHidden", "isTextTruncated", "text"
90207cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    };
903d67a248de45a698d1009757c9f4e750c77bf35f1Kurt Partridge    public static void latinIME_onWindowHidden(final int savedSelectionStart,
904d67a248de45a698d1009757c9f4e750c77bf35f1Kurt Partridge            final int savedSelectionEnd, final InputConnection ic) {
90507cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge        if (ic != null) {
90694e7f4bef970431f509a806d1b92b19fc3b5ce7dKurt Partridge            // Capture the TextView contents.  This will trigger onUpdateSelection(), so we
90794e7f4bef970431f509a806d1b92b19fc3b5ce7dKurt Partridge            // set sLatinIMEExpectingUpdateSelection so that when onUpdateSelection() is called,
90894e7f4bef970431f509a806d1b92b19fc3b5ce7dKurt Partridge            // it can tell that it was generated by the logging code, and not by the user, and
90994e7f4bef970431f509a806d1b92b19fc3b5ce7dKurt Partridge            // therefore keep user-visible state as is.
91007cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge            ic.beginBatchEdit();
91107cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge            ic.performContextMenuAction(android.R.id.selectAll);
91207cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge            CharSequence charSequence = ic.getSelectedText(0);
91307cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge            ic.setSelection(savedSelectionStart, savedSelectionEnd);
91407cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge            ic.endBatchEdit();
91507cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge            sLatinIMEExpectingUpdateSelection = true;
9166080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge            final Object[] values = new Object[2];
9176080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge            if (OUTPUT_ENTIRE_BUFFER) {
9186080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge                if (TextUtils.isEmpty(charSequence)) {
91907cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge                    values[0] = false;
9206080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge                    values[1] = "";
9216080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge                } else {
9226080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge                    if (charSequence.length() > MAX_INPUTVIEW_LENGTH_TO_CAPTURE) {
9236080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge                        int length = MAX_INPUTVIEW_LENGTH_TO_CAPTURE;
9246080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge                        // do not cut in the middle of a supplementary character
9256080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge                        final char c = charSequence.charAt(length - 1);
9266080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge                        if (Character.isHighSurrogate(c)) {
9276080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge                            length--;
9286080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge                        }
9296080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge                        final CharSequence truncatedCharSequence = charSequence.subSequence(0,
9306080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge                                length);
9316080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge                        values[0] = true;
9326080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge                        values[1] = truncatedCharSequence.toString();
9336080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge                    } else {
9346080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge                        values[0] = false;
9356080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge                        values[1] = charSequence.toString();
9366080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge                    }
937d67a248de45a698d1009757c9f4e750c77bf35f1Kurt Partridge                }
9386080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge            } else {
9396080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge                values[0] = true;
9406080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge                values[1] = "";
941d67a248de45a698d1009757c9f4e750c77bf35f1Kurt Partridge            }
9426080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge            final ResearchLogger researchLogger = getInstance();
9436080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge            researchLogger.enqueueEvent(EVENTKEYS_LATINIME_ONWINDOWHIDDEN, values);
944bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge            researchLogger.commitCurrentLogUnit();
9454331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge            getInstance().stop();
946d67a248de45a698d1009757c9f4e750c77bf35f1Kurt Partridge        }
947d67a248de45a698d1009757c9f4e750c77bf35f1Kurt Partridge    }
948d67a248de45a698d1009757c9f4e750c77bf35f1Kurt Partridge
94907cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    private static final String[] EVENTKEYS_LATINIME_ONUPDATESELECTION = {
950f739119f3ff54d7c37b67b873373b236a45e47e4Kurt Partridge        "LatinIMEOnUpdateSelection", "lastSelectionStart", "lastSelectionEnd", "oldSelStart",
95107cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge        "oldSelEnd", "newSelStart", "newSelEnd", "composingSpanStart", "composingSpanEnd",
95286fcadde5d1ca69e4d93dc7cf5e72c763a32ac84Kurt Partridge        "expectingUpdateSelection", "expectingUpdateSelectionFromLogger", "context"
95307cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    };
9549bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge    public static void latinIME_onUpdateSelection(final int lastSelectionStart,
9559bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge            final int lastSelectionEnd, final int oldSelStart, final int oldSelEnd,
9569bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge            final int newSelStart, final int newSelEnd, final int composingSpanStart,
957d67a248de45a698d1009757c9f4e750c77bf35f1Kurt Partridge            final int composingSpanEnd, final boolean expectingUpdateSelection,
95802308bec632a5df23325c916bffec5def16b22b4Jean Chalard            final boolean expectingUpdateSelectionFromLogger,
95902308bec632a5df23325c916bffec5def16b22b4Jean Chalard            final RichInputConnection connection) {
96065fc909e13134d34e87d5d75ff4cdd46fb9cebf0Kurt Partridge        String word = "";
96165fc909e13134d34e87d5d75ff4cdd46fb9cebf0Kurt Partridge        if (connection != null) {
96265fc909e13134d34e87d5d75ff4cdd46fb9cebf0Kurt Partridge            Range range = connection.getWordRangeAtCursor(WHITESPACE_SEPARATORS, 1);
96365fc909e13134d34e87d5d75ff4cdd46fb9cebf0Kurt Partridge            if (range != null) {
96465fc909e13134d34e87d5d75ff4cdd46fb9cebf0Kurt Partridge                word = range.mWord;
96565fc909e13134d34e87d5d75ff4cdd46fb9cebf0Kurt Partridge            }
96665fc909e13134d34e87d5d75ff4cdd46fb9cebf0Kurt Partridge        }
9676080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge        final ResearchLogger researchLogger = getInstance();
9686080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge        final String scrubbedWord = researchLogger.scrubWord(word);
96907cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge        final Object[] values = {
97007cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge            lastSelectionStart, lastSelectionEnd, oldSelStart, oldSelEnd, newSelStart,
97107cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge            newSelEnd, composingSpanStart, composingSpanEnd, expectingUpdateSelection,
9726080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge            expectingUpdateSelectionFromLogger, scrubbedWord
97307cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge        };
9746080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge        researchLogger.enqueuePotentiallyPrivateEvent(EVENTKEYS_LATINIME_ONUPDATESELECTION, values);
97507cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    }
97607cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge
97707cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    private static final String[] EVENTKEYS_LATINIME_PICKSUGGESTIONMANUALLY = {
978f739119f3ff54d7c37b67b873373b236a45e47e4Kurt Partridge        "LatinIMEPickSuggestionManually", "replacedWord", "index", "suggestion", "x", "y"
97907cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    };
9809bfb6202154e06d7156f2f374dd9359f1be4eb68Kurt Partridge    public static void latinIME_pickSuggestionManually(final String replacedWord,
9816785b9072762e15bb49657ce7b7d228dab76e44aTadashi G. Takaoka            final int index, CharSequence suggestion) {
98207cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge        final Object[] values = {
9836785b9072762e15bb49657ce7b7d228dab76e44aTadashi G. Takaoka            scrubDigitsFromString(replacedWord), index,
9846785b9072762e15bb49657ce7b7d228dab76e44aTadashi G. Takaoka            (suggestion == null ? null : scrubDigitsFromString(suggestion.toString())),
985ac78633be28e8990fc3b3a8de192c80966e746e3Tadashi G. Takaoka            Constants.SUGGESTION_STRIP_COORDINATE, Constants.SUGGESTION_STRIP_COORDINATE
98607cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge        };
9876080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge        final ResearchLogger researchLogger = getInstance();
9886080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge        researchLogger.enqueuePotentiallyPrivateEvent(EVENTKEYS_LATINIME_PICKSUGGESTIONMANUALLY,
9896080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge                values);
9909bfb6202154e06d7156f2f374dd9359f1be4eb68Kurt Partridge    }
9919bfb6202154e06d7156f2f374dd9359f1be4eb68Kurt Partridge
99207cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    private static final String[] EVENTKEYS_LATINIME_PUNCTUATIONSUGGESTION = {
993f739119f3ff54d7c37b67b873373b236a45e47e4Kurt Partridge        "LatinIMEPunctuationSuggestion", "index", "suggestion", "x", "y"
99407cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    };
9959bfb6202154e06d7156f2f374dd9359f1be4eb68Kurt Partridge    public static void latinIME_punctuationSuggestion(final int index,
9966785b9072762e15bb49657ce7b7d228dab76e44aTadashi G. Takaoka            final CharSequence suggestion) {
99707cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge        final Object[] values = {
9986785b9072762e15bb49657ce7b7d228dab76e44aTadashi G. Takaoka            index, suggestion,
999ac78633be28e8990fc3b3a8de192c80966e746e3Tadashi G. Takaoka            Constants.SUGGESTION_STRIP_COORDINATE, Constants.SUGGESTION_STRIP_COORDINATE
100007cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge        };
10016080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge        getInstance().enqueueEvent(EVENTKEYS_LATINIME_PUNCTUATIONSUGGESTION, values);
1002d442984e96cc6299c905141e3e32e0a4f55394c8Kurt Partridge    }
1003d442984e96cc6299c905141e3e32e0a4f55394c8Kurt Partridge
100407cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    private static final String[] EVENTKEYS_LATINIME_SENDKEYCODEPOINT = {
1005f739119f3ff54d7c37b67b873373b236a45e47e4Kurt Partridge        "LatinIMESendKeyCodePoint", "code"
100607cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    };
1007d442984e96cc6299c905141e3e32e0a4f55394c8Kurt Partridge    public static void latinIME_sendKeyCodePoint(final int code) {
100807cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge        final Object[] values = {
1009a696781c2b18d8002275aa89e07fa7379661d025Kurt Partridge            Keyboard.printableCode(scrubDigitFromCodePoint(code))
101007cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge        };
1011bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge        final ResearchLogger researchLogger = getInstance();
1012bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge        researchLogger.enqueuePotentiallyPrivateEvent(EVENTKEYS_LATINIME_SENDKEYCODEPOINT, values);
1013bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge        if (Character.isDigit(code)) {
1014bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge            researchLogger.setCurrentLogUnitContainsDigitFlag();
1015bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge        }
1016d442984e96cc6299c905141e3e32e0a4f55394c8Kurt Partridge    }
1017d442984e96cc6299c905141e3e32e0a4f55394c8Kurt Partridge
101894e7f4bef970431f509a806d1b92b19fc3b5ce7dKurt Partridge    private static final String[] EVENTKEYS_LATINIME_SWAPSWAPPERANDSPACE = {
101994e7f4bef970431f509a806d1b92b19fc3b5ce7dKurt Partridge        "LatinIMESwapSwapperAndSpace"
102007cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    };
102194e7f4bef970431f509a806d1b92b19fc3b5ce7dKurt Partridge    public static void latinIME_swapSwapperAndSpace() {
102294e7f4bef970431f509a806d1b92b19fc3b5ce7dKurt Partridge        getInstance().enqueueEvent(EVENTKEYS_LATINIME_SWAPSWAPPERANDSPACE, EVENTKEYS_NULLVALUES);
10239bfb6202154e06d7156f2f374dd9359f1be4eb68Kurt Partridge    }
10249bfb6202154e06d7156f2f374dd9359f1be4eb68Kurt Partridge
1025c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka    private static final String[] EVENTKEYS_MAINKEYBOARDVIEW_ONLONGPRESS = {
1026c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka        "MainKeyboardViewOnLongPress"
102707cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    };
1028c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka    public static void mainKeyboardView_onLongPress() {
1029c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka        getInstance().enqueueEvent(EVENTKEYS_MAINKEYBOARDVIEW_ONLONGPRESS, EVENTKEYS_NULLVALUES);
10309bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge    }
10319bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge
1032c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka    private static final String[] EVENTKEYS_MAINKEYBOARDVIEW_SETKEYBOARD = {
1033c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka        "MainKeyboardViewSetKeyboard", "elementId", "locale", "orientation", "width",
103486fcadde5d1ca69e4d93dc7cf5e72c763a32ac84Kurt Partridge        "modeName", "action", "navigateNext", "navigatePrevious", "clobberSettingsKey",
103586fcadde5d1ca69e4d93dc7cf5e72c763a32ac84Kurt Partridge        "passwordInput", "shortcutKeyEnabled", "hasShortcutKey", "languageSwitchKeyEnabled",
103686fcadde5d1ca69e4d93dc7cf5e72c763a32ac84Kurt Partridge        "isMultiLine", "tw", "th", "keys"
103707cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    };
1038c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka    public static void mainKeyboardView_setKeyboard(final Keyboard keyboard) {
103907cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge        if (keyboard != null) {
104086fcadde5d1ca69e4d93dc7cf5e72c763a32ac84Kurt Partridge            final KeyboardId kid = keyboard.mId;
1041a696781c2b18d8002275aa89e07fa7379661d025Kurt Partridge            final boolean isPasswordView = kid.passwordInput();
10420df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge            getInstance().setIsPasswordView(isPasswordView);
104307cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge            final Object[] values = {
1044596911479cd7cdc3bf999a5260f0be381e30c7cfKurt Partridge                KeyboardId.elementIdToName(kid.mElementId),
1045596911479cd7cdc3bf999a5260f0be381e30c7cfKurt Partridge                kid.mLocale + ":" + kid.mSubtype.getExtraValueOf(KEYBOARD_LAYOUT_SET),
1046596911479cd7cdc3bf999a5260f0be381e30c7cfKurt Partridge                kid.mOrientation,
1047596911479cd7cdc3bf999a5260f0be381e30c7cfKurt Partridge                kid.mWidth,
1048596911479cd7cdc3bf999a5260f0be381e30c7cfKurt Partridge                KeyboardId.modeName(kid.mMode),
1049596911479cd7cdc3bf999a5260f0be381e30c7cfKurt Partridge                kid.imeAction(),
1050596911479cd7cdc3bf999a5260f0be381e30c7cfKurt Partridge                kid.navigateNext(),
1051596911479cd7cdc3bf999a5260f0be381e30c7cfKurt Partridge                kid.navigatePrevious(),
1052596911479cd7cdc3bf999a5260f0be381e30c7cfKurt Partridge                kid.mClobberSettingsKey,
1053596911479cd7cdc3bf999a5260f0be381e30c7cfKurt Partridge                isPasswordView,
1054596911479cd7cdc3bf999a5260f0be381e30c7cfKurt Partridge                kid.mShortcutKeyEnabled,
1055596911479cd7cdc3bf999a5260f0be381e30c7cfKurt Partridge                kid.mHasShortcutKey,
1056596911479cd7cdc3bf999a5260f0be381e30c7cfKurt Partridge                kid.mLanguageSwitchKeyEnabled,
1057596911479cd7cdc3bf999a5260f0be381e30c7cfKurt Partridge                kid.isMultiLine(),
1058596911479cd7cdc3bf999a5260f0be381e30c7cfKurt Partridge                keyboard.mOccupiedWidth,
1059596911479cd7cdc3bf999a5260f0be381e30c7cfKurt Partridge                keyboard.mOccupiedHeight,
1060596911479cd7cdc3bf999a5260f0be381e30c7cfKurt Partridge                keyboard.mKeys
1061596911479cd7cdc3bf999a5260f0be381e30c7cfKurt Partridge            };
10621cef91e4818790ea5419a6ad9ff6e36ac535c763Kurt Partridge            getInstance().setIsPasswordView(isPasswordView);
1063596911479cd7cdc3bf999a5260f0be381e30c7cfKurt Partridge            getInstance().enqueueEvent(EVENTKEYS_MAINKEYBOARDVIEW_SETKEYBOARD, values);
106448a7681e064ae259b840f0e757da2d716043d893Kurt Partridge        }
106548a7681e064ae259b840f0e757da2d716043d893Kurt Partridge    }
106648a7681e064ae259b840f0e757da2d716043d893Kurt Partridge
106707cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    private static final String[] EVENTKEYS_LATINIME_REVERTCOMMIT = {
1068f739119f3ff54d7c37b67b873373b236a45e47e4Kurt Partridge        "LatinIMERevertCommit", "originallyTypedWord"
106907cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    };
1070d442984e96cc6299c905141e3e32e0a4f55394c8Kurt Partridge    public static void latinIME_revertCommit(final String originallyTypedWord) {
107107cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge        final Object[] values = {
107207cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge            originallyTypedWord
107307cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge        };
10746080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge        getInstance().enqueuePotentiallyPrivateEvent(EVENTKEYS_LATINIME_REVERTCOMMIT, values);
1075d442984e96cc6299c905141e3e32e0a4f55394c8Kurt Partridge    }
1076d442984e96cc6299c905141e3e32e0a4f55394c8Kurt Partridge
107707cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    private static final String[] EVENTKEYS_POINTERTRACKER_CALLLISTENERONCANCELINPUT = {
1078f739119f3ff54d7c37b67b873373b236a45e47e4Kurt Partridge        "PointerTrackerCallListenerOnCancelInput"
107907cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    };
10809bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge    public static void pointerTracker_callListenerOnCancelInput() {
10816080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge        getInstance().enqueueEvent(EVENTKEYS_POINTERTRACKER_CALLLISTENERONCANCELINPUT,
108207cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge                EVENTKEYS_NULLVALUES);
10839bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge    }
10849bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge
108507cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    private static final String[] EVENTKEYS_POINTERTRACKER_CALLLISTENERONCODEINPUT = {
1086f739119f3ff54d7c37b67b873373b236a45e47e4Kurt Partridge        "PointerTrackerCallListenerOnCodeInput", "code", "outputText", "x", "y",
108707cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge        "ignoreModifierKey", "altersCode", "isEnabled"
108807cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    };
10899bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge    public static void pointerTracker_callListenerOnCodeInput(final Key key, final int x,
10909bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge            final int y, final boolean ignoreModifierKey, final boolean altersCode,
10919bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge            final int code) {
109207cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge        if (key != null) {
109329d5973fd35438a83acf7f44b5d55d5620278ee3Tadashi G. Takaoka            String outputText = key.getOutputText();
109407cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge            final Object[] values = {
1095a696781c2b18d8002275aa89e07fa7379661d025Kurt Partridge                Keyboard.printableCode(scrubDigitFromCodePoint(code)), outputText == null ? null
1096a696781c2b18d8002275aa89e07fa7379661d025Kurt Partridge                        : scrubDigitsFromString(outputText.toString()),
1097a696781c2b18d8002275aa89e07fa7379661d025Kurt Partridge                x, y, ignoreModifierKey, altersCode, key.isEnabled()
109807cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge            };
10996080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge            getInstance().enqueuePotentiallyPrivateEvent(
11006080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge                    EVENTKEYS_POINTERTRACKER_CALLLISTENERONCODEINPUT, values);
11019bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge        }
11029bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge    }
11039bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge
110407cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    private static final String[] EVENTKEYS_POINTERTRACKER_CALLLISTENERONRELEASE = {
1105f739119f3ff54d7c37b67b873373b236a45e47e4Kurt Partridge        "PointerTrackerCallListenerOnRelease", "code", "withSliding", "ignoreModifierKey",
110607cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge        "isEnabled"
110707cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    };
11089bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge    public static void pointerTracker_callListenerOnRelease(final Key key, final int primaryCode,
11099bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge            final boolean withSliding, final boolean ignoreModifierKey) {
111007cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge        if (key != null) {
111107cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge            final Object[] values = {
1112a696781c2b18d8002275aa89e07fa7379661d025Kurt Partridge                Keyboard.printableCode(scrubDigitFromCodePoint(primaryCode)), withSliding,
1113a696781c2b18d8002275aa89e07fa7379661d025Kurt Partridge                ignoreModifierKey, key.isEnabled()
111407cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge            };
11156080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge            getInstance().enqueuePotentiallyPrivateEvent(
11166080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge                    EVENTKEYS_POINTERTRACKER_CALLLISTENERONRELEASE, values);
11179bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge        }
11189bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge    }
11199bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge
112007cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    private static final String[] EVENTKEYS_POINTERTRACKER_ONDOWNEVENT = {
1121f739119f3ff54d7c37b67b873373b236a45e47e4Kurt Partridge        "PointerTrackerOnDownEvent", "deltaT", "distanceSquared"
112207cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    };
11239bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge    public static void pointerTracker_onDownEvent(long deltaT, int distanceSquared) {
112407cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge        final Object[] values = {
112507cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge            deltaT, distanceSquared
112607cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge        };
11276080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge        getInstance().enqueuePotentiallyPrivateEvent(EVENTKEYS_POINTERTRACKER_ONDOWNEVENT, values);
11289bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge    }
11299bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge
113007cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    private static final String[] EVENTKEYS_POINTERTRACKER_ONMOVEEVENT = {
1131f739119f3ff54d7c37b67b873373b236a45e47e4Kurt Partridge        "PointerTrackerOnMoveEvent", "x", "y", "lastX", "lastY"
113207cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    };
11339bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge    public static void pointerTracker_onMoveEvent(final int x, final int y, final int lastX,
11349bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge            final int lastY) {
113507cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge        final Object[] values = {
113607cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge            x, y, lastX, lastY
113707cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge        };
11386080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge        getInstance().enqueuePotentiallyPrivateEvent(EVENTKEYS_POINTERTRACKER_ONMOVEEVENT, values);
11399bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge    }
11409bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge
114194e7f4bef970431f509a806d1b92b19fc3b5ce7dKurt Partridge    private static final String[] EVENTKEYS_RICHINPUTCONNECTION_COMMITCOMPLETION = {
114294e7f4bef970431f509a806d1b92b19fc3b5ce7dKurt Partridge        "RichInputConnectionCommitCompletion", "completionInfo"
114394e7f4bef970431f509a806d1b92b19fc3b5ce7dKurt Partridge    };
114494e7f4bef970431f509a806d1b92b19fc3b5ce7dKurt Partridge    public static void richInputConnection_commitCompletion(final CompletionInfo completionInfo) {
114594e7f4bef970431f509a806d1b92b19fc3b5ce7dKurt Partridge        final Object[] values = {
114694e7f4bef970431f509a806d1b92b19fc3b5ce7dKurt Partridge            completionInfo
114794e7f4bef970431f509a806d1b92b19fc3b5ce7dKurt Partridge        };
114894e7f4bef970431f509a806d1b92b19fc3b5ce7dKurt Partridge        final ResearchLogger researchLogger = getInstance();
114994e7f4bef970431f509a806d1b92b19fc3b5ce7dKurt Partridge        researchLogger.enqueuePotentiallyPrivateEvent(
115094e7f4bef970431f509a806d1b92b19fc3b5ce7dKurt Partridge                EVENTKEYS_RICHINPUTCONNECTION_COMMITCOMPLETION, values);
115194e7f4bef970431f509a806d1b92b19fc3b5ce7dKurt Partridge    }
115294e7f4bef970431f509a806d1b92b19fc3b5ce7dKurt Partridge
1153bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge    // Disabled for privacy-protection reasons.  Because this event comes after
1154bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge    // richInputConnection_commitText, which is the event used to separate LogUnits, the
1155bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge    // data in this event can be associated with the next LogUnit, revealing information
1156bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge    // about the current word even if it was supposed to be suppressed.  The occurrance of
1157bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge    // autocorrection can be determined by examining the difference between the text strings in
1158bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge    // the last call to richInputConnection_setComposingText before
1159bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge    // richInputConnection_commitText, so it's not a data loss.
1160bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge    // TODO: Figure out how to log this event without loss of privacy.
1161bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge    /*
116294e7f4bef970431f509a806d1b92b19fc3b5ce7dKurt Partridge    private static final String[] EVENTKEYS_RICHINPUTCONNECTION_COMMITCORRECTION = {
1163bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge        "RichInputConnectionCommitCorrection", "typedWord", "autoCorrection"
116494e7f4bef970431f509a806d1b92b19fc3b5ce7dKurt Partridge    };
1165bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge    */
116694e7f4bef970431f509a806d1b92b19fc3b5ce7dKurt Partridge    public static void richInputConnection_commitCorrection(CorrectionInfo correctionInfo) {
1167bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge        /*
116894e7f4bef970431f509a806d1b92b19fc3b5ce7dKurt Partridge        final String typedWord = correctionInfo.getOldText().toString();
116994e7f4bef970431f509a806d1b92b19fc3b5ce7dKurt Partridge        final String autoCorrection = correctionInfo.getNewText().toString();
117094e7f4bef970431f509a806d1b92b19fc3b5ce7dKurt Partridge        final Object[] values = {
117194e7f4bef970431f509a806d1b92b19fc3b5ce7dKurt Partridge            scrubDigitsFromString(typedWord), scrubDigitsFromString(autoCorrection)
117294e7f4bef970431f509a806d1b92b19fc3b5ce7dKurt Partridge        };
117394e7f4bef970431f509a806d1b92b19fc3b5ce7dKurt Partridge        final ResearchLogger researchLogger = getInstance();
117494e7f4bef970431f509a806d1b92b19fc3b5ce7dKurt Partridge        researchLogger.enqueuePotentiallyPrivateEvent(
117594e7f4bef970431f509a806d1b92b19fc3b5ce7dKurt Partridge                EVENTKEYS_RICHINPUTCONNECTION_COMMITCORRECTION, values);
1176bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge        */
117794e7f4bef970431f509a806d1b92b19fc3b5ce7dKurt Partridge    }
117894e7f4bef970431f509a806d1b92b19fc3b5ce7dKurt Partridge
117994e7f4bef970431f509a806d1b92b19fc3b5ce7dKurt Partridge    private static final String[] EVENTKEYS_RICHINPUTCONNECTION_COMMITTEXT = {
118094e7f4bef970431f509a806d1b92b19fc3b5ce7dKurt Partridge        "RichInputConnectionCommitText", "typedWord", "newCursorPosition"
118194e7f4bef970431f509a806d1b92b19fc3b5ce7dKurt Partridge    };
118294e7f4bef970431f509a806d1b92b19fc3b5ce7dKurt Partridge    public static void richInputConnection_commitText(final CharSequence typedWord,
118394e7f4bef970431f509a806d1b92b19fc3b5ce7dKurt Partridge            final int newCursorPosition) {
118494e7f4bef970431f509a806d1b92b19fc3b5ce7dKurt Partridge        final String scrubbedWord = scrubDigitsFromString(typedWord.toString());
118594e7f4bef970431f509a806d1b92b19fc3b5ce7dKurt Partridge        final Object[] values = {
118694e7f4bef970431f509a806d1b92b19fc3b5ce7dKurt Partridge            scrubbedWord, newCursorPosition
118794e7f4bef970431f509a806d1b92b19fc3b5ce7dKurt Partridge        };
118894e7f4bef970431f509a806d1b92b19fc3b5ce7dKurt Partridge        final ResearchLogger researchLogger = getInstance();
118994e7f4bef970431f509a806d1b92b19fc3b5ce7dKurt Partridge        researchLogger.enqueuePotentiallyPrivateEvent(EVENTKEYS_RICHINPUTCONNECTION_COMMITTEXT,
119094e7f4bef970431f509a806d1b92b19fc3b5ce7dKurt Partridge                values);
119194e7f4bef970431f509a806d1b92b19fc3b5ce7dKurt Partridge        researchLogger.onWordComplete(scrubbedWord);
119294e7f4bef970431f509a806d1b92b19fc3b5ce7dKurt Partridge    }
119394e7f4bef970431f509a806d1b92b19fc3b5ce7dKurt Partridge
119494e7f4bef970431f509a806d1b92b19fc3b5ce7dKurt Partridge    private static final String[] EVENTKEYS_RICHINPUTCONNECTION_DELETESURROUNDINGTEXT = {
119594e7f4bef970431f509a806d1b92b19fc3b5ce7dKurt Partridge        "RichInputConnectionDeleteSurroundingText", "beforeLength", "afterLength"
119694e7f4bef970431f509a806d1b92b19fc3b5ce7dKurt Partridge    };
119794e7f4bef970431f509a806d1b92b19fc3b5ce7dKurt Partridge    public static void richInputConnection_deleteSurroundingText(final int beforeLength,
119894e7f4bef970431f509a806d1b92b19fc3b5ce7dKurt Partridge            final int afterLength) {
119994e7f4bef970431f509a806d1b92b19fc3b5ce7dKurt Partridge        final Object[] values = {
120094e7f4bef970431f509a806d1b92b19fc3b5ce7dKurt Partridge            beforeLength, afterLength
120194e7f4bef970431f509a806d1b92b19fc3b5ce7dKurt Partridge        };
1202bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge        getInstance().enqueuePotentiallyPrivateEvent(
1203bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge                EVENTKEYS_RICHINPUTCONNECTION_DELETESURROUNDINGTEXT, values);
120494e7f4bef970431f509a806d1b92b19fc3b5ce7dKurt Partridge    }
120594e7f4bef970431f509a806d1b92b19fc3b5ce7dKurt Partridge
120694e7f4bef970431f509a806d1b92b19fc3b5ce7dKurt Partridge    private static final String[] EVENTKEYS_RICHINPUTCONNECTION_FINISHCOMPOSINGTEXT = {
120794e7f4bef970431f509a806d1b92b19fc3b5ce7dKurt Partridge        "RichInputConnectionFinishComposingText"
120894e7f4bef970431f509a806d1b92b19fc3b5ce7dKurt Partridge    };
120994e7f4bef970431f509a806d1b92b19fc3b5ce7dKurt Partridge    public static void richInputConnection_finishComposingText() {
121094e7f4bef970431f509a806d1b92b19fc3b5ce7dKurt Partridge        getInstance().enqueueEvent(EVENTKEYS_RICHINPUTCONNECTION_FINISHCOMPOSINGTEXT,
121194e7f4bef970431f509a806d1b92b19fc3b5ce7dKurt Partridge                EVENTKEYS_NULLVALUES);
121294e7f4bef970431f509a806d1b92b19fc3b5ce7dKurt Partridge    }
121394e7f4bef970431f509a806d1b92b19fc3b5ce7dKurt Partridge
121494e7f4bef970431f509a806d1b92b19fc3b5ce7dKurt Partridge    private static final String[] EVENTKEYS_RICHINPUTCONNECTION_PERFORMEDITORACTION = {
121594e7f4bef970431f509a806d1b92b19fc3b5ce7dKurt Partridge        "RichInputConnectionPerformEditorAction", "imeActionNext"
121694e7f4bef970431f509a806d1b92b19fc3b5ce7dKurt Partridge    };
121794e7f4bef970431f509a806d1b92b19fc3b5ce7dKurt Partridge    public static void richInputConnection_performEditorAction(final int imeActionNext) {
121894e7f4bef970431f509a806d1b92b19fc3b5ce7dKurt Partridge        final Object[] values = {
121994e7f4bef970431f509a806d1b92b19fc3b5ce7dKurt Partridge            imeActionNext
122094e7f4bef970431f509a806d1b92b19fc3b5ce7dKurt Partridge        };
122194e7f4bef970431f509a806d1b92b19fc3b5ce7dKurt Partridge        getInstance().enqueueEvent(EVENTKEYS_RICHINPUTCONNECTION_PERFORMEDITORACTION, values);
122294e7f4bef970431f509a806d1b92b19fc3b5ce7dKurt Partridge    }
122394e7f4bef970431f509a806d1b92b19fc3b5ce7dKurt Partridge
122494e7f4bef970431f509a806d1b92b19fc3b5ce7dKurt Partridge    private static final String[] EVENTKEYS_RICHINPUTCONNECTION_SENDKEYEVENT = {
122594e7f4bef970431f509a806d1b92b19fc3b5ce7dKurt Partridge        "RichInputConnectionSendKeyEvent", "eventTime", "action", "code"
122694e7f4bef970431f509a806d1b92b19fc3b5ce7dKurt Partridge    };
122794e7f4bef970431f509a806d1b92b19fc3b5ce7dKurt Partridge    public static void richInputConnection_sendKeyEvent(final KeyEvent keyEvent) {
122894e7f4bef970431f509a806d1b92b19fc3b5ce7dKurt Partridge        final Object[] values = {
122994e7f4bef970431f509a806d1b92b19fc3b5ce7dKurt Partridge            keyEvent.getEventTime(),
123094e7f4bef970431f509a806d1b92b19fc3b5ce7dKurt Partridge            keyEvent.getAction(),
123194e7f4bef970431f509a806d1b92b19fc3b5ce7dKurt Partridge            keyEvent.getKeyCode()
123294e7f4bef970431f509a806d1b92b19fc3b5ce7dKurt Partridge        };
1233bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge        getInstance().enqueuePotentiallyPrivateEvent(EVENTKEYS_RICHINPUTCONNECTION_SENDKEYEVENT,
1234bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge                values);
123594e7f4bef970431f509a806d1b92b19fc3b5ce7dKurt Partridge    }
123694e7f4bef970431f509a806d1b92b19fc3b5ce7dKurt Partridge
123794e7f4bef970431f509a806d1b92b19fc3b5ce7dKurt Partridge    private static final String[] EVENTKEYS_RICHINPUTCONNECTION_SETCOMPOSINGTEXT = {
123894e7f4bef970431f509a806d1b92b19fc3b5ce7dKurt Partridge        "RichInputConnectionSetComposingText", "text", "newCursorPosition"
123994e7f4bef970431f509a806d1b92b19fc3b5ce7dKurt Partridge    };
124094e7f4bef970431f509a806d1b92b19fc3b5ce7dKurt Partridge    public static void richInputConnection_setComposingText(final CharSequence text,
124194e7f4bef970431f509a806d1b92b19fc3b5ce7dKurt Partridge            final int newCursorPosition) {
1242bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge        if (text == null) {
1243bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge            throw new RuntimeException("setComposingText is null");
1244bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge        }
124594e7f4bef970431f509a806d1b92b19fc3b5ce7dKurt Partridge        final Object[] values = {
124694e7f4bef970431f509a806d1b92b19fc3b5ce7dKurt Partridge            text, newCursorPosition
124794e7f4bef970431f509a806d1b92b19fc3b5ce7dKurt Partridge        };
1248bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge        getInstance().enqueuePotentiallyPrivateEvent(EVENTKEYS_RICHINPUTCONNECTION_SETCOMPOSINGTEXT,
1249bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge                values);
125094e7f4bef970431f509a806d1b92b19fc3b5ce7dKurt Partridge    }
125194e7f4bef970431f509a806d1b92b19fc3b5ce7dKurt Partridge
125294e7f4bef970431f509a806d1b92b19fc3b5ce7dKurt Partridge    private static final String[] EVENTKEYS_RICHINPUTCONNECTION_SETSELECTION = {
125394e7f4bef970431f509a806d1b92b19fc3b5ce7dKurt Partridge        "RichInputConnectionSetSelection", "from", "to"
125494e7f4bef970431f509a806d1b92b19fc3b5ce7dKurt Partridge    };
125594e7f4bef970431f509a806d1b92b19fc3b5ce7dKurt Partridge    public static void richInputConnection_setSelection(final int from, final int to) {
125694e7f4bef970431f509a806d1b92b19fc3b5ce7dKurt Partridge        final Object[] values = {
125794e7f4bef970431f509a806d1b92b19fc3b5ce7dKurt Partridge            from, to
125894e7f4bef970431f509a806d1b92b19fc3b5ce7dKurt Partridge        };
1259bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge        getInstance().enqueuePotentiallyPrivateEvent(EVENTKEYS_RICHINPUTCONNECTION_SETSELECTION,
1260bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge                values);
126194e7f4bef970431f509a806d1b92b19fc3b5ce7dKurt Partridge    }
126294e7f4bef970431f509a806d1b92b19fc3b5ce7dKurt Partridge
126307cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    private static final String[] EVENTKEYS_SUDDENJUMPINGTOUCHEVENTHANDLER_ONTOUCHEVENT = {
1264f739119f3ff54d7c37b67b873373b236a45e47e4Kurt Partridge        "SuddenJumpingTouchEventHandlerOnTouchEvent", "motionEvent"
126507cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    };
12669bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge    public static void suddenJumpingTouchEventHandler_onTouchEvent(final MotionEvent me) {
126707cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge        if (me != null) {
126807cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge            final Object[] values = {
126907cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge                me.toString()
127007cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge            };
12716080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge            getInstance().enqueuePotentiallyPrivateEvent(
12726080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge                    EVENTKEYS_SUDDENJUMPINGTOUCHEVENTHANDLER_ONTOUCHEVENT, values);
127307cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge        }
127407cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    }
127507cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge
12764702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka    private static final String[] EVENTKEYS_SUGGESTIONSTRIPVIEW_SETSUGGESTIONS = {
12774702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka        "SuggestionStripViewSetSuggestions", "suggestedWords"
127807cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    };
12794702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka    public static void suggestionStripView_setSuggestions(final SuggestedWords suggestedWords) {
128007cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge        if (suggestedWords != null) {
128107cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge            final Object[] values = {
128286fcadde5d1ca69e4d93dc7cf5e72c763a32ac84Kurt Partridge                suggestedWords
128307cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge            };
12844702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka            getInstance().enqueuePotentiallyPrivateEvent(
12854702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka                    EVENTKEYS_SUGGESTIONSTRIPVIEW_SETSUGGESTIONS, values);
1286a9ca7867b5a7c0be115966211a05f5d460c8638cKurt Partridge        }
1287a9ca7867b5a7c0be115966211a05f5d460c8638cKurt Partridge    }
1288724bc479f7d796d6ce5d5e200216bea855b818b2Kurt Partridge
1289724bc479f7d796d6ce5d5e200216bea855b818b2Kurt Partridge    private static final String[] EVENTKEYS_USER_TIMESTAMP = {
1290724bc479f7d796d6ce5d5e200216bea855b818b2Kurt Partridge        "UserTimestamp"
1291724bc479f7d796d6ce5d5e200216bea855b818b2Kurt Partridge    };
1292724bc479f7d796d6ce5d5e200216bea855b818b2Kurt Partridge    public void userTimestamp() {
12936080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge        getInstance().enqueueEvent(EVENTKEYS_USER_TIMESTAMP, EVENTKEYS_NULLVALUES);
1294724bc479f7d796d6ce5d5e200216bea855b818b2Kurt Partridge    }
1295bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge
1296bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge    private static final String[] EVENTKEYS_STATISTICS = {
1297bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge        "Statistics", "charCount", "letterCount", "numberCount", "spaceCount", "deleteOpsCount",
1298bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge        "wordCount", "isEmptyUponStarting", "isEmptinessStateKnown", "averageTimeBetweenKeys",
1299bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge        "averageTimeBeforeDelete", "averageTimeDuringRepeatedDelete", "averageTimeAfterDelete"
1300bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge    };
1301bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge    private static void logStatistics() {
1302bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge        final ResearchLogger researchLogger = getInstance();
1303bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge        final Statistics statistics = researchLogger.mStatistics;
1304bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge        final Object[] values = {
1305bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge            statistics.mCharCount, statistics.mLetterCount, statistics.mNumberCount,
1306bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge            statistics.mSpaceCount, statistics.mDeleteKeyCount,
1307bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge            statistics.mWordCount, statistics.mIsEmptyUponStarting,
1308bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge            statistics.mIsEmptinessStateKnown, statistics.mKeyCounter.getAverageTime(),
1309bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge            statistics.mBeforeDeleteKeyCounter.getAverageTime(),
1310bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge            statistics.mDuringRepeatedDeleteKeysCounter.getAverageTime(),
1311bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge            statistics.mAfterDeleteKeyCounter.getAverageTime()
1312bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge        };
1313bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge        researchLogger.enqueueEvent(EVENTKEYS_STATISTICS, values);
1314bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge    }
13155a937aae99fbd1c1e6f4976e639ef585e45675e5Kurt Partridge}
1316