ResearchLogger.java revision c8e45ddb032554f4e9d4411d8ef47d98db62d77b
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
21724bc479f7d796d6ce5d5e200216bea855b818b2Kurt Partridgeimport android.app.AlertDialog;
224331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridgeimport android.app.Dialog;
2373c5dbd9d262159af3475273b79babe292c75d76Kurt Partridgeimport android.content.Context;
24724bc479f7d796d6ce5d5e200216bea855b818b2Kurt Partridgeimport android.content.DialogInterface;
254331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridgeimport android.content.DialogInterface.OnCancelListener;
26d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridgeimport android.content.SharedPreferences;
2777814c4bb0670c3a20c5e636890d70ea1a144409Kurt Partridgeimport android.content.SharedPreferences.Editor;
2873c5dbd9d262159af3475273b79babe292c75d76Kurt Partridgeimport android.content.pm.PackageInfo;
2973c5dbd9d262159af3475273b79babe292c75d76Kurt Partridgeimport android.content.pm.PackageManager.NameNotFoundException;
304fa6e5726041a22db4f15d99521ea06419401946Kurt Partridgeimport android.graphics.Canvas;
314fa6e5726041a22db4f15d99521ea06419401946Kurt Partridgeimport android.graphics.Color;
324fa6e5726041a22db4f15d99521ea06419401946Kurt Partridgeimport android.graphics.Paint;
334fa6e5726041a22db4f15d99521ea06419401946Kurt Partridgeimport android.graphics.Paint.Style;
34c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaokaimport android.inputmethodservice.InputMethodService;
3548a7681e064ae259b840f0e757da2d716043d893Kurt Partridgeimport android.os.Build;
364331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridgeimport android.os.IBinder;
37d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridgeimport android.text.TextUtils;
3881dae8d015f63834b2ded44424636b625ece7736Kurt Partridgeimport android.text.format.DateUtils;
39d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridgeimport android.util.Log;
40d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridgeimport android.view.MotionEvent;
414331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridgeimport android.view.View;
424331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridgeimport android.view.View.OnClickListener;
434331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridgeimport android.view.Window;
444331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridgeimport android.view.WindowManager;
459bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridgeimport android.view.inputmethod.CompletionInfo;
469bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridgeimport android.view.inputmethod.EditorInfo;
47d67a248de45a698d1009757c9f4e750c77bf35f1Kurt Partridgeimport android.view.inputmethod.InputConnection;
484331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridgeimport android.widget.Button;
49724bc479f7d796d6ce5d5e200216bea855b818b2Kurt Partridgeimport android.widget.Toast;
50d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge
519bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridgeimport com.android.inputmethod.keyboard.Key;
52d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridgeimport com.android.inputmethod.keyboard.Keyboard;
5386fcadde5d1ca69e4d93dc7cf5e72c763a32ac84Kurt Partridgeimport com.android.inputmethod.keyboard.KeyboardId;
54223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridgeimport com.android.inputmethod.keyboard.KeyboardSwitcher;
554fa6e5726041a22db4f15d99521ea06419401946Kurt Partridgeimport com.android.inputmethod.keyboard.KeyboardView;
56c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaokaimport com.android.inputmethod.keyboard.MainKeyboardView;
576b966160ac8570271547bf63217efa5e228d4accKurt Partridgeimport com.android.inputmethod.latin.Dictionary;
586b966160ac8570271547bf63217efa5e228d4accKurt Partridgeimport com.android.inputmethod.latin.LatinIME;
596b966160ac8570271547bf63217efa5e228d4accKurt Partridgeimport com.android.inputmethod.latin.R;
606b966160ac8570271547bf63217efa5e228d4accKurt Partridgeimport com.android.inputmethod.latin.RichInputConnection;
6165fc909e13134d34e87d5d75ff4cdd46fb9cebf0Kurt Partridgeimport com.android.inputmethod.latin.RichInputConnection.Range;
626b966160ac8570271547bf63217efa5e228d4accKurt Partridgeimport com.android.inputmethod.latin.Suggest;
636b966160ac8570271547bf63217efa5e228d4accKurt Partridgeimport com.android.inputmethod.latin.SuggestedWords;
649bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridgeimport com.android.inputmethod.latin.define.ProductionFlag;
65d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge
66d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridgeimport java.io.File;
67b8e2ae3bc312269897057fccc34cd736c05bcc90Kurt Partridgeimport java.io.IOException;
6807cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridgeimport java.text.SimpleDateFormat;
696080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridgeimport java.util.ArrayList;
7007cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridgeimport java.util.Date;
716080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridgeimport java.util.List;
7207cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridgeimport java.util.Locale;
7377814c4bb0670c3a20c5e636890d70ea1a144409Kurt Partridgeimport java.util.UUID;
74d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge
75d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge/**
76d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge * Logs the use of the LatinIME keyboard.
77d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge *
78d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge * This class logs operations on the IME keyboard, including what the user has typed.
79d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge * Data is stored locally in a file in app-specific storage.
80d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge *
8193ebf74bae44728e0d5f7e738ea28376187a876eTadashi G. Takaoka * This functionality is off by default. See {@link ProductionFlag#IS_EXPERIMENTAL}.
82d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge */
83d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridgepublic class ResearchLogger implements SharedPreferences.OnSharedPreferenceChangeListener {
84d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge    private static final String TAG = ResearchLogger.class.getSimpleName();
856080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge    private static final boolean OUTPUT_ENTIRE_BUFFER = false;  // true may disclose private info
866b966160ac8570271547bf63217efa5e228d4accKurt Partridge    public static final boolean DEFAULT_USABILITY_STUDY_MODE = false;
8707cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    /* package */ static boolean sIsLogging = false;
8858caa775a700e99d18cdca922861f1882bf8d1f4Kurt Partridge    private static final int OUTPUT_FORMAT_VERSION = 1;
8907cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    private static final String PREF_USABILITY_STUDY_MODE = "usability_study_mode";
904331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge    private static final String PREF_RESEARCH_HAS_SEEN_SPLASH = "pref_research_has_seen_splash";
910df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge    /* package */ static final String FILENAME_PREFIX = "researchLog";
9207cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    private static final String FILENAME_SUFFIX = ".txt";
9307cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    private static final SimpleDateFormat TIMESTAMP_DATEFORMAT =
94223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge            new SimpleDateFormat("yyyyMMddHHmmssS", Locale.US);
954fa6e5726041a22db4f15d99521ea06419401946Kurt Partridge    private static final boolean IS_SHOWING_INDICATOR = true;
964fa6e5726041a22db4f15d99521ea06419401946Kurt Partridge    private static final boolean IS_SHOWING_INDICATOR_CLEARLY = false;
9707cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge
9807cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    // constants related to specific log points
99aec44d50a7534d8704a7006b4f90f5e8040a931bKurt Partridge    private static final String WHITESPACE_SEPARATORS = " \t\n\r";
100d67a248de45a698d1009757c9f4e750c77bf35f1Kurt Partridge    private static final int MAX_INPUTVIEW_LENGTH_TO_CAPTURE = 8192; // must be >=1
10107cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    private static final String PREF_RESEARCH_LOGGER_UUID_STRING = "pref_research_logger_uuid";
1023c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge    private static final int ABORT_TIMEOUT_IN_MS = 10 * 1000; // timeout to notify user
103d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge
10407cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    private static final ResearchLogger sInstance = new ResearchLogger();
10507cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    // to write to a different filename, e.g., for testing, set mFile before calling start()
106223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge    /* package */ File mFilesDir;
107223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge    /* package */ String mUUIDString;
108223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge    /* package */ ResearchLog mMainResearchLog;
109223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge    // The mIntentionalResearchLog records all events for the session, private or not (excepting
110223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge    // passwords).  It is written to permanent storage only if the user explicitly commands
111223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge    // the system to do so.
112223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge    /* package */ ResearchLog mIntentionalResearchLog;
113223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge    // LogUnits are queued here and released only when the user requests the intentional log.
1143c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge    private List<LogUnit> mIntentionalResearchLogQueue = new ArrayList<LogUnit>();
115223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge
1161cef91e4818790ea5419a6ad9ff6e36ac535c763Kurt Partridge    private boolean mIsPasswordView = false;
117223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge    private boolean mIsLoggingSuspended = false;
1180df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge    private SharedPreferences mPrefs;
119d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge
120a696781c2b18d8002275aa89e07fa7379661d025Kurt Partridge    // digits entered by the user are replaced with this codepoint.
121a696781c2b18d8002275aa89e07fa7379661d025Kurt Partridge    /* package for test */ static final int DIGIT_REPLACEMENT_CODEPOINT =
122a696781c2b18d8002275aa89e07fa7379661d025Kurt Partridge            Character.codePointAt("\uE000", 0);  // U+E000 is in the "private-use area"
1236080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge    // U+E001 is in the "private-use area"
1246080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge    /* package for test */ static final String WORD_REPLACEMENT_STRING = "\uE001";
12581dae8d015f63834b2ded44424636b625ece7736Kurt Partridge    private static final String PREF_LAST_CLEANUP_TIME = "pref_last_cleanup_time";
12681dae8d015f63834b2ded44424636b625ece7736Kurt Partridge    private static final long DURATION_BETWEEN_DIR_CLEANUP_IN_MS = DateUtils.DAY_IN_MILLIS;
12781dae8d015f63834b2ded44424636b625ece7736Kurt Partridge    private static final long MAX_LOGFILE_AGE_IN_MS = DateUtils.DAY_IN_MILLIS;
1280df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge    protected static final int SUSPEND_DURATION_IN_MINUTES = 1;
12907cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    // set when LatinIME should ignore an onUpdateSelection() callback that
13007cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    // arises from operations in this class
13107cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    private static boolean sLatinIMEExpectingUpdateSelection = false;
132d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge
1336080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge    // used to check whether words are not unique
1346080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge    private Suggest mSuggest;
1356080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge    private Dictionary mDictionary;
136223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge    private KeyboardSwitcher mKeyboardSwitcher;
1374331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge    private InputMethodService mInputMethodService;
138b8e2ae3bc312269897057fccc34cd736c05bcc90Kurt Partridge
1399c539d5a5c8e9b36be482fd7ebb2a71a22ef6af0Kurt Partridge    private ResearchLogUploader mResearchLogUploader;
1409c539d5a5c8e9b36be482fd7ebb2a71a22ef6af0Kurt Partridge
14107cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    private ResearchLogger() {
14207cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    }
143d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge
14407cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    public static ResearchLogger getInstance() {
14507cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge        return sInstance;
14607cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    }
147d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge
148223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge    public void init(final InputMethodService ims, final SharedPreferences prefs,
149223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge            KeyboardSwitcher keyboardSwitcher) {
15007cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge        assert ims != null;
15107cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge        if (ims == null) {
15207cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge            Log.w(TAG, "IMS is null; logging is off");
15307cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge        } else {
15407cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge            mFilesDir = ims.getFilesDir();
15507cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge            if (mFilesDir == null || !mFilesDir.exists()) {
15607cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge                Log.w(TAG, "IME storage directory does not exist.");
157d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge            }
158d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge        }
15907cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge        if (prefs != null) {
160223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge            mUUIDString = getUUID(prefs);
1610df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge            if (!prefs.contains(PREF_USABILITY_STUDY_MODE)) {
1620df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge                Editor e = prefs.edit();
1630df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge                e.putBoolean(PREF_USABILITY_STUDY_MODE, DEFAULT_USABILITY_STUDY_MODE);
1640df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge                e.apply();
1650df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge            }
16607cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge            sIsLogging = prefs.getBoolean(PREF_USABILITY_STUDY_MODE, false);
167724bc479f7d796d6ce5d5e200216bea855b818b2Kurt Partridge            prefs.registerOnSharedPreferenceChangeListener(this);
16881dae8d015f63834b2ded44424636b625ece7736Kurt Partridge
16981dae8d015f63834b2ded44424636b625ece7736Kurt Partridge            final long lastCleanupTime = prefs.getLong(PREF_LAST_CLEANUP_TIME, 0L);
17081dae8d015f63834b2ded44424636b625ece7736Kurt Partridge            final long now = System.currentTimeMillis();
17181dae8d015f63834b2ded44424636b625ece7736Kurt Partridge            if (lastCleanupTime + DURATION_BETWEEN_DIR_CLEANUP_IN_MS < now) {
17281dae8d015f63834b2ded44424636b625ece7736Kurt Partridge                final long timeHorizon = now - MAX_LOGFILE_AGE_IN_MS;
17381dae8d015f63834b2ded44424636b625ece7736Kurt Partridge                cleanupLoggingDir(mFilesDir, timeHorizon);
17481dae8d015f63834b2ded44424636b625ece7736Kurt Partridge                Editor e = prefs.edit();
17581dae8d015f63834b2ded44424636b625ece7736Kurt Partridge                e.putLong(PREF_LAST_CLEANUP_TIME, now);
17681dae8d015f63834b2ded44424636b625ece7736Kurt Partridge                e.apply();
17781dae8d015f63834b2ded44424636b625ece7736Kurt Partridge            }
178d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge        }
1799c539d5a5c8e9b36be482fd7ebb2a71a22ef6af0Kurt Partridge        mResearchLogUploader = new ResearchLogUploader(ims, mFilesDir);
1809c539d5a5c8e9b36be482fd7ebb2a71a22ef6af0Kurt Partridge        mResearchLogUploader.start();
181223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge        mKeyboardSwitcher = keyboardSwitcher;
1824331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge        mInputMethodService = ims;
1830df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge        mPrefs = prefs;
184223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge    }
185223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge
18681dae8d015f63834b2ded44424636b625ece7736Kurt Partridge    private void cleanupLoggingDir(final File dir, final long time) {
18781dae8d015f63834b2ded44424636b625ece7736Kurt Partridge        for (File file : dir.listFiles()) {
18881dae8d015f63834b2ded44424636b625ece7736Kurt Partridge            if (file.getName().startsWith(ResearchLogger.FILENAME_PREFIX) &&
18981dae8d015f63834b2ded44424636b625ece7736Kurt Partridge                    file.lastModified() < time) {
19081dae8d015f63834b2ded44424636b625ece7736Kurt Partridge                file.delete();
19181dae8d015f63834b2ded44424636b625ece7736Kurt Partridge            }
19281dae8d015f63834b2ded44424636b625ece7736Kurt Partridge        }
19381dae8d015f63834b2ded44424636b625ece7736Kurt Partridge    }
19481dae8d015f63834b2ded44424636b625ece7736Kurt Partridge
195c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka    public void mainKeyboardView_onAttachedToWindow() {
1964331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge        maybeShowSplashScreen();
1974331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge    }
1984331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge
1994331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge    private boolean hasSeenSplash() {
2004331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge        return mPrefs.getBoolean(PREF_RESEARCH_HAS_SEEN_SPLASH, false);
2014331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge    }
2024331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge
2034331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge    private Dialog mSplashDialog = null;
2044331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge
2054331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge    private void maybeShowSplashScreen() {
2064331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge        if (hasSeenSplash()) {
2074331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge            return;
2084331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge        }
2094331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge        if (mSplashDialog != null && mSplashDialog.isShowing()) {
2104331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge            return;
2114331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge        }
2124331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge        final IBinder windowToken = mKeyboardSwitcher.getKeyboardView().getWindowToken();
2134331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge        if (windowToken == null) {
2144331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge            return;
2154331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge        }
2164331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge        mSplashDialog = new Dialog(mInputMethodService, android.R.style.Theme_Holo_Dialog);
2174331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge        mSplashDialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
2184331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge        mSplashDialog.setContentView(R.layout.research_splash);
2194331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge        mSplashDialog.setCancelable(true);
2204331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge        final Window w = mSplashDialog.getWindow();
2214331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge        final WindowManager.LayoutParams lp = w.getAttributes();
2224331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge        lp.token = windowToken;
2234331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge        lp.type = WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
2244331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge        w.setAttributes(lp);
2254331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge        w.addFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
2264331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge        mSplashDialog.setOnCancelListener(new OnCancelListener() {
2274331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge            @Override
2284331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge            public void onCancel(DialogInterface dialog) {
2294331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge                mInputMethodService.requestHideSelf(0);
2304331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge            }
2314331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge        });
2324331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge        final Button doNotLogButton = (Button) mSplashDialog.findViewById(
2334331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge                R.id.research_do_not_log_button);
2344331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge        doNotLogButton.setOnClickListener(new OnClickListener() {
2354331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge            @Override
2364331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge            public void onClick(View v) {
2374331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge                onUserLoggingElection(false);
2384331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge                mSplashDialog.dismiss();
2394331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge            }
2404331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge        });
2414331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge        final Button doLogButton = (Button) mSplashDialog.findViewById(R.id.research_do_log_button);
2424331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge        doLogButton.setOnClickListener(new OnClickListener() {
2434331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge            @Override
2444331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge            public void onClick(View v) {
2454331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge                onUserLoggingElection(true);
2464331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge                mSplashDialog.dismiss();
2474331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge            }
2484331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge        });
2494331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge        mSplashDialog.show();
2504331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge    }
2514331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge
2524331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge    public void onUserLoggingElection(final boolean enableLogging) {
2534331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge        setLoggingAllowed(enableLogging);
2544331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge        if (mPrefs == null) {
2554331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge            return;
2564331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge        }
2574331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge        final Editor e = mPrefs.edit();
2584331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge        e.putBoolean(PREF_RESEARCH_HAS_SEEN_SPLASH, true);
2594331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge        e.apply();
2604331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge    }
2614331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge
262223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge    private File createLogFile(File filesDir) {
263223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge        final StringBuilder sb = new StringBuilder();
264223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge        sb.append(FILENAME_PREFIX).append('-');
265223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge        sb.append(mUUIDString).append('-');
266223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge        sb.append(TIMESTAMP_DATEFORMAT.format(new Date()));
267223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge        sb.append(FILENAME_SUFFIX);
268223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge        return new File(filesDir, sb.toString());
26907cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    }
270b8e2ae3bc312269897057fccc34cd736c05bcc90Kurt Partridge
2710df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge    private void start() {
2724331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge        maybeShowSplashScreen();
2730df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge        updateSuspendedState();
2740df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge        requestIndicatorRedraw();
2750df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge        if (!isAllowedToLog()) {
276724bc479f7d796d6ce5d5e200216bea855b818b2Kurt Partridge            // Log.w(TAG, "not in usability mode; not logging");
277724bc479f7d796d6ce5d5e200216bea855b818b2Kurt Partridge            return;
278724bc479f7d796d6ce5d5e200216bea855b818b2Kurt Partridge        }
27907cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge        if (mFilesDir == null || !mFilesDir.exists()) {
28007cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge            Log.w(TAG, "IME storage directory does not exist.  Cannot start logging.");
281223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge            return;
282223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge        }
283223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge        try {
2840df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge            if (mMainResearchLog == null || !mMainResearchLog.isAlive()) {
2850df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge                mMainResearchLog = new ResearchLog(createLogFile(mFilesDir));
2860df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge            }
287223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge            mMainResearchLog.start();
288223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge            if (mIntentionalResearchLog == null || !mIntentionalResearchLog.isAlive()) {
289223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge                mIntentionalResearchLog = new ResearchLog(createLogFile(mFilesDir));
290b8e2ae3bc312269897057fccc34cd736c05bcc90Kurt Partridge            }
291223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge            mIntentionalResearchLog.start();
292223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge        } catch (IOException e) {
293223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge            Log.w(TAG, "Could not start ResearchLogger.");
294b8e2ae3bc312269897057fccc34cd736c05bcc90Kurt Partridge        }
295d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge    }
296d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge
2970df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge    /* package */ void stop() {
298223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge        if (mMainResearchLog != null) {
299223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge            mMainResearchLog.stop();
300223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge        }
3010df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge        if (mIntentionalResearchLog != null) {
3020df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge            mIntentionalResearchLog.stop();
3030df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge        }
3040df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge    }
3050df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge
3060df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge    private void setLoggingAllowed(boolean enableLogging) {
3070df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge        if (mPrefs == null) {
3080df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge            return;
3090df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge        }
3100df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge        Editor e = mPrefs.edit();
3110df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge        e.putBoolean(PREF_USABILITY_STUDY_MODE, enableLogging);
3120df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge        e.apply();
3130df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge        sIsLogging = enableLogging;
314223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge    }
315223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge
316223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge    public boolean abort() {
317223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge        boolean didAbortMainLog = false;
318223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge        if (mMainResearchLog != null) {
319223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge            mMainResearchLog.abort();
32048a7681e064ae259b840f0e757da2d716043d893Kurt Partridge            try {
321223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge                mMainResearchLog.waitUntilStopped(ABORT_TIMEOUT_IN_MS);
32207cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge            } catch (InterruptedException e) {
323223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge                // interrupted early.  carry on.
324223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge            }
325223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge            if (mMainResearchLog.isAbortSuccessful()) {
326223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge                didAbortMainLog = true;
32748a7681e064ae259b840f0e757da2d716043d893Kurt Partridge            }
3280df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge            mMainResearchLog = null;
329d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge        }
330223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge        boolean didAbortIntentionalLog = false;
331223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge        if (mIntentionalResearchLog != null) {
332223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge            mIntentionalResearchLog.abort();
333724bc479f7d796d6ce5d5e200216bea855b818b2Kurt Partridge            try {
334223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge                mIntentionalResearchLog.waitUntilStopped(ABORT_TIMEOUT_IN_MS);
335223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge            } catch (InterruptedException e) {
336223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge                // interrupted early.  carry on.
337223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge            }
338223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge            if (mIntentionalResearchLog.isAbortSuccessful()) {
339223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge                didAbortIntentionalLog = true;
340724bc479f7d796d6ce5d5e200216bea855b818b2Kurt Partridge            }
3410df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge            mIntentionalResearchLog = null;
342724bc479f7d796d6ce5d5e200216bea855b818b2Kurt Partridge        }
343223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge        return didAbortMainLog && didAbortIntentionalLog;
344724bc479f7d796d6ce5d5e200216bea855b818b2Kurt Partridge    }
345724bc479f7d796d6ce5d5e200216bea855b818b2Kurt Partridge
346223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge    /* package */ void flush() {
347223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge        if (mMainResearchLog != null) {
348223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge            mMainResearchLog.flush();
349223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge        }
350223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge    }
351223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge
3520df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge    private void restart() {
3530df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge        stop();
3540df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge        start();
3550df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge    }
3560df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge
3570df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge    private long mResumeTime = 0L;
3580df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge    private void suspendLoggingUntil(long time) {
3590df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge        mIsLoggingSuspended = true;
3600df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge        mResumeTime = time;
3610df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge        requestIndicatorRedraw();
3620df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge    }
3630df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge
3640df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge    private void resumeLogging() {
3650df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge        mResumeTime = 0L;
3660df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge        updateSuspendedState();
3670df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge        requestIndicatorRedraw();
3680df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge        if (isAllowedToLog()) {
3690df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge            restart();
3700df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge        }
3710df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge    }
3720df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge
3730df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge    private void updateSuspendedState() {
3740df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge        final long time = System.currentTimeMillis();
3750df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge        if (time > mResumeTime) {
3760df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge            mIsLoggingSuspended = false;
3770df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge        }
3780df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge    }
3790df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge
38007cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    @Override
38107cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
38207cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge        if (key == null || prefs == null) {
38307cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge            return;
384d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge        }
38507cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge        sIsLogging = prefs.getBoolean(PREF_USABILITY_STUDY_MODE, false);
386724bc479f7d796d6ce5d5e200216bea855b818b2Kurt Partridge        if (sIsLogging == false) {
387724bc479f7d796d6ce5d5e200216bea855b818b2Kurt Partridge            abort();
388724bc479f7d796d6ce5d5e200216bea855b818b2Kurt Partridge        }
3890df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge        requestIndicatorRedraw();
390724bc479f7d796d6ce5d5e200216bea855b818b2Kurt Partridge    }
391724bc479f7d796d6ce5d5e200216bea855b818b2Kurt Partridge
3926b966160ac8570271547bf63217efa5e228d4accKurt Partridge    public void presentResearchDialog(final LatinIME latinIME) {
3933c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge        if (mInFeedbackDialog) {
3943c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge            Toast.makeText(latinIME, R.string.research_please_exit_feedback_form,
3953c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge                    Toast.LENGTH_LONG).show();
3963c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge            return;
3973c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge        }
398724bc479f7d796d6ce5d5e200216bea855b818b2Kurt Partridge        final CharSequence title = latinIME.getString(R.string.english_ime_research_log);
3990df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge        final boolean showEnable = mIsLoggingSuspended || !sIsLogging;
400724bc479f7d796d6ce5d5e200216bea855b818b2Kurt Partridge        final CharSequence[] items = new CharSequence[] {
4013c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge                latinIME.getString(R.string.research_feedback_menu_option),
4023c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge                showEnable ? latinIME.getString(R.string.research_enable_session_logging) :
4033c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge                        latinIME.getString(R.string.research_do_not_log_this_session)
404724bc479f7d796d6ce5d5e200216bea855b818b2Kurt Partridge        };
405724bc479f7d796d6ce5d5e200216bea855b818b2Kurt Partridge        final DialogInterface.OnClickListener listener = new DialogInterface.OnClickListener() {
406724bc479f7d796d6ce5d5e200216bea855b818b2Kurt Partridge            @Override
407724bc479f7d796d6ce5d5e200216bea855b818b2Kurt Partridge            public void onClick(DialogInterface di, int position) {
408724bc479f7d796d6ce5d5e200216bea855b818b2Kurt Partridge                di.dismiss();
409724bc479f7d796d6ce5d5e200216bea855b818b2Kurt Partridge                switch (position) {
410724bc479f7d796d6ce5d5e200216bea855b818b2Kurt Partridge                    case 0:
4113c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge                        presentFeedbackDialog(latinIME);
412724bc479f7d796d6ce5d5e200216bea855b818b2Kurt Partridge                        break;
413724bc479f7d796d6ce5d5e200216bea855b818b2Kurt Partridge                    case 1:
4140df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge                        if (showEnable) {
4150df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge                            if (!sIsLogging) {
4160df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge                                setLoggingAllowed(true);
4170df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge                            }
4180df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge                            resumeLogging();
4193c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge                            Toast.makeText(latinIME,
4203c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge                                    R.string.research_notify_session_logging_enabled,
4210df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge                                    Toast.LENGTH_LONG).show();
422724bc479f7d796d6ce5d5e200216bea855b818b2Kurt Partridge                        } else {
423223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge                            Toast toast = Toast.makeText(latinIME,
4243c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge                                    R.string.research_notify_session_log_deleting,
4253c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge                                    Toast.LENGTH_LONG);
426223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge                            toast.show();
427223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge                            boolean isLogDeleted = abort();
4280df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge                            final long currentTime = System.currentTimeMillis();
4290df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge                            final long resumeTime = currentTime + 1000 * 60 *
4300df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge                                    SUSPEND_DURATION_IN_MINUTES;
4310df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge                            suspendLoggingUntil(resumeTime);
432223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge                            toast.cancel();
4333c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge                            Toast.makeText(latinIME, R.string.research_notify_logging_suspended,
4340df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge                                    Toast.LENGTH_LONG).show();
435223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge                        }
436223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge                        break;
437724bc479f7d796d6ce5d5e200216bea855b818b2Kurt Partridge                }
438724bc479f7d796d6ce5d5e200216bea855b818b2Kurt Partridge            }
439223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge
440724bc479f7d796d6ce5d5e200216bea855b818b2Kurt Partridge        };
441724bc479f7d796d6ce5d5e200216bea855b818b2Kurt Partridge        final AlertDialog.Builder builder = new AlertDialog.Builder(latinIME)
442724bc479f7d796d6ce5d5e200216bea855b818b2Kurt Partridge                .setItems(items, listener)
443724bc479f7d796d6ce5d5e200216bea855b818b2Kurt Partridge                .setTitle(title);
444724bc479f7d796d6ce5d5e200216bea855b818b2Kurt Partridge        latinIME.showOptionDialog(builder.create());
445d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge    }
446d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge
4473c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge    private boolean mInFeedbackDialog = false;
4483c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge    public void presentFeedbackDialog(LatinIME latinIME) {
4493c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge        mInFeedbackDialog = true;
4503c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge        latinIME.launchKeyboardedDialogActivity(FeedbackActivity.class);
4513c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge    }
4523c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge
4533c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge    private ResearchLog mFeedbackLog;
4543c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge    private List<LogUnit> mFeedbackQueue;
4553c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge    private ResearchLog mSavedMainResearchLog;
4563c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge    private ResearchLog mSavedIntentionalResearchLog;
4573c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge    private List<LogUnit> mSavedIntentionalResearchLogQueue;
4583c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge
4593c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge    private void saveLogsForFeedback() {
4603c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge        mFeedbackLog = mIntentionalResearchLog;
4613c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge        if (mIntentionalResearchLogQueue != null) {
4623c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge            mFeedbackQueue = new ArrayList<LogUnit>(mIntentionalResearchLogQueue);
4633c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge        } else {
4643c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge            mFeedbackQueue = null;
4653c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge        }
4663c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge        mSavedMainResearchLog = mMainResearchLog;
4673c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge        mSavedIntentionalResearchLog = mIntentionalResearchLog;
4683c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge        mSavedIntentionalResearchLogQueue = mIntentionalResearchLogQueue;
4693c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge
4703c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge        mMainResearchLog = null;
4713c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge        mIntentionalResearchLog = null;
4723c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge        mIntentionalResearchLogQueue = new ArrayList<LogUnit>();
4733c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge    }
4743c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge
4753c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge    private static final int LOG_DRAIN_TIMEOUT_IN_MS = 1000 * 5;
4763c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge    public void sendFeedback(final String feedbackContents, final boolean includeHistory) {
4773c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge        if (includeHistory && mFeedbackLog != null) {
4783c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge            try {
4793c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge                LogUnit headerLogUnit = new LogUnit();
4803c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge                headerLogUnit.addLogAtom(EVENTKEYS_INTENTIONAL_LOG, EVENTKEYS_NULLVALUES, false);
4813c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge                mFeedbackLog.publishAllEvents(headerLogUnit);
4823c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge                for (LogUnit logUnit : mFeedbackQueue) {
4833c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge                    mFeedbackLog.publishAllEvents(logUnit);
4843c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge                }
4853c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge                userFeedback(mFeedbackLog, feedbackContents);
4863c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge                mFeedbackLog.stop();
4873c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge                try {
4883c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge                    mFeedbackLog.waitUntilStopped(LOG_DRAIN_TIMEOUT_IN_MS);
4893c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge                } catch (InterruptedException e) {
4903c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge                    e.printStackTrace();
4913c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge                }
4923c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge                mIntentionalResearchLog = new ResearchLog(createLogFile(mFilesDir));
4933c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge                mIntentionalResearchLog.start();
4943c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge            } catch (IOException e) {
4953c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge                e.printStackTrace();
4963c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge            } finally {
4973c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge                mIntentionalResearchLogQueue.clear();
4983c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge            }
4993c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge            mResearchLogUploader.uploadNow(null);
5003c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge        } else {
5013c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge            // create a separate ResearchLog just for feedback
5023c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge            final ResearchLog feedbackLog = new ResearchLog(createLogFile(mFilesDir));
5033c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge            try {
5043c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge                feedbackLog.start();
5053c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge                userFeedback(feedbackLog, feedbackContents);
5063c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge                feedbackLog.stop();
5073c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge                feedbackLog.waitUntilStopped(LOG_DRAIN_TIMEOUT_IN_MS);
5083c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge                mResearchLogUploader.uploadNow(null);
5093c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge            } catch (IOException e) {
5103c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge                e.printStackTrace();
5113c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge            } catch (InterruptedException e) {
5123c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge                e.printStackTrace();
5133c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge            }
5143c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge        }
5153c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge    }
5163c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge
5173c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge    public void onLeavingSendFeedbackDialog() {
5183c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge        mInFeedbackDialog = false;
5193c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge        mMainResearchLog = mSavedMainResearchLog;
5203c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge        mIntentionalResearchLog = mSavedIntentionalResearchLog;
5213c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge        mIntentionalResearchLogQueue = mSavedIntentionalResearchLogQueue;
5223c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge    }
5233c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge
5246080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge    public void initSuggest(Suggest suggest) {
5256080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge        mSuggest = suggest;
5266080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge    }
5276080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge
5281cef91e4818790ea5419a6ad9ff6e36ac535c763Kurt Partridge    private void setIsPasswordView(boolean isPasswordView) {
5291cef91e4818790ea5419a6ad9ff6e36ac535c763Kurt Partridge        mIsPasswordView = isPasswordView;
5301cef91e4818790ea5419a6ad9ff6e36ac535c763Kurt Partridge    }
5311cef91e4818790ea5419a6ad9ff6e36ac535c763Kurt Partridge
5321cef91e4818790ea5419a6ad9ff6e36ac535c763Kurt Partridge    private boolean isAllowedToLog() {
5330df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge        return !mIsPasswordView && !mIsLoggingSuspended && sIsLogging;
534223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge    }
535223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge
536223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge    public void requestIndicatorRedraw() {
5374fa6e5726041a22db4f15d99521ea06419401946Kurt Partridge        if (!IS_SHOWING_INDICATOR) {
5384fa6e5726041a22db4f15d99521ea06419401946Kurt Partridge            return;
5394fa6e5726041a22db4f15d99521ea06419401946Kurt Partridge        }
5404fa6e5726041a22db4f15d99521ea06419401946Kurt Partridge        if (mKeyboardSwitcher == null) {
5414fa6e5726041a22db4f15d99521ea06419401946Kurt Partridge            return;
5424fa6e5726041a22db4f15d99521ea06419401946Kurt Partridge        }
5434fa6e5726041a22db4f15d99521ea06419401946Kurt Partridge        final KeyboardView keyboardView = mKeyboardSwitcher.getKeyboardView();
5444fa6e5726041a22db4f15d99521ea06419401946Kurt Partridge        if (keyboardView == null) {
5454fa6e5726041a22db4f15d99521ea06419401946Kurt Partridge            return;
5464fa6e5726041a22db4f15d99521ea06419401946Kurt Partridge        }
5474fa6e5726041a22db4f15d99521ea06419401946Kurt Partridge        keyboardView.invalidateAllKeys();
5484fa6e5726041a22db4f15d99521ea06419401946Kurt Partridge    }
5494fa6e5726041a22db4f15d99521ea06419401946Kurt Partridge
5504fa6e5726041a22db4f15d99521ea06419401946Kurt Partridge
5514fa6e5726041a22db4f15d99521ea06419401946Kurt Partridge    public void paintIndicator(KeyboardView view, Paint paint, Canvas canvas, int width,
5524fa6e5726041a22db4f15d99521ea06419401946Kurt Partridge            int height) {
5534fa6e5726041a22db4f15d99521ea06419401946Kurt Partridge        // TODO: Reimplement using a keyboard background image specific to the ResearchLogger
5544fa6e5726041a22db4f15d99521ea06419401946Kurt Partridge        // and remove this method.
555c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka        // The check for MainKeyboardView ensures that a red border is only placed around
5564fa6e5726041a22db4f15d99521ea06419401946Kurt Partridge        // the main keyboard, not every keyboard.
557c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka        if (IS_SHOWING_INDICATOR && isAllowedToLog() && view instanceof MainKeyboardView) {
5584fa6e5726041a22db4f15d99521ea06419401946Kurt Partridge            final int savedColor = paint.getColor();
5594fa6e5726041a22db4f15d99521ea06419401946Kurt Partridge            paint.setColor(Color.RED);
5604fa6e5726041a22db4f15d99521ea06419401946Kurt Partridge            final Style savedStyle = paint.getStyle();
5614fa6e5726041a22db4f15d99521ea06419401946Kurt Partridge            paint.setStyle(Style.STROKE);
5624fa6e5726041a22db4f15d99521ea06419401946Kurt Partridge            final float savedStrokeWidth = paint.getStrokeWidth();
5634fa6e5726041a22db4f15d99521ea06419401946Kurt Partridge            if (IS_SHOWING_INDICATOR_CLEARLY) {
5644fa6e5726041a22db4f15d99521ea06419401946Kurt Partridge                paint.setStrokeWidth(5);
5654fa6e5726041a22db4f15d99521ea06419401946Kurt Partridge                canvas.drawRect(0, 0, width, height, paint);
5664fa6e5726041a22db4f15d99521ea06419401946Kurt Partridge            } else {
5674fa6e5726041a22db4f15d99521ea06419401946Kurt Partridge                // Put a tiny red dot on the screen so a knowledgeable user can check whether
5684fa6e5726041a22db4f15d99521ea06419401946Kurt Partridge                // it is enabled.  The dot is actually a zero-width, zero-height rectangle,
5694fa6e5726041a22db4f15d99521ea06419401946Kurt Partridge                // placed at the lower-right corner of the canvas, painted with a non-zero border
5704fa6e5726041a22db4f15d99521ea06419401946Kurt Partridge                // width.
5714fa6e5726041a22db4f15d99521ea06419401946Kurt Partridge                paint.setStrokeWidth(3);
5724fa6e5726041a22db4f15d99521ea06419401946Kurt Partridge                canvas.drawRect(width, height, width, height, paint);
5730df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge            }
5744fa6e5726041a22db4f15d99521ea06419401946Kurt Partridge            paint.setColor(savedColor);
5754fa6e5726041a22db4f15d99521ea06419401946Kurt Partridge            paint.setStyle(savedStyle);
5764fa6e5726041a22db4f15d99521ea06419401946Kurt Partridge            paint.setStrokeWidth(savedStrokeWidth);
577223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge        }
5781cef91e4818790ea5419a6ad9ff6e36ac535c763Kurt Partridge    }
5791cef91e4818790ea5419a6ad9ff6e36ac535c763Kurt Partridge
58007cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    private static final String CURRENT_TIME_KEY = "_ct";
58107cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    private static final String UPTIME_KEY = "_ut";
58207cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    private static final String EVENT_TYPE_KEY = "_ty";
58307cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    private static final Object[] EVENTKEYS_NULLVALUES = {};
584d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge
5856080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge    private LogUnit mCurrentLogUnit = new LogUnit();
5866080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge
58707cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    /**
5886080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge     * Buffer a research log event, flagging it as privacy-sensitive.
58907cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge     *
5906080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge     * This event contains potentially private information.  If the word that this event is a part
5916080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge     * of is determined to be privacy-sensitive, then this event should not be included in the
5926080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge     * output log.  The system waits to output until the containing word is known.
59307cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge     *
59407cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge     * @param keys an array containing a descriptive name for the event, followed by the keys
59507cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge     * @param values an array of values, either a String or Number.  length should be one
59607cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge     * less than the keys array
59707cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge     */
5986080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge    private synchronized void enqueuePotentiallyPrivateEvent(final String[] keys,
5996080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge            final Object[] values) {
60007cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge        assert values.length + 1 == keys.length;
601223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge        if (isAllowedToLog()) {
602223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge            mCurrentLogUnit.addLogAtom(keys, values, true);
603223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge        }
6046080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge    }
6056080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge
6066080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge    /**
6076080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge     * Buffer a research log event, flaggint it as not privacy-sensitive.
6086080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge     *
6096080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge     * This event contains no potentially private information.  Even if the word that this event
6106080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge     * is privacy-sensitive, this event can still safely be sent to the output log.  The system
6116080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge     * waits until the containing word is known so that this event can be written in the proper
6126080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge     * temporal order with other events that may be privacy sensitive.
6136080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge     *
6146080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge     * @param keys an array containing a descriptive name for the event, followed by the keys
6156080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge     * @param values an array of values, either a String or Number.  length should be one
6166080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge     * less than the keys array
6176080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge     */
6186080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge    private synchronized void enqueueEvent(final String[] keys, final Object[] values) {
6196080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge        assert values.length + 1 == keys.length;
620223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge        if (isAllowedToLog()) {
621223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge            mCurrentLogUnit.addLogAtom(keys, values, false);
622223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge        }
6236080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge    }
6246080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge
625e961188e9fd4f4365c6c745c8d3d838dd7dfe6a0Kurt Partridge    // Used to track how often words are logged.  Too-frequent logging can leak
626e961188e9fd4f4365c6c745c8d3d838dd7dfe6a0Kurt Partridge    // semantics, disclosing private data.
627e961188e9fd4f4365c6c745c8d3d838dd7dfe6a0Kurt Partridge    /* package for test */ static class LoggingFrequencyState {
628e961188e9fd4f4365c6c745c8d3d838dd7dfe6a0Kurt Partridge        private static final int DEFAULT_WORD_LOG_FREQUENCY = 10;
629e961188e9fd4f4365c6c745c8d3d838dd7dfe6a0Kurt Partridge        private int mWordsRemainingToSkip;
630e961188e9fd4f4365c6c745c8d3d838dd7dfe6a0Kurt Partridge        private final int mFrequency;
631e961188e9fd4f4365c6c745c8d3d838dd7dfe6a0Kurt Partridge
632e961188e9fd4f4365c6c745c8d3d838dd7dfe6a0Kurt Partridge        /**
633e961188e9fd4f4365c6c745c8d3d838dd7dfe6a0Kurt Partridge         * Tracks how often words may be uploaded.
634e961188e9fd4f4365c6c745c8d3d838dd7dfe6a0Kurt Partridge         *
635e961188e9fd4f4365c6c745c8d3d838dd7dfe6a0Kurt Partridge         * @param frequency 1=Every word, 2=Every other word, etc.
636e961188e9fd4f4365c6c745c8d3d838dd7dfe6a0Kurt Partridge         */
637e961188e9fd4f4365c6c745c8d3d838dd7dfe6a0Kurt Partridge        public LoggingFrequencyState(int frequency) {
638e961188e9fd4f4365c6c745c8d3d838dd7dfe6a0Kurt Partridge            mFrequency = frequency;
639e961188e9fd4f4365c6c745c8d3d838dd7dfe6a0Kurt Partridge            mWordsRemainingToSkip = mFrequency;
640e961188e9fd4f4365c6c745c8d3d838dd7dfe6a0Kurt Partridge        }
641e961188e9fd4f4365c6c745c8d3d838dd7dfe6a0Kurt Partridge
642e961188e9fd4f4365c6c745c8d3d838dd7dfe6a0Kurt Partridge        public void onWordLogged() {
643e961188e9fd4f4365c6c745c8d3d838dd7dfe6a0Kurt Partridge            mWordsRemainingToSkip = mFrequency;
644e961188e9fd4f4365c6c745c8d3d838dd7dfe6a0Kurt Partridge        }
645e961188e9fd4f4365c6c745c8d3d838dd7dfe6a0Kurt Partridge
646e961188e9fd4f4365c6c745c8d3d838dd7dfe6a0Kurt Partridge        public void onWordNotLogged() {
647e961188e9fd4f4365c6c745c8d3d838dd7dfe6a0Kurt Partridge            if (mWordsRemainingToSkip > 1) {
648e961188e9fd4f4365c6c745c8d3d838dd7dfe6a0Kurt Partridge                mWordsRemainingToSkip--;
649e961188e9fd4f4365c6c745c8d3d838dd7dfe6a0Kurt Partridge            }
650e961188e9fd4f4365c6c745c8d3d838dd7dfe6a0Kurt Partridge        }
651e961188e9fd4f4365c6c745c8d3d838dd7dfe6a0Kurt Partridge
652e961188e9fd4f4365c6c745c8d3d838dd7dfe6a0Kurt Partridge        public boolean isSafeToLog() {
653e961188e9fd4f4365c6c745c8d3d838dd7dfe6a0Kurt Partridge            return mWordsRemainingToSkip <= 1;
654e961188e9fd4f4365c6c745c8d3d838dd7dfe6a0Kurt Partridge        }
655e961188e9fd4f4365c6c745c8d3d838dd7dfe6a0Kurt Partridge    }
656e961188e9fd4f4365c6c745c8d3d838dd7dfe6a0Kurt Partridge
657e961188e9fd4f4365c6c745c8d3d838dd7dfe6a0Kurt Partridge    /* package for test */ LoggingFrequencyState mLoggingFrequencyState =
658e961188e9fd4f4365c6c745c8d3d838dd7dfe6a0Kurt Partridge            new LoggingFrequencyState(LoggingFrequencyState.DEFAULT_WORD_LOG_FREQUENCY);
659e961188e9fd4f4365c6c745c8d3d838dd7dfe6a0Kurt Partridge
66033d9f9b6dbafba97d5f46b021727b9d797906baaKurt Partridge    /* package for test */ boolean isPrivacyThreat(String word) {
661e961188e9fd4f4365c6c745c8d3d838dd7dfe6a0Kurt Partridge        // Current checks:
662e961188e9fd4f4365c6c745c8d3d838dd7dfe6a0Kurt Partridge        // - Word not in dictionary
663e961188e9fd4f4365c6c745c8d3d838dd7dfe6a0Kurt Partridge        // - Word contains numbers
664e961188e9fd4f4365c6c745c8d3d838dd7dfe6a0Kurt Partridge        // - Privacy-safe word not logged recently
66533d9f9b6dbafba97d5f46b021727b9d797906baaKurt Partridge        if (TextUtils.isEmpty(word)) {
66633d9f9b6dbafba97d5f46b021727b9d797906baaKurt Partridge            return false;
66733d9f9b6dbafba97d5f46b021727b9d797906baaKurt Partridge        }
668e961188e9fd4f4365c6c745c8d3d838dd7dfe6a0Kurt Partridge        if (!mLoggingFrequencyState.isSafeToLog()) {
669e961188e9fd4f4365c6c745c8d3d838dd7dfe6a0Kurt Partridge            return true;
670e961188e9fd4f4365c6c745c8d3d838dd7dfe6a0Kurt Partridge        }
67133d9f9b6dbafba97d5f46b021727b9d797906baaKurt Partridge        final int length = word.length();
67233d9f9b6dbafba97d5f46b021727b9d797906baaKurt Partridge        boolean hasLetter = false;
67333d9f9b6dbafba97d5f46b021727b9d797906baaKurt Partridge        for (int i = 0; i < length; i = word.offsetByCodePoints(i, 1)) {
67433d9f9b6dbafba97d5f46b021727b9d797906baaKurt Partridge            final int codePoint = Character.codePointAt(word, i);
67533d9f9b6dbafba97d5f46b021727b9d797906baaKurt Partridge            if (Character.isDigit(codePoint)) {
67633d9f9b6dbafba97d5f46b021727b9d797906baaKurt Partridge                return true;
67733d9f9b6dbafba97d5f46b021727b9d797906baaKurt Partridge            }
67833d9f9b6dbafba97d5f46b021727b9d797906baaKurt Partridge            if (Character.isLetter(codePoint)) {
67933d9f9b6dbafba97d5f46b021727b9d797906baaKurt Partridge                hasLetter = true;
68033d9f9b6dbafba97d5f46b021727b9d797906baaKurt Partridge                break; // Word may contain digits, but will only be allowed if in the dictionary.
68133d9f9b6dbafba97d5f46b021727b9d797906baaKurt Partridge            }
68233d9f9b6dbafba97d5f46b021727b9d797906baaKurt Partridge        }
68333d9f9b6dbafba97d5f46b021727b9d797906baaKurt Partridge        if (hasLetter) {
68433d9f9b6dbafba97d5f46b021727b9d797906baaKurt Partridge            if (mDictionary == null && mSuggest != null && mSuggest.hasMainDictionary()) {
68533d9f9b6dbafba97d5f46b021727b9d797906baaKurt Partridge                mDictionary = mSuggest.getMainDictionary();
68633d9f9b6dbafba97d5f46b021727b9d797906baaKurt Partridge            }
68733d9f9b6dbafba97d5f46b021727b9d797906baaKurt Partridge            if (mDictionary == null) {
68833d9f9b6dbafba97d5f46b021727b9d797906baaKurt Partridge                // Can't access dictionary.  Assume privacy threat.
68933d9f9b6dbafba97d5f46b021727b9d797906baaKurt Partridge                return true;
69033d9f9b6dbafba97d5f46b021727b9d797906baaKurt Partridge            }
69133d9f9b6dbafba97d5f46b021727b9d797906baaKurt Partridge            return !(mDictionary.isValidWord(word));
69233d9f9b6dbafba97d5f46b021727b9d797906baaKurt Partridge        }
69333d9f9b6dbafba97d5f46b021727b9d797906baaKurt Partridge        // No letters, no numbers.  Punctuation, space, or something else.
69433d9f9b6dbafba97d5f46b021727b9d797906baaKurt Partridge        return false;
6956080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge    }
6966080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge
697e961188e9fd4f4365c6c745c8d3d838dd7dfe6a0Kurt Partridge    private void onWordComplete(String word) {
698223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge        if (isPrivacyThreat(word)) {
699223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge            publishLogUnit(mCurrentLogUnit, true);
700e961188e9fd4f4365c6c745c8d3d838dd7dfe6a0Kurt Partridge            mLoggingFrequencyState.onWordNotLogged();
701e961188e9fd4f4365c6c745c8d3d838dd7dfe6a0Kurt Partridge        } else {
702223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge            publishLogUnit(mCurrentLogUnit, false);
703e961188e9fd4f4365c6c745c8d3d838dd7dfe6a0Kurt Partridge            mLoggingFrequencyState.onWordLogged();
704e961188e9fd4f4365c6c745c8d3d838dd7dfe6a0Kurt Partridge        }
705223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge        mCurrentLogUnit = new LogUnit();
706e961188e9fd4f4365c6c745c8d3d838dd7dfe6a0Kurt Partridge    }
707e961188e9fd4f4365c6c745c8d3d838dd7dfe6a0Kurt Partridge
708223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge    private void publishLogUnit(LogUnit logUnit, boolean isPrivacySensitive) {
7090df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge        if (!isAllowedToLog()) {
7100df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge            return;
7110df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge        }
7120df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge        if (mMainResearchLog == null) {
7130df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge            return;
7140df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge        }
715223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge        if (isPrivacySensitive) {
716223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge            mMainResearchLog.publishPublicEvents(logUnit);
717223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge        } else {
718223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge            mMainResearchLog.publishAllEvents(logUnit);
7196080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge        }
720223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge        mIntentionalResearchLogQueue.add(logUnit);
7216080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge    }
7226080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge
723223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge    /* package */ void publishCurrentLogUnit(ResearchLog researchLog, boolean isPrivacySensitive) {
724223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge        publishLogUnit(mCurrentLogUnit, isPrivacySensitive);
7256080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge    }
7266080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge
727223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge    static class LogUnit {
7286080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge        private final List<String[]> mKeysList = new ArrayList<String[]>();
7296080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge        private final List<Object[]> mValuesList = new ArrayList<Object[]>();
7306080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge        private final List<Boolean> mIsPotentiallyPrivate = new ArrayList<Boolean>();
7316080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge
7326080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge        private void addLogAtom(final String[] keys, final Object[] values,
7336080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge                final Boolean isPotentiallyPrivate) {
7346080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge            mKeysList.add(keys);
7356080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge            mValuesList.add(values);
7366080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge            mIsPotentiallyPrivate.add(isPotentiallyPrivate);
7376080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge        }
7386080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge
739223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge        public void publishPublicEventsTo(ResearchLog researchLog) {
740223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge            final int size = mKeysList.size();
741223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge            for (int i = 0; i < size; i++) {
742223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge                if (!mIsPotentiallyPrivate.get(i)) {
743223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge                    researchLog.outputEvent(mKeysList.get(i), mValuesList.get(i));
744223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge                }
745223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge            }
7466080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge        }
7476080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge
748223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge        public void publishAllEventsTo(ResearchLog researchLog) {
749223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge            final int size = mKeysList.size();
750223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge            for (int i = 0; i < size; i++) {
751223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge                researchLog.outputEvent(mKeysList.get(i), mValuesList.get(i));
7526080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge            }
75307cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge        }
75407cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    }
75507cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge
756a696781c2b18d8002275aa89e07fa7379661d025Kurt Partridge    private static int scrubDigitFromCodePoint(int codePoint) {
757a696781c2b18d8002275aa89e07fa7379661d025Kurt Partridge        return Character.isDigit(codePoint) ? DIGIT_REPLACEMENT_CODEPOINT : codePoint;
758a696781c2b18d8002275aa89e07fa7379661d025Kurt Partridge    }
759a696781c2b18d8002275aa89e07fa7379661d025Kurt Partridge
760a696781c2b18d8002275aa89e07fa7379661d025Kurt Partridge    /* package for test */ static String scrubDigitsFromString(String s) {
761a696781c2b18d8002275aa89e07fa7379661d025Kurt Partridge        StringBuilder sb = null;
762a696781c2b18d8002275aa89e07fa7379661d025Kurt Partridge        final int length = s.length();
763a696781c2b18d8002275aa89e07fa7379661d025Kurt Partridge        for (int i = 0; i < length; i = s.offsetByCodePoints(i, 1)) {
76433d9f9b6dbafba97d5f46b021727b9d797906baaKurt Partridge            final int codePoint = Character.codePointAt(s, i);
765a696781c2b18d8002275aa89e07fa7379661d025Kurt Partridge            if (Character.isDigit(codePoint)) {
766a696781c2b18d8002275aa89e07fa7379661d025Kurt Partridge                if (sb == null) {
767a696781c2b18d8002275aa89e07fa7379661d025Kurt Partridge                    sb = new StringBuilder(length);
768a696781c2b18d8002275aa89e07fa7379661d025Kurt Partridge                    sb.append(s.substring(0, i));
769a696781c2b18d8002275aa89e07fa7379661d025Kurt Partridge                }
770a696781c2b18d8002275aa89e07fa7379661d025Kurt Partridge                sb.appendCodePoint(DIGIT_REPLACEMENT_CODEPOINT);
771a696781c2b18d8002275aa89e07fa7379661d025Kurt Partridge            } else {
772a696781c2b18d8002275aa89e07fa7379661d025Kurt Partridge                if (sb != null) {
773a696781c2b18d8002275aa89e07fa7379661d025Kurt Partridge                    sb.appendCodePoint(codePoint);
774a696781c2b18d8002275aa89e07fa7379661d025Kurt Partridge                }
775a696781c2b18d8002275aa89e07fa7379661d025Kurt Partridge            }
776a696781c2b18d8002275aa89e07fa7379661d025Kurt Partridge        }
777a696781c2b18d8002275aa89e07fa7379661d025Kurt Partridge        if (sb == null) {
778a696781c2b18d8002275aa89e07fa7379661d025Kurt Partridge            return s;
779a696781c2b18d8002275aa89e07fa7379661d025Kurt Partridge        } else {
780a696781c2b18d8002275aa89e07fa7379661d025Kurt Partridge            return sb.toString();
781a696781c2b18d8002275aa89e07fa7379661d025Kurt Partridge        }
782a696781c2b18d8002275aa89e07fa7379661d025Kurt Partridge    }
783a696781c2b18d8002275aa89e07fa7379661d025Kurt Partridge
7840df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge    private static String getUUID(final SharedPreferences prefs) {
7850df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge        String uuidString = prefs.getString(PREF_RESEARCH_LOGGER_UUID_STRING, null);
7860df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge        if (null == uuidString) {
7870df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge            UUID uuid = UUID.randomUUID();
7880df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge            uuidString = uuid.toString();
7890df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge            Editor editor = prefs.edit();
7900df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge            editor.putString(PREF_RESEARCH_LOGGER_UUID_STRING, uuidString);
7910df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge            editor.apply();
7920df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge        }
7930df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge        return uuidString;
7940df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge    }
7950df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge
7966080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge    private String scrubWord(String word) {
7976080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge        if (mDictionary == null) {
7986080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge            return WORD_REPLACEMENT_STRING;
7996080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge        }
8006080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge        if (mDictionary.isValidWord(word)) {
8016080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge            return word;
8026080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge        }
8036080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge        return WORD_REPLACEMENT_STRING;
8046080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge    }
8056080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge
8060df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge    // Special methods related to startup, shutdown, logging itself
8070df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge
808223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge    private static final String[] EVENTKEYS_INTENTIONAL_LOG = {
809223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge        "IntentionalLog"
810223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge    };
8110df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge
8120df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge    private static final String[] EVENTKEYS_LATINIME_ONSTARTINPUTVIEWINTERNAL = {
8130df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge        "LatinIMEOnStartInputViewInternal", "uuid", "packageName", "inputType", "imeOptions",
8140df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge        "fieldId", "display", "model", "prefs", "versionCode", "versionName", "outputFormatVersion"
8150df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge    };
8160df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge    public static void latinIME_onStartInputViewInternal(final EditorInfo editorInfo,
8170df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge            final SharedPreferences prefs) {
8180df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge        final ResearchLogger researchLogger = getInstance();
8193c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge        if (researchLogger.mInFeedbackDialog) {
8203c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge            researchLogger.saveLogsForFeedback();
8213c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge        }
8220df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge        researchLogger.start();
8230df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge        if (editorInfo != null) {
8244331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge            final Context context = researchLogger.mInputMethodService;
8250df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge            try {
8260df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge                final PackageInfo packageInfo;
8270df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge                packageInfo = context.getPackageManager().getPackageInfo(context.getPackageName(),
8280df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge                        0);
8290df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge                final Integer versionCode = packageInfo.versionCode;
8300df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge                final String versionName = packageInfo.versionName;
8310df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge                final Object[] values = {
8320df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge                        researchLogger.mUUIDString, editorInfo.packageName,
8330df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge                        Integer.toHexString(editorInfo.inputType),
8340df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge                        Integer.toHexString(editorInfo.imeOptions), editorInfo.fieldId,
8350df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge                        Build.DISPLAY, Build.MODEL, prefs, versionCode, versionName,
8360df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge                        OUTPUT_FORMAT_VERSION
8370df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge                };
8380df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge                researchLogger.enqueueEvent(EVENTKEYS_LATINIME_ONSTARTINPUTVIEWINTERNAL, values);
8390df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge            } catch (NameNotFoundException e) {
8400df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge                e.printStackTrace();
8410df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge            }
8420df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge        }
8430df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge    }
8440df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge
8450df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge    public void latinIME_onFinishInputInternal() {
8460df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge        stop();
8470df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge    }
8480df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge
8490df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge    private static final String[] EVENTKEYS_LATINIME_COMMITTEXT = {
8500df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge        "LatinIMECommitText", "typedWord"
8510df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge    };
8520df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge
8530df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge    public static void latinIME_commitText(final CharSequence typedWord) {
8540df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge        final String scrubbedWord = scrubDigitsFromString(typedWord.toString());
8550df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge        final Object[] values = {
8560df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge            scrubbedWord
8570df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge        };
8580df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge        final ResearchLogger researchLogger = getInstance();
8590df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge        researchLogger.enqueuePotentiallyPrivateEvent(EVENTKEYS_LATINIME_COMMITTEXT, values);
8600df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge        researchLogger.onWordComplete(scrubbedWord);
8610df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge    }
8620df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge
8633c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge    private static final String[] EVENTKEYS_USER_FEEDBACK = {
8643c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge        "UserFeedback", "FeedbackContents"
8653c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge    };
8663c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge
8673c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge    private void userFeedback(ResearchLog researchLog, String feedbackContents) {
8683c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge        // this method is special; it directs the feedbackContents to a particular researchLog
8693c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge        final LogUnit logUnit = new LogUnit();
8703c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge        final Object[] values = {
8713c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge            feedbackContents
8723c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge        };
8733c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge        logUnit.addLogAtom(EVENTKEYS_USER_FEEDBACK, values, false);
8743c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge        researchLog.publishAllEvents(logUnit);
8753c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge    }
8763c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge
8770df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge    // Regular logging methods
8780df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge
879c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka    private static final String[] EVENTKEYS_MAINKEYBOARDVIEW_PROCESSMOTIONEVENT = {
880c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka        "MainKeyboardViewProcessMotionEvent", "action", "eventTime", "id", "x", "y", "size",
88107cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge        "pressure"
88207cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    };
883c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka    public static void mainKeyboardView_processMotionEvent(final MotionEvent me, final int action,
88407cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge            final long eventTime, final int index, final int id, final int x, final int y) {
88507cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge        if (me != null) {
88607cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge            final String actionString;
88707cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge            switch (action) {
88807cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge                case MotionEvent.ACTION_CANCEL: actionString = "CANCEL"; break;
88907cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge                case MotionEvent.ACTION_UP: actionString = "UP"; break;
89007cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge                case MotionEvent.ACTION_DOWN: actionString = "DOWN"; break;
89107cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge                case MotionEvent.ACTION_POINTER_UP: actionString = "POINTER_UP"; break;
89207cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge                case MotionEvent.ACTION_POINTER_DOWN: actionString = "POINTER_DOWN"; break;
89307cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge                case MotionEvent.ACTION_MOVE: actionString = "MOVE"; break;
89407cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge                case MotionEvent.ACTION_OUTSIDE: actionString = "OUTSIDE"; break;
89507cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge                default: actionString = "ACTION_" + action; break;
896d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge            }
89707cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge            final float size = me.getSize(index);
89807cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge            final float pressure = me.getPressure(index);
89907cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge            final Object[] values = {
90007cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge                actionString, eventTime, id, x, y, size, pressure
90107cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge            };
9026080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge            getInstance().enqueuePotentiallyPrivateEvent(
903c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka                    EVENTKEYS_MAINKEYBOARDVIEW_PROCESSMOTIONEVENT, values);
90407cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge        }
905d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge    }
906d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge
90707cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    private static final String[] EVENTKEYS_LATINIME_ONCODEINPUT = {
908f739119f3ff54d7c37b67b873373b236a45e47e4Kurt Partridge        "LatinIMEOnCodeInput", "code", "x", "y"
90907cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    };
91007cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    public static void latinIME_onCodeInput(final int code, final int x, final int y) {
91107cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge        final Object[] values = {
912a696781c2b18d8002275aa89e07fa7379661d025Kurt Partridge            Keyboard.printableCode(scrubDigitFromCodePoint(code)), x, y
91307cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge        };
9146080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge        getInstance().enqueuePotentiallyPrivateEvent(EVENTKEYS_LATINIME_ONCODEINPUT, values);
915d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge    }
916d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge
91707cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    private static final String[] EVENTKEYS_CORRECTION = {
918f739119f3ff54d7c37b67b873373b236a45e47e4Kurt Partridge        "LogCorrection", "subgroup", "before", "after", "position"
91907cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    };
92007cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    public static void logCorrection(final String subgroup, final String before, final String after,
92107cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge            final int position) {
92207cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge        final Object[] values = {
923a696781c2b18d8002275aa89e07fa7379661d025Kurt Partridge            subgroup, scrubDigitsFromString(before), scrubDigitsFromString(after), position
92407cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge        };
9256080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge        getInstance().enqueuePotentiallyPrivateEvent(EVENTKEYS_CORRECTION, values);
926b8e2ae3bc312269897057fccc34cd736c05bcc90Kurt Partridge    }
927b8e2ae3bc312269897057fccc34cd736c05bcc90Kurt Partridge
92807cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    private static final String[] EVENTKEYS_LATINIME_COMMITCURRENTAUTOCORRECTION = {
929f739119f3ff54d7c37b67b873373b236a45e47e4Kurt Partridge        "LatinIMECommitCurrentAutoCorrection", "typedWord", "autoCorrection"
93007cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    };
931d442984e96cc6299c905141e3e32e0a4f55394c8Kurt Partridge    public static void latinIME_commitCurrentAutoCorrection(final String typedWord,
93260adb8757496fecb8f376a80832c176b35e43d06Kurt Partridge            final String autoCorrection) {
93307cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge        final Object[] values = {
934a696781c2b18d8002275aa89e07fa7379661d025Kurt Partridge            scrubDigitsFromString(typedWord), scrubDigitsFromString(autoCorrection)
93507cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge        };
9366080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge        final ResearchLogger researchLogger = getInstance();
9376080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge        researchLogger.enqueuePotentiallyPrivateEvent(
9386080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge                EVENTKEYS_LATINIME_COMMITCURRENTAUTOCORRECTION, values);
93960adb8757496fecb8f376a80832c176b35e43d06Kurt Partridge    }
94060adb8757496fecb8f376a80832c176b35e43d06Kurt Partridge
94107cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    private static final String[] EVENTKEYS_LATINIME_DELETESURROUNDINGTEXT = {
942f739119f3ff54d7c37b67b873373b236a45e47e4Kurt Partridge        "LatinIMEDeleteSurroundingText", "length"
94307cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    };
944d442984e96cc6299c905141e3e32e0a4f55394c8Kurt Partridge    public static void latinIME_deleteSurroundingText(final int length) {
94507cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge        final Object[] values = {
94607cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge            length
94707cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge        };
9486080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge        getInstance().enqueueEvent(EVENTKEYS_LATINIME_DELETESURROUNDINGTEXT, values);
949d442984e96cc6299c905141e3e32e0a4f55394c8Kurt Partridge    }
950d442984e96cc6299c905141e3e32e0a4f55394c8Kurt Partridge
95107cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    private static final String[] EVENTKEYS_LATINIME_DOUBLESPACEAUTOPERIOD = {
952f739119f3ff54d7c37b67b873373b236a45e47e4Kurt Partridge        "LatinIMEDoubleSpaceAutoPeriod"
95307cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    };
954d442984e96cc6299c905141e3e32e0a4f55394c8Kurt Partridge    public static void latinIME_doubleSpaceAutoPeriod() {
9556080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge        getInstance().enqueueEvent(EVENTKEYS_LATINIME_DOUBLESPACEAUTOPERIOD, EVENTKEYS_NULLVALUES);
956d442984e96cc6299c905141e3e32e0a4f55394c8Kurt Partridge    }
957d442984e96cc6299c905141e3e32e0a4f55394c8Kurt Partridge
95807cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    private static final String[] EVENTKEYS_LATINIME_ONDISPLAYCOMPLETIONS = {
959f739119f3ff54d7c37b67b873373b236a45e47e4Kurt Partridge        "LatinIMEOnDisplayCompletions", "applicationSpecifiedCompletions"
96007cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    };
9619bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge    public static void latinIME_onDisplayCompletions(
9629bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge            final CompletionInfo[] applicationSpecifiedCompletions) {
96307cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge        final Object[] values = {
96407cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge            applicationSpecifiedCompletions
96507cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge        };
9666080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge        getInstance().enqueuePotentiallyPrivateEvent(EVENTKEYS_LATINIME_ONDISPLAYCOMPLETIONS,
9676080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge                values);
9689bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge    }
9699bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge
9706b966160ac8570271547bf63217efa5e228d4accKurt Partridge    public static boolean getAndClearLatinIMEExpectingUpdateSelection() {
97107cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge        boolean returnValue = sLatinIMEExpectingUpdateSelection;
97207cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge        sLatinIMEExpectingUpdateSelection = false;
973d67a248de45a698d1009757c9f4e750c77bf35f1Kurt Partridge        return returnValue;
974d67a248de45a698d1009757c9f4e750c77bf35f1Kurt Partridge    }
975d67a248de45a698d1009757c9f4e750c77bf35f1Kurt Partridge
97607cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    private static final String[] EVENTKEYS_LATINIME_ONWINDOWHIDDEN = {
977f739119f3ff54d7c37b67b873373b236a45e47e4Kurt Partridge        "LatinIMEOnWindowHidden", "isTextTruncated", "text"
97807cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    };
979d67a248de45a698d1009757c9f4e750c77bf35f1Kurt Partridge    public static void latinIME_onWindowHidden(final int savedSelectionStart,
980d67a248de45a698d1009757c9f4e750c77bf35f1Kurt Partridge            final int savedSelectionEnd, final InputConnection ic) {
98107cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge        if (ic != null) {
98207cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge            ic.beginBatchEdit();
98307cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge            ic.performContextMenuAction(android.R.id.selectAll);
98407cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge            CharSequence charSequence = ic.getSelectedText(0);
98507cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge            ic.setSelection(savedSelectionStart, savedSelectionEnd);
98607cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge            ic.endBatchEdit();
98707cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge            sLatinIMEExpectingUpdateSelection = true;
9886080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge            final Object[] values = new Object[2];
9896080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge            if (OUTPUT_ENTIRE_BUFFER) {
9906080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge                if (TextUtils.isEmpty(charSequence)) {
99107cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge                    values[0] = false;
9926080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge                    values[1] = "";
9936080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge                } else {
9946080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge                    if (charSequence.length() > MAX_INPUTVIEW_LENGTH_TO_CAPTURE) {
9956080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge                        int length = MAX_INPUTVIEW_LENGTH_TO_CAPTURE;
9966080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge                        // do not cut in the middle of a supplementary character
9976080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge                        final char c = charSequence.charAt(length - 1);
9986080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge                        if (Character.isHighSurrogate(c)) {
9996080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge                            length--;
10006080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge                        }
10016080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge                        final CharSequence truncatedCharSequence = charSequence.subSequence(0,
10026080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge                                length);
10036080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge                        values[0] = true;
10046080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge                        values[1] = truncatedCharSequence.toString();
10056080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge                    } else {
10066080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge                        values[0] = false;
10076080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge                        values[1] = charSequence.toString();
10086080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge                    }
1009d67a248de45a698d1009757c9f4e750c77bf35f1Kurt Partridge                }
10106080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge            } else {
10116080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge                values[0] = true;
10126080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge                values[1] = "";
1013d67a248de45a698d1009757c9f4e750c77bf35f1Kurt Partridge            }
10146080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge            final ResearchLogger researchLogger = getInstance();
10156080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge            researchLogger.enqueueEvent(EVENTKEYS_LATINIME_ONWINDOWHIDDEN, values);
1016223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge            // Play it safe.  Remove privacy-sensitive events.
1017223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge            researchLogger.publishLogUnit(researchLogger.mCurrentLogUnit, true);
1018223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge            researchLogger.mCurrentLogUnit = new LogUnit();
10194331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge            getInstance().stop();
1020d67a248de45a698d1009757c9f4e750c77bf35f1Kurt Partridge        }
1021d67a248de45a698d1009757c9f4e750c77bf35f1Kurt Partridge    }
1022d67a248de45a698d1009757c9f4e750c77bf35f1Kurt Partridge
102307cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    private static final String[] EVENTKEYS_LATINIME_ONUPDATESELECTION = {
1024f739119f3ff54d7c37b67b873373b236a45e47e4Kurt Partridge        "LatinIMEOnUpdateSelection", "lastSelectionStart", "lastSelectionEnd", "oldSelStart",
102507cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge        "oldSelEnd", "newSelStart", "newSelEnd", "composingSpanStart", "composingSpanEnd",
102686fcadde5d1ca69e4d93dc7cf5e72c763a32ac84Kurt Partridge        "expectingUpdateSelection", "expectingUpdateSelectionFromLogger", "context"
102707cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    };
10289bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge    public static void latinIME_onUpdateSelection(final int lastSelectionStart,
10299bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge            final int lastSelectionEnd, final int oldSelStart, final int oldSelEnd,
10309bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge            final int newSelStart, final int newSelEnd, final int composingSpanStart,
1031d67a248de45a698d1009757c9f4e750c77bf35f1Kurt Partridge            final int composingSpanEnd, final boolean expectingUpdateSelection,
103202308bec632a5df23325c916bffec5def16b22b4Jean Chalard            final boolean expectingUpdateSelectionFromLogger,
103302308bec632a5df23325c916bffec5def16b22b4Jean Chalard            final RichInputConnection connection) {
103465fc909e13134d34e87d5d75ff4cdd46fb9cebf0Kurt Partridge        String word = "";
103565fc909e13134d34e87d5d75ff4cdd46fb9cebf0Kurt Partridge        if (connection != null) {
103665fc909e13134d34e87d5d75ff4cdd46fb9cebf0Kurt Partridge            Range range = connection.getWordRangeAtCursor(WHITESPACE_SEPARATORS, 1);
103765fc909e13134d34e87d5d75ff4cdd46fb9cebf0Kurt Partridge            if (range != null) {
103865fc909e13134d34e87d5d75ff4cdd46fb9cebf0Kurt Partridge                word = range.mWord;
103965fc909e13134d34e87d5d75ff4cdd46fb9cebf0Kurt Partridge            }
104065fc909e13134d34e87d5d75ff4cdd46fb9cebf0Kurt Partridge        }
10416080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge        final ResearchLogger researchLogger = getInstance();
10426080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge        final String scrubbedWord = researchLogger.scrubWord(word);
104307cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge        final Object[] values = {
104407cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge            lastSelectionStart, lastSelectionEnd, oldSelStart, oldSelEnd, newSelStart,
104507cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge            newSelEnd, composingSpanStart, composingSpanEnd, expectingUpdateSelection,
10466080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge            expectingUpdateSelectionFromLogger, scrubbedWord
104707cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge        };
10486080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge        researchLogger.enqueuePotentiallyPrivateEvent(EVENTKEYS_LATINIME_ONUPDATESELECTION, values);
104907cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    }
105007cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge
105107cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    private static final String[] EVENTKEYS_LATINIME_PERFORMEDITORACTION = {
1052f739119f3ff54d7c37b67b873373b236a45e47e4Kurt Partridge        "LatinIMEPerformEditorAction", "imeActionNext"
105307cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    };
1054d442984e96cc6299c905141e3e32e0a4f55394c8Kurt Partridge    public static void latinIME_performEditorAction(final int imeActionNext) {
105507cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge        final Object[] values = {
105607cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge            imeActionNext
105707cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge        };
10586080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge        getInstance().enqueueEvent(EVENTKEYS_LATINIME_PERFORMEDITORACTION, values);
1059d442984e96cc6299c905141e3e32e0a4f55394c8Kurt Partridge    }
1060d442984e96cc6299c905141e3e32e0a4f55394c8Kurt Partridge
106107cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    private static final String[] EVENTKEYS_LATINIME_PICKAPPLICATIONSPECIFIEDCOMPLETION = {
1062f739119f3ff54d7c37b67b873373b236a45e47e4Kurt Partridge        "LatinIMEPickApplicationSpecifiedCompletion", "index", "text", "x", "y"
106307cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    };
10649bfb6202154e06d7156f2f374dd9359f1be4eb68Kurt Partridge    public static void latinIME_pickApplicationSpecifiedCompletion(final int index,
106565fc909e13134d34e87d5d75ff4cdd46fb9cebf0Kurt Partridge            final CharSequence cs, int x, int y) {
106607cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge        final Object[] values = {
106765fc909e13134d34e87d5d75ff4cdd46fb9cebf0Kurt Partridge            index, cs, x, y
106807cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge        };
10696080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge        final ResearchLogger researchLogger = getInstance();
10706080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge        researchLogger.enqueuePotentiallyPrivateEvent(
10716080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge                EVENTKEYS_LATINIME_PICKAPPLICATIONSPECIFIEDCOMPLETION, values);
10729bfb6202154e06d7156f2f374dd9359f1be4eb68Kurt Partridge    }
10739bfb6202154e06d7156f2f374dd9359f1be4eb68Kurt Partridge
107407cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    private static final String[] EVENTKEYS_LATINIME_PICKSUGGESTIONMANUALLY = {
1075f739119f3ff54d7c37b67b873373b236a45e47e4Kurt Partridge        "LatinIMEPickSuggestionManually", "replacedWord", "index", "suggestion", "x", "y"
107607cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    };
10779bfb6202154e06d7156f2f374dd9359f1be4eb68Kurt Partridge    public static void latinIME_pickSuggestionManually(final String replacedWord,
10789bfb6202154e06d7156f2f374dd9359f1be4eb68Kurt Partridge            final int index, CharSequence suggestion, int x, int y) {
107907cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge        final Object[] values = {
1080a696781c2b18d8002275aa89e07fa7379661d025Kurt Partridge            scrubDigitsFromString(replacedWord), index, suggestion == null ? null :
1081a696781c2b18d8002275aa89e07fa7379661d025Kurt Partridge                    scrubDigitsFromString(suggestion.toString()), x, y
108207cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge        };
10836080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge        final ResearchLogger researchLogger = getInstance();
10846080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge        researchLogger.enqueuePotentiallyPrivateEvent(EVENTKEYS_LATINIME_PICKSUGGESTIONMANUALLY,
10856080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge                values);
10869bfb6202154e06d7156f2f374dd9359f1be4eb68Kurt Partridge    }
10879bfb6202154e06d7156f2f374dd9359f1be4eb68Kurt Partridge
108807cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    private static final String[] EVENTKEYS_LATINIME_PUNCTUATIONSUGGESTION = {
1089f739119f3ff54d7c37b67b873373b236a45e47e4Kurt Partridge        "LatinIMEPunctuationSuggestion", "index", "suggestion", "x", "y"
109007cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    };
10919bfb6202154e06d7156f2f374dd9359f1be4eb68Kurt Partridge    public static void latinIME_punctuationSuggestion(final int index,
10929bfb6202154e06d7156f2f374dd9359f1be4eb68Kurt Partridge            final CharSequence suggestion, int x, int y) {
109307cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge        final Object[] values = {
109465fc909e13134d34e87d5d75ff4cdd46fb9cebf0Kurt Partridge            index, suggestion, x, y
109507cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge        };
10966080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge        getInstance().enqueueEvent(EVENTKEYS_LATINIME_PUNCTUATIONSUGGESTION, values);
1097d442984e96cc6299c905141e3e32e0a4f55394c8Kurt Partridge    }
1098d442984e96cc6299c905141e3e32e0a4f55394c8Kurt Partridge
109907cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    private static final String[] EVENTKEYS_LATINIME_REVERTDOUBLESPACEWHILEINBATCHEDIT = {
1100f739119f3ff54d7c37b67b873373b236a45e47e4Kurt Partridge        "LatinIMERevertDoubleSpaceWhileInBatchEdit"
110107cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    };
1102d442984e96cc6299c905141e3e32e0a4f55394c8Kurt Partridge    public static void latinIME_revertDoubleSpaceWhileInBatchEdit() {
11036080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge        getInstance().enqueueEvent(EVENTKEYS_LATINIME_REVERTDOUBLESPACEWHILEINBATCHEDIT,
110407cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge                EVENTKEYS_NULLVALUES);
1105d442984e96cc6299c905141e3e32e0a4f55394c8Kurt Partridge    }
1106d442984e96cc6299c905141e3e32e0a4f55394c8Kurt Partridge
110707cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    private static final String[] EVENTKEYS_LATINIME_REVERTSWAPPUNCTUATION = {
1108f739119f3ff54d7c37b67b873373b236a45e47e4Kurt Partridge        "LatinIMERevertSwapPunctuation"
110907cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    };
1110d442984e96cc6299c905141e3e32e0a4f55394c8Kurt Partridge    public static void latinIME_revertSwapPunctuation() {
11116080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge        getInstance().enqueueEvent(EVENTKEYS_LATINIME_REVERTSWAPPUNCTUATION, EVENTKEYS_NULLVALUES);
1112d442984e96cc6299c905141e3e32e0a4f55394c8Kurt Partridge    }
1113d442984e96cc6299c905141e3e32e0a4f55394c8Kurt Partridge
111407cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    private static final String[] EVENTKEYS_LATINIME_SENDKEYCODEPOINT = {
1115f739119f3ff54d7c37b67b873373b236a45e47e4Kurt Partridge        "LatinIMESendKeyCodePoint", "code"
111607cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    };
1117d442984e96cc6299c905141e3e32e0a4f55394c8Kurt Partridge    public static void latinIME_sendKeyCodePoint(final int code) {
111807cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge        final Object[] values = {
1119a696781c2b18d8002275aa89e07fa7379661d025Kurt Partridge            Keyboard.printableCode(scrubDigitFromCodePoint(code))
112007cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge        };
11216080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge        getInstance().enqueuePotentiallyPrivateEvent(EVENTKEYS_LATINIME_SENDKEYCODEPOINT, values);
1122d442984e96cc6299c905141e3e32e0a4f55394c8Kurt Partridge    }
1123d442984e96cc6299c905141e3e32e0a4f55394c8Kurt Partridge
112407cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    private static final String[] EVENTKEYS_LATINIME_SWAPSWAPPERANDSPACEWHILEINBATCHEDIT = {
1125f739119f3ff54d7c37b67b873373b236a45e47e4Kurt Partridge        "LatinIMESwapSwapperAndSpaceWhileInBatchEdit"
112607cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    };
1127d442984e96cc6299c905141e3e32e0a4f55394c8Kurt Partridge    public static void latinIME_swapSwapperAndSpaceWhileInBatchEdit() {
11286080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge        getInstance().enqueueEvent(EVENTKEYS_LATINIME_SWAPSWAPPERANDSPACEWHILEINBATCHEDIT,
112907cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge                EVENTKEYS_NULLVALUES);
11309bfb6202154e06d7156f2f374dd9359f1be4eb68Kurt Partridge    }
11319bfb6202154e06d7156f2f374dd9359f1be4eb68Kurt Partridge
1132c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka    private static final String[] EVENTKEYS_MAINKEYBOARDVIEW_ONLONGPRESS = {
1133c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka        "MainKeyboardViewOnLongPress"
113407cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    };
1135c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka    public static void mainKeyboardView_onLongPress() {
1136c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka        getInstance().enqueueEvent(EVENTKEYS_MAINKEYBOARDVIEW_ONLONGPRESS, EVENTKEYS_NULLVALUES);
11379bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge    }
11389bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge
1139c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka    private static final String[] EVENTKEYS_MAINKEYBOARDVIEW_SETKEYBOARD = {
1140c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka        "MainKeyboardViewSetKeyboard", "elementId", "locale", "orientation", "width",
114186fcadde5d1ca69e4d93dc7cf5e72c763a32ac84Kurt Partridge        "modeName", "action", "navigateNext", "navigatePrevious", "clobberSettingsKey",
114286fcadde5d1ca69e4d93dc7cf5e72c763a32ac84Kurt Partridge        "passwordInput", "shortcutKeyEnabled", "hasShortcutKey", "languageSwitchKeyEnabled",
114386fcadde5d1ca69e4d93dc7cf5e72c763a32ac84Kurt Partridge        "isMultiLine", "tw", "th", "keys"
114407cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    };
1145c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka    public static void mainKeyboardView_setKeyboard(final Keyboard keyboard) {
114607cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge        if (keyboard != null) {
114786fcadde5d1ca69e4d93dc7cf5e72c763a32ac84Kurt Partridge            final KeyboardId kid = keyboard.mId;
1148a696781c2b18d8002275aa89e07fa7379661d025Kurt Partridge            final boolean isPasswordView = kid.passwordInput();
11490df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge            getInstance().setIsPasswordView(isPasswordView);
115007cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge            final Object[] values = {
115186fcadde5d1ca69e4d93dc7cf5e72c763a32ac84Kurt Partridge                    KeyboardId.elementIdToName(kid.mElementId),
115286fcadde5d1ca69e4d93dc7cf5e72c763a32ac84Kurt Partridge                    kid.mLocale + ":" + kid.mSubtype.getExtraValueOf(KEYBOARD_LAYOUT_SET),
115386fcadde5d1ca69e4d93dc7cf5e72c763a32ac84Kurt Partridge                    kid.mOrientation,
115486fcadde5d1ca69e4d93dc7cf5e72c763a32ac84Kurt Partridge                    kid.mWidth,
115586fcadde5d1ca69e4d93dc7cf5e72c763a32ac84Kurt Partridge                    KeyboardId.modeName(kid.mMode),
115686fcadde5d1ca69e4d93dc7cf5e72c763a32ac84Kurt Partridge                    kid.imeAction(),
115786fcadde5d1ca69e4d93dc7cf5e72c763a32ac84Kurt Partridge                    kid.navigateNext(),
115886fcadde5d1ca69e4d93dc7cf5e72c763a32ac84Kurt Partridge                    kid.navigatePrevious(),
115986fcadde5d1ca69e4d93dc7cf5e72c763a32ac84Kurt Partridge                    kid.mClobberSettingsKey,
11601cef91e4818790ea5419a6ad9ff6e36ac535c763Kurt Partridge                    isPasswordView,
116186fcadde5d1ca69e4d93dc7cf5e72c763a32ac84Kurt Partridge                    kid.mShortcutKeyEnabled,
116286fcadde5d1ca69e4d93dc7cf5e72c763a32ac84Kurt Partridge                    kid.mHasShortcutKey,
116386fcadde5d1ca69e4d93dc7cf5e72c763a32ac84Kurt Partridge                    kid.mLanguageSwitchKeyEnabled,
116486fcadde5d1ca69e4d93dc7cf5e72c763a32ac84Kurt Partridge                    kid.isMultiLine(),
116586fcadde5d1ca69e4d93dc7cf5e72c763a32ac84Kurt Partridge                    keyboard.mOccupiedWidth,
116686fcadde5d1ca69e4d93dc7cf5e72c763a32ac84Kurt Partridge                    keyboard.mOccupiedHeight,
116786fcadde5d1ca69e4d93dc7cf5e72c763a32ac84Kurt Partridge                    keyboard.mKeys
116886fcadde5d1ca69e4d93dc7cf5e72c763a32ac84Kurt Partridge                };
1169c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka            getInstance().enqueueEvent(EVENTKEYS_MAINKEYBOARDVIEW_SETKEYBOARD, values);
11701cef91e4818790ea5419a6ad9ff6e36ac535c763Kurt Partridge            getInstance().setIsPasswordView(isPasswordView);
117148a7681e064ae259b840f0e757da2d716043d893Kurt Partridge        }
117248a7681e064ae259b840f0e757da2d716043d893Kurt Partridge    }
117348a7681e064ae259b840f0e757da2d716043d893Kurt Partridge
117407cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    private static final String[] EVENTKEYS_LATINIME_REVERTCOMMIT = {
1175f739119f3ff54d7c37b67b873373b236a45e47e4Kurt Partridge        "LatinIMERevertCommit", "originallyTypedWord"
117607cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    };
1177d442984e96cc6299c905141e3e32e0a4f55394c8Kurt Partridge    public static void latinIME_revertCommit(final String originallyTypedWord) {
117807cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge        final Object[] values = {
117907cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge            originallyTypedWord
118007cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge        };
11816080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge        getInstance().enqueuePotentiallyPrivateEvent(EVENTKEYS_LATINIME_REVERTCOMMIT, values);
1182d442984e96cc6299c905141e3e32e0a4f55394c8Kurt Partridge    }
1183d442984e96cc6299c905141e3e32e0a4f55394c8Kurt Partridge
118407cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    private static final String[] EVENTKEYS_POINTERTRACKER_CALLLISTENERONCANCELINPUT = {
1185f739119f3ff54d7c37b67b873373b236a45e47e4Kurt Partridge        "PointerTrackerCallListenerOnCancelInput"
118607cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    };
11879bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge    public static void pointerTracker_callListenerOnCancelInput() {
11886080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge        getInstance().enqueueEvent(EVENTKEYS_POINTERTRACKER_CALLLISTENERONCANCELINPUT,
118907cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge                EVENTKEYS_NULLVALUES);
11909bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge    }
11919bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge
119207cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    private static final String[] EVENTKEYS_POINTERTRACKER_CALLLISTENERONCODEINPUT = {
1193f739119f3ff54d7c37b67b873373b236a45e47e4Kurt Partridge        "PointerTrackerCallListenerOnCodeInput", "code", "outputText", "x", "y",
119407cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge        "ignoreModifierKey", "altersCode", "isEnabled"
119507cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    };
11969bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge    public static void pointerTracker_callListenerOnCodeInput(final Key key, final int x,
11979bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge            final int y, final boolean ignoreModifierKey, final boolean altersCode,
11989bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge            final int code) {
119907cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge        if (key != null) {
120007cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge            CharSequence outputText = key.mOutputText;
120107cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge            final Object[] values = {
1202a696781c2b18d8002275aa89e07fa7379661d025Kurt Partridge                Keyboard.printableCode(scrubDigitFromCodePoint(code)), outputText == null ? null
1203a696781c2b18d8002275aa89e07fa7379661d025Kurt Partridge                        : scrubDigitsFromString(outputText.toString()),
1204a696781c2b18d8002275aa89e07fa7379661d025Kurt Partridge                x, y, ignoreModifierKey, altersCode, key.isEnabled()
120507cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge            };
12066080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge            getInstance().enqueuePotentiallyPrivateEvent(
12076080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge                    EVENTKEYS_POINTERTRACKER_CALLLISTENERONCODEINPUT, values);
12089bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge        }
12099bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge    }
12109bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge
121107cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    private static final String[] EVENTKEYS_POINTERTRACKER_CALLLISTENERONRELEASE = {
1212f739119f3ff54d7c37b67b873373b236a45e47e4Kurt Partridge        "PointerTrackerCallListenerOnRelease", "code", "withSliding", "ignoreModifierKey",
121307cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge        "isEnabled"
121407cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    };
12159bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge    public static void pointerTracker_callListenerOnRelease(final Key key, final int primaryCode,
12169bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge            final boolean withSliding, final boolean ignoreModifierKey) {
121707cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge        if (key != null) {
121807cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge            final Object[] values = {
1219a696781c2b18d8002275aa89e07fa7379661d025Kurt Partridge                Keyboard.printableCode(scrubDigitFromCodePoint(primaryCode)), withSliding,
1220a696781c2b18d8002275aa89e07fa7379661d025Kurt Partridge                ignoreModifierKey, key.isEnabled()
122107cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge            };
12226080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge            getInstance().enqueuePotentiallyPrivateEvent(
12236080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge                    EVENTKEYS_POINTERTRACKER_CALLLISTENERONRELEASE, values);
12249bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge        }
12259bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge    }
12269bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge
122707cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    private static final String[] EVENTKEYS_POINTERTRACKER_ONDOWNEVENT = {
1228f739119f3ff54d7c37b67b873373b236a45e47e4Kurt Partridge        "PointerTrackerOnDownEvent", "deltaT", "distanceSquared"
122907cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    };
12309bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge    public static void pointerTracker_onDownEvent(long deltaT, int distanceSquared) {
123107cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge        final Object[] values = {
123207cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge            deltaT, distanceSquared
123307cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge        };
12346080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge        getInstance().enqueuePotentiallyPrivateEvent(EVENTKEYS_POINTERTRACKER_ONDOWNEVENT, values);
12359bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge    }
12369bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge
123707cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    private static final String[] EVENTKEYS_POINTERTRACKER_ONMOVEEVENT = {
1238f739119f3ff54d7c37b67b873373b236a45e47e4Kurt Partridge        "PointerTrackerOnMoveEvent", "x", "y", "lastX", "lastY"
123907cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    };
12409bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge    public static void pointerTracker_onMoveEvent(final int x, final int y, final int lastX,
12419bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge            final int lastY) {
124207cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge        final Object[] values = {
124307cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge            x, y, lastX, lastY
124407cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge        };
12456080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge        getInstance().enqueuePotentiallyPrivateEvent(EVENTKEYS_POINTERTRACKER_ONMOVEEVENT, values);
12469bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge    }
12479bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge
124807cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    private static final String[] EVENTKEYS_SUDDENJUMPINGTOUCHEVENTHANDLER_ONTOUCHEVENT = {
1249f739119f3ff54d7c37b67b873373b236a45e47e4Kurt Partridge        "SuddenJumpingTouchEventHandlerOnTouchEvent", "motionEvent"
125007cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    };
12519bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge    public static void suddenJumpingTouchEventHandler_onTouchEvent(final MotionEvent me) {
125207cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge        if (me != null) {
125307cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge            final Object[] values = {
125407cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge                me.toString()
125507cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge            };
12566080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge            getInstance().enqueuePotentiallyPrivateEvent(
12576080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge                    EVENTKEYS_SUDDENJUMPINGTOUCHEVENTHANDLER_ONTOUCHEVENT, values);
125807cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge        }
125907cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    }
126007cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge
126107cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    private static final String[] EVENTKEYS_SUGGESTIONSVIEW_SETSUGGESTIONS = {
1262f739119f3ff54d7c37b67b873373b236a45e47e4Kurt Partridge        "SuggestionsViewSetSuggestions", "suggestedWords"
126307cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    };
126407cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge    public static void suggestionsView_setSuggestions(final SuggestedWords suggestedWords) {
126507cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge        if (suggestedWords != null) {
126607cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge            final Object[] values = {
126786fcadde5d1ca69e4d93dc7cf5e72c763a32ac84Kurt Partridge                suggestedWords
126807cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge            };
12696080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge            getInstance().enqueuePotentiallyPrivateEvent(EVENTKEYS_SUGGESTIONSVIEW_SETSUGGESTIONS,
12706080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge                    values);
1271a9ca7867b5a7c0be115966211a05f5d460c8638cKurt Partridge        }
1272a9ca7867b5a7c0be115966211a05f5d460c8638cKurt Partridge    }
1273724bc479f7d796d6ce5d5e200216bea855b818b2Kurt Partridge
1274724bc479f7d796d6ce5d5e200216bea855b818b2Kurt Partridge    private static final String[] EVENTKEYS_USER_TIMESTAMP = {
1275724bc479f7d796d6ce5d5e200216bea855b818b2Kurt Partridge        "UserTimestamp"
1276724bc479f7d796d6ce5d5e200216bea855b818b2Kurt Partridge    };
1277724bc479f7d796d6ce5d5e200216bea855b818b2Kurt Partridge    public void userTimestamp() {
12786080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge        getInstance().enqueueEvent(EVENTKEYS_USER_TIMESTAMP, EVENTKEYS_NULLVALUES);
1279724bc479f7d796d6ce5d5e200216bea855b818b2Kurt Partridge    }
12805a937aae99fbd1c1e6f4976e639ef585e45675e5Kurt Partridge}
1281