diff options
Diffstat (limited to '')
-rw-r--r-- | java/src/com/android/inputmethod/research/ResearchLogger.java (renamed from java/src/com/android/inputmethod/latin/ResearchLogger.java) | 548 |
1 files changed, 411 insertions, 137 deletions
diff --git a/java/src/com/android/inputmethod/latin/ResearchLogger.java b/java/src/com/android/inputmethod/research/ResearchLogger.java index 1abfbad13..68bd98a23 100644 --- a/java/src/com/android/inputmethod/latin/ResearchLogger.java +++ b/java/src/com/android/inputmethod/research/ResearchLogger.java @@ -14,37 +14,56 @@ * the License. */ -package com.android.inputmethod.latin; +package com.android.inputmethod.research; import static com.android.inputmethod.latin.Constants.Subtype.ExtraValue.KEYBOARD_LAYOUT_SET; import android.app.AlertDialog; +import android.app.Dialog; import android.content.Context; import android.content.DialogInterface; +import android.content.DialogInterface.OnCancelListener; import android.content.SharedPreferences; import android.content.SharedPreferences.Editor; import android.content.pm.PackageInfo; import android.content.pm.PackageManager.NameNotFoundException; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.Paint.Style; import android.inputmethodservice.InputMethodService; import android.os.Build; +import android.os.IBinder; import android.text.TextUtils; import android.text.format.DateUtils; import android.util.Log; import android.view.MotionEvent; +import android.view.View; +import android.view.View.OnClickListener; +import android.view.Window; +import android.view.WindowManager; import android.view.inputmethod.CompletionInfo; import android.view.inputmethod.EditorInfo; import android.view.inputmethod.InputConnection; +import android.widget.Button; import android.widget.Toast; import com.android.inputmethod.keyboard.Key; import com.android.inputmethod.keyboard.Keyboard; import com.android.inputmethod.keyboard.KeyboardId; import com.android.inputmethod.keyboard.KeyboardSwitcher; +import com.android.inputmethod.keyboard.KeyboardView; +import com.android.inputmethod.keyboard.MainKeyboardView; +import com.android.inputmethod.latin.Dictionary; +import com.android.inputmethod.latin.LatinIME; +import com.android.inputmethod.latin.R; +import com.android.inputmethod.latin.RichInputConnection; import com.android.inputmethod.latin.RichInputConnection.Range; +import com.android.inputmethod.latin.Suggest; +import com.android.inputmethod.latin.SuggestedWords; import com.android.inputmethod.latin.define.ProductionFlag; import java.io.File; -import java.io.FileFilter; import java.io.IOException; import java.text.SimpleDateFormat; import java.util.ArrayList; @@ -64,19 +83,23 @@ import java.util.UUID; public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChangeListener { private static final String TAG = ResearchLogger.class.getSimpleName(); private static final boolean OUTPUT_ENTIRE_BUFFER = false; // true may disclose private info + public static final boolean DEFAULT_USABILITY_STUDY_MODE = false; /* package */ static boolean sIsLogging = false; private static final int OUTPUT_FORMAT_VERSION = 1; private static final String PREF_USABILITY_STUDY_MODE = "usability_study_mode"; - private static final String FILENAME_PREFIX = "researchLog"; + private static final String PREF_RESEARCH_HAS_SEEN_SPLASH = "pref_research_has_seen_splash"; + /* package */ static final String FILENAME_PREFIX = "researchLog"; private static final String FILENAME_SUFFIX = ".txt"; private static final SimpleDateFormat TIMESTAMP_DATEFORMAT = new SimpleDateFormat("yyyyMMddHHmmssS", Locale.US); + private static final boolean IS_SHOWING_INDICATOR = true; + private static final boolean IS_SHOWING_INDICATOR_CLEARLY = false; // constants related to specific log points private static final String WHITESPACE_SEPARATORS = " \t\n\r"; private static final int MAX_INPUTVIEW_LENGTH_TO_CAPTURE = 8192; // must be >=1 private static final String PREF_RESEARCH_LOGGER_UUID_STRING = "pref_research_logger_uuid"; - private static final int ABORT_TIMEOUT_IN_MS = 10 * 1000; + private static final int ABORT_TIMEOUT_IN_MS = 10 * 1000; // timeout to notify user private static final ResearchLogger sInstance = new ResearchLogger(); // to write to a different filename, e.g., for testing, set mFile before calling start() @@ -88,10 +111,11 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang // the system to do so. /* package */ ResearchLog mIntentionalResearchLog; // LogUnits are queued here and released only when the user requests the intentional log. - private final List<LogUnit> mIntentionalResearchLogQueue = new ArrayList<LogUnit>(); + private List<LogUnit> mIntentionalResearchLogQueue = new ArrayList<LogUnit>(); private boolean mIsPasswordView = false; private boolean mIsLoggingSuspended = false; + private SharedPreferences mPrefs; // digits entered by the user are replaced with this codepoint. /* package for test */ static final int DIGIT_REPLACEMENT_CODEPOINT = @@ -101,6 +125,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang private static final String PREF_LAST_CLEANUP_TIME = "pref_last_cleanup_time"; private static final long DURATION_BETWEEN_DIR_CLEANUP_IN_MS = DateUtils.DAY_IN_MILLIS; private static final long MAX_LOGFILE_AGE_IN_MS = DateUtils.DAY_IN_MILLIS; + protected static final int SUSPEND_DURATION_IN_MINUTES = 1; // set when LatinIME should ignore an onUpdateSelection() callback that // arises from operations in this class private static boolean sLatinIMEExpectingUpdateSelection = false; @@ -109,7 +134,9 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang private Suggest mSuggest; private Dictionary mDictionary; private KeyboardSwitcher mKeyboardSwitcher; - private Context mContext; + private InputMethodService mInputMethodService; + + private ResearchLogUploader mResearchLogUploader; private ResearchLogger() { } @@ -124,7 +151,6 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang if (ims == null) { Log.w(TAG, "IMS is null; logging is off"); } else { - mContext = ims; mFilesDir = ims.getFilesDir(); if (mFilesDir == null || !mFilesDir.exists()) { Log.w(TAG, "IME storage directory does not exist."); @@ -132,6 +158,11 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang } if (prefs != null) { mUUIDString = getUUID(prefs); + if (!prefs.contains(PREF_USABILITY_STUDY_MODE)) { + Editor e = prefs.edit(); + e.putBoolean(PREF_USABILITY_STUDY_MODE, DEFAULT_USABILITY_STUDY_MODE); + e.apply(); + } sIsLogging = prefs.getBoolean(PREF_USABILITY_STUDY_MODE, false); prefs.registerOnSharedPreferenceChangeListener(this); @@ -145,7 +176,11 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang e.apply(); } } + mResearchLogUploader = new ResearchLogUploader(ims, mFilesDir); + mResearchLogUploader.start(); mKeyboardSwitcher = keyboardSwitcher; + mInputMethodService = ims; + mPrefs = prefs; } private void cleanupLoggingDir(final File dir, final long time) { @@ -157,6 +192,73 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang } } + public void mainKeyboardView_onAttachedToWindow() { + maybeShowSplashScreen(); + } + + private boolean hasSeenSplash() { + return mPrefs.getBoolean(PREF_RESEARCH_HAS_SEEN_SPLASH, false); + } + + private Dialog mSplashDialog = null; + + private void maybeShowSplashScreen() { + if (hasSeenSplash()) { + return; + } + if (mSplashDialog != null && mSplashDialog.isShowing()) { + return; + } + final IBinder windowToken = mKeyboardSwitcher.getKeyboardView().getWindowToken(); + if (windowToken == null) { + return; + } + mSplashDialog = new Dialog(mInputMethodService, android.R.style.Theme_Holo_Dialog); + mSplashDialog.requestWindowFeature(Window.FEATURE_NO_TITLE); + mSplashDialog.setContentView(R.layout.research_splash); + mSplashDialog.setCancelable(true); + final Window w = mSplashDialog.getWindow(); + final WindowManager.LayoutParams lp = w.getAttributes(); + lp.token = windowToken; + lp.type = WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG; + w.setAttributes(lp); + w.addFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM); + mSplashDialog.setOnCancelListener(new OnCancelListener() { + @Override + public void onCancel(DialogInterface dialog) { + mInputMethodService.requestHideSelf(0); + } + }); + final Button doNotLogButton = (Button) mSplashDialog.findViewById( + R.id.research_do_not_log_button); + doNotLogButton.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + onUserLoggingElection(false); + mSplashDialog.dismiss(); + } + }); + final Button doLogButton = (Button) mSplashDialog.findViewById(R.id.research_do_log_button); + doLogButton.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + onUserLoggingElection(true); + mSplashDialog.dismiss(); + } + }); + mSplashDialog.show(); + } + + public void onUserLoggingElection(final boolean enableLogging) { + setLoggingAllowed(enableLogging); + if (mPrefs == null) { + return; + } + final Editor e = mPrefs.edit(); + e.putBoolean(PREF_RESEARCH_HAS_SEEN_SPLASH, true); + e.apply(); + } + private File createLogFile(File filesDir) { final StringBuilder sb = new StringBuilder(); sb.append(FILENAME_PREFIX).append('-'); @@ -166,8 +268,11 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang return new File(filesDir, sb.toString()); } - public void start() { - if (!sIsLogging) { + private void start() { + maybeShowSplashScreen(); + updateSuspendedState(); + requestIndicatorRedraw(); + if (!isAllowedToLog()) { // Log.w(TAG, "not in usability mode; not logging"); return; } @@ -175,10 +280,10 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang Log.w(TAG, "IME storage directory does not exist. Cannot start logging."); return; } - if (mMainResearchLog == null || !mMainResearchLog.isAlive()) { - mMainResearchLog = new ResearchLog(createLogFile(mFilesDir)); - } try { + if (mMainResearchLog == null || !mMainResearchLog.isAlive()) { + mMainResearchLog = new ResearchLog(createLogFile(mFilesDir)); + } mMainResearchLog.start(); if (mIntentionalResearchLog == null || !mIntentionalResearchLog.isAlive()) { mIntentionalResearchLog = new ResearchLog(createLogFile(mFilesDir)); @@ -189,15 +294,26 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang } } - public void stop() { + /* package */ void stop() { if (mMainResearchLog != null) { mMainResearchLog.stop(); } + if (mIntentionalResearchLog != null) { + mIntentionalResearchLog.stop(); + } + } + + private void setLoggingAllowed(boolean enableLogging) { + if (mPrefs == null) { + return; + } + Editor e = mPrefs.edit(); + e.putBoolean(PREF_USABILITY_STUDY_MODE, enableLogging); + e.apply(); + sIsLogging = enableLogging; } public boolean abort() { - mIsLoggingSuspended = true; - requestIndicatorRedraw(); boolean didAbortMainLog = false; if (mMainResearchLog != null) { mMainResearchLog.abort(); @@ -209,6 +325,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang if (mMainResearchLog.isAbortSuccessful()) { didAbortMainLog = true; } + mMainResearchLog = null; } boolean didAbortIntentionalLog = false; if (mIntentionalResearchLog != null) { @@ -221,6 +338,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang if (mIntentionalResearchLog.isAbortSuccessful()) { didAbortIntentionalLog = true; } + mIntentionalResearchLog = null; } return didAbortMainLog && didAbortIntentionalLog; } @@ -231,19 +349,31 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang } } - private void logWholeSessionHistory() throws IOException { - try { - LogUnit headerLogUnit = new LogUnit(); - headerLogUnit.addLogAtom(EVENTKEYS_INTENTIONAL_LOG, EVENTKEYS_NULLVALUES, false); - mIntentionalResearchLog.publishAllEvents(headerLogUnit); - for (LogUnit logUnit : mIntentionalResearchLogQueue) { - mIntentionalResearchLog.publishAllEvents(logUnit); - } - mIntentionalResearchLog.stop(); - mIntentionalResearchLog = new ResearchLog(createLogFile(mFilesDir)); - mIntentionalResearchLog.start(); - } finally { - mIntentionalResearchLogQueue.clear(); + private void restart() { + stop(); + start(); + } + + private long mResumeTime = 0L; + private void suspendLoggingUntil(long time) { + mIsLoggingSuspended = true; + mResumeTime = time; + requestIndicatorRedraw(); + } + + private void resumeLogging() { + mResumeTime = 0L; + updateSuspendedState(); + requestIndicatorRedraw(); + if (isAllowedToLog()) { + restart(); + } + } + + private void updateSuspendedState() { + final long time = System.currentTimeMillis(); + if (time > mResumeTime) { + mIsLoggingSuspended = false; } } @@ -256,15 +386,21 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang if (sIsLogging == false) { abort(); } + requestIndicatorRedraw(); } - /* package */ void presentResearchDialog(final LatinIME latinIME) { + public void presentResearchDialog(final LatinIME latinIME) { + if (mInFeedbackDialog) { + Toast.makeText(latinIME, R.string.research_please_exit_feedback_form, + Toast.LENGTH_LONG).show(); + return; + } final CharSequence title = latinIME.getString(R.string.english_ime_research_log); + final boolean showEnable = mIsLoggingSuspended || !sIsLogging; final CharSequence[] items = new CharSequence[] { - latinIME.getString(R.string.note_timestamp_for_researchlog), - mIsLoggingSuspended ? latinIME.getString(R.string.enable_session_logging) : - latinIME.getString(R.string.do_not_log_this_session), - latinIME.getString(R.string.log_whole_session_history), + latinIME.getString(R.string.research_feedback_menu_option), + showEnable ? latinIME.getString(R.string.research_enable_session_logging) : + latinIME.getString(R.string.research_do_not_log_this_session) }; final DialogInterface.OnClickListener listener = new DialogInterface.OnClickListener() { @Override @@ -272,41 +408,30 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang di.dismiss(); switch (position) { case 0: - userTimestamp(); - Toast.makeText(latinIME, R.string.notify_recorded_timestamp, - Toast.LENGTH_LONG).show(); + presentFeedbackDialog(latinIME); break; case 1: - if (mIsLoggingSuspended) { - mIsLoggingSuspended = false; - requestIndicatorRedraw(); - Toast toast = Toast.makeText(latinIME, - R.string.notify_session_logging_enabled, Toast.LENGTH_LONG); + if (showEnable) { + if (!sIsLogging) { + setLoggingAllowed(true); + } + resumeLogging(); + Toast.makeText(latinIME, + R.string.research_notify_session_logging_enabled, + Toast.LENGTH_LONG).show(); } else { Toast toast = Toast.makeText(latinIME, - R.string.notify_session_log_deleting, Toast.LENGTH_LONG); + R.string.research_notify_session_log_deleting, + Toast.LENGTH_LONG); toast.show(); boolean isLogDeleted = abort(); + final long currentTime = System.currentTimeMillis(); + final long resumeTime = currentTime + 1000 * 60 * + SUSPEND_DURATION_IN_MINUTES; + suspendLoggingUntil(resumeTime); toast.cancel(); - if (isLogDeleted) { - Toast.makeText(latinIME, R.string.notify_session_log_deleted, - Toast.LENGTH_LONG).show(); - } else { - Toast.makeText(latinIME, - R.string.notify_session_log_not_deleted, Toast.LENGTH_LONG) - .show(); - } - } - break; - case 2: - try { - logWholeSessionHistory(); - Toast.makeText(latinIME, R.string.notify_session_history_logged, + Toast.makeText(latinIME, R.string.research_notify_logging_suspended, Toast.LENGTH_LONG).show(); - } catch (IOException e) { - Toast.makeText(latinIME, R.string.notify_session_history_not_logged, - Toast.LENGTH_LONG).show(); - e.printStackTrace(); } break; } @@ -319,6 +444,83 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang latinIME.showOptionDialog(builder.create()); } + private boolean mInFeedbackDialog = false; + public void presentFeedbackDialog(LatinIME latinIME) { + mInFeedbackDialog = true; + latinIME.launchKeyboardedDialogActivity(FeedbackActivity.class); + } + + private ResearchLog mFeedbackLog; + private List<LogUnit> mFeedbackQueue; + private ResearchLog mSavedMainResearchLog; + private ResearchLog mSavedIntentionalResearchLog; + private List<LogUnit> mSavedIntentionalResearchLogQueue; + + private void saveLogsForFeedback() { + mFeedbackLog = mIntentionalResearchLog; + if (mIntentionalResearchLogQueue != null) { + mFeedbackQueue = new ArrayList<LogUnit>(mIntentionalResearchLogQueue); + } else { + mFeedbackQueue = null; + } + mSavedMainResearchLog = mMainResearchLog; + mSavedIntentionalResearchLog = mIntentionalResearchLog; + mSavedIntentionalResearchLogQueue = mIntentionalResearchLogQueue; + + mMainResearchLog = null; + mIntentionalResearchLog = null; + mIntentionalResearchLogQueue = new ArrayList<LogUnit>(); + } + + private static final int LOG_DRAIN_TIMEOUT_IN_MS = 1000 * 5; + public void sendFeedback(final String feedbackContents, final boolean includeHistory) { + if (includeHistory && mFeedbackLog != null) { + try { + LogUnit headerLogUnit = new LogUnit(); + headerLogUnit.addLogAtom(EVENTKEYS_INTENTIONAL_LOG, EVENTKEYS_NULLVALUES, false); + mFeedbackLog.publishAllEvents(headerLogUnit); + for (LogUnit logUnit : mFeedbackQueue) { + mFeedbackLog.publishAllEvents(logUnit); + } + userFeedback(mFeedbackLog, feedbackContents); + mFeedbackLog.stop(); + try { + mFeedbackLog.waitUntilStopped(LOG_DRAIN_TIMEOUT_IN_MS); + } catch (InterruptedException e) { + e.printStackTrace(); + } + mIntentionalResearchLog = new ResearchLog(createLogFile(mFilesDir)); + mIntentionalResearchLog.start(); + } catch (IOException e) { + e.printStackTrace(); + } finally { + mIntentionalResearchLogQueue.clear(); + } + mResearchLogUploader.uploadNow(null); + } else { + // create a separate ResearchLog just for feedback + final ResearchLog feedbackLog = new ResearchLog(createLogFile(mFilesDir)); + try { + feedbackLog.start(); + userFeedback(feedbackLog, feedbackContents); + feedbackLog.stop(); + feedbackLog.waitUntilStopped(LOG_DRAIN_TIMEOUT_IN_MS); + mResearchLogUploader.uploadNow(null); + } catch (IOException e) { + e.printStackTrace(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + + public void onLeavingSendFeedbackDialog() { + mInFeedbackDialog = false; + mMainResearchLog = mSavedMainResearchLog; + mIntentionalResearchLog = mSavedIntentionalResearchLog; + mIntentionalResearchLogQueue = mSavedIntentionalResearchLogQueue; + } + public void initSuggest(Suggest suggest) { mSuggest = suggest; } @@ -328,13 +530,50 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang } private boolean isAllowedToLog() { - return !mIsPasswordView && !mIsLoggingSuspended; + return !mIsPasswordView && !mIsLoggingSuspended && sIsLogging; } public void requestIndicatorRedraw() { - // invalidate any existing graphics - if (mKeyboardSwitcher != null) { - mKeyboardSwitcher.getKeyboardView().invalidateAllKeys(); + if (!IS_SHOWING_INDICATOR) { + return; + } + if (mKeyboardSwitcher == null) { + return; + } + final KeyboardView keyboardView = mKeyboardSwitcher.getKeyboardView(); + if (keyboardView == null) { + return; + } + keyboardView.invalidateAllKeys(); + } + + + public void paintIndicator(KeyboardView view, Paint paint, Canvas canvas, int width, + int height) { + // TODO: Reimplement using a keyboard background image specific to the ResearchLogger + // and remove this method. + // The check for MainKeyboardView ensures that a red border is only placed around + // the main keyboard, not every keyboard. + if (IS_SHOWING_INDICATOR && isAllowedToLog() && view instanceof MainKeyboardView) { + final int savedColor = paint.getColor(); + paint.setColor(Color.RED); + final Style savedStyle = paint.getStyle(); + paint.setStyle(Style.STROKE); + final float savedStrokeWidth = paint.getStrokeWidth(); + if (IS_SHOWING_INDICATOR_CLEARLY) { + paint.setStrokeWidth(5); + canvas.drawRect(0, 0, width, height, paint); + } else { + // Put a tiny red dot on the screen so a knowledgeable user can check whether + // it is enabled. The dot is actually a zero-width, zero-height rectangle, + // placed at the lower-right corner of the canvas, painted with a non-zero border + // width. + paint.setStrokeWidth(3); + canvas.drawRect(width, height, width, height, paint); + } + paint.setColor(savedColor); + paint.setStyle(savedStyle); + paint.setStrokeWidth(savedStrokeWidth); } } @@ -467,6 +706,12 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang } private void publishLogUnit(LogUnit logUnit, boolean isPrivacySensitive) { + if (!isAllowedToLog()) { + return; + } + if (mMainResearchLog == null) { + return; + } if (isPrivacySensitive) { mMainResearchLog.publishPublicEvents(logUnit); } else { @@ -536,6 +781,18 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang } } + private static String getUUID(final SharedPreferences prefs) { + String uuidString = prefs.getString(PREF_RESEARCH_LOGGER_UUID_STRING, null); + if (null == uuidString) { + UUID uuid = UUID.randomUUID(); + uuidString = uuid.toString(); + Editor editor = prefs.edit(); + editor.putString(PREF_RESEARCH_LOGGER_UUID_STRING, uuidString); + editor.apply(); + } + return uuidString; + } + private String scrubWord(String word) { if (mDictionary == null) { return WORD_REPLACEMENT_STRING; @@ -546,14 +803,84 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang return WORD_REPLACEMENT_STRING; } + // Special methods related to startup, shutdown, logging itself + private static final String[] EVENTKEYS_INTENTIONAL_LOG = { "IntentionalLog" }; - private static final String[] EVENTKEYS_LATINKEYBOARDVIEW_PROCESSMOTIONEVENT = { - "LatinKeyboardViewProcessMotionEvent", "action", "eventTime", "id", "x", "y", "size", + + private static final String[] EVENTKEYS_LATINIME_ONSTARTINPUTVIEWINTERNAL = { + "LatinIMEOnStartInputViewInternal", "uuid", "packageName", "inputType", "imeOptions", + "fieldId", "display", "model", "prefs", "versionCode", "versionName", "outputFormatVersion" + }; + public static void latinIME_onStartInputViewInternal(final EditorInfo editorInfo, + final SharedPreferences prefs) { + final ResearchLogger researchLogger = getInstance(); + if (researchLogger.mInFeedbackDialog) { + researchLogger.saveLogsForFeedback(); + } + researchLogger.start(); + if (editorInfo != null) { + final Context context = researchLogger.mInputMethodService; + try { + final PackageInfo packageInfo; + packageInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), + 0); + final Integer versionCode = packageInfo.versionCode; + final String versionName = packageInfo.versionName; + final Object[] values = { + researchLogger.mUUIDString, editorInfo.packageName, + Integer.toHexString(editorInfo.inputType), + Integer.toHexString(editorInfo.imeOptions), editorInfo.fieldId, + Build.DISPLAY, Build.MODEL, prefs, versionCode, versionName, + OUTPUT_FORMAT_VERSION + }; + researchLogger.enqueueEvent(EVENTKEYS_LATINIME_ONSTARTINPUTVIEWINTERNAL, values); + } catch (NameNotFoundException e) { + e.printStackTrace(); + } + } + } + + public void latinIME_onFinishInputInternal() { + stop(); + } + + private static final String[] EVENTKEYS_LATINIME_COMMITTEXT = { + "LatinIMECommitText", "typedWord" + }; + + public static void latinIME_commitText(final CharSequence typedWord) { + final String scrubbedWord = scrubDigitsFromString(typedWord.toString()); + final Object[] values = { + scrubbedWord + }; + final ResearchLogger researchLogger = getInstance(); + researchLogger.enqueuePotentiallyPrivateEvent(EVENTKEYS_LATINIME_COMMITTEXT, values); + researchLogger.onWordComplete(scrubbedWord); + } + + private static final String[] EVENTKEYS_USER_FEEDBACK = { + "UserFeedback", "FeedbackContents" + }; + + private void userFeedback(ResearchLog researchLog, String feedbackContents) { + // this method is special; it directs the feedbackContents to a particular researchLog + final LogUnit logUnit = new LogUnit(); + final Object[] values = { + feedbackContents + }; + logUnit.addLogAtom(EVENTKEYS_USER_FEEDBACK, values, false); + researchLog.publishAllEvents(logUnit); + } + + // Regular logging methods + + private static final String[] EVENTKEYS_MAINKEYBOARDVIEW_PROCESSMOTIONEVENT = { + "MainKeyboardViewProcessMotionEvent", "action", "eventTime", "id", "x", "y", "size", "pressure" }; - public static void latinKeyboardView_processMotionEvent(final MotionEvent me, final int action, + public static void mainKeyboardView_processMotionEvent(final MotionEvent me, final int action, final long eventTime, final int index, final int id, final int x, final int y) { if (me != null) { final String actionString; @@ -573,7 +900,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang actionString, eventTime, id, x, y, size, pressure }; getInstance().enqueuePotentiallyPrivateEvent( - EVENTKEYS_LATINKEYBOARDVIEW_PROCESSMOTIONEVENT, values); + EVENTKEYS_MAINKEYBOARDVIEW_PROCESSMOTIONEVENT, values); } } @@ -611,19 +938,6 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang EVENTKEYS_LATINIME_COMMITCURRENTAUTOCORRECTION, values); } - private static final String[] EVENTKEYS_LATINIME_COMMITTEXT = { - "LatinIMECommitText", "typedWord" - }; - public static void latinIME_commitText(final CharSequence typedWord) { - final String scrubbedWord = scrubDigitsFromString(typedWord.toString()); - final Object[] values = { - scrubbedWord - }; - final ResearchLogger researchLogger = getInstance(); - researchLogger.enqueuePotentiallyPrivateEvent(EVENTKEYS_LATINIME_COMMITTEXT, values); - researchLogger.onWordComplete(scrubbedWord); - } - private static final String[] EVENTKEYS_LATINIME_DELETESURROUNDINGTEXT = { "LatinIMEDeleteSurroundingText", "length" }; @@ -653,7 +967,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang values); } - /* package */ static boolean getAndClearLatinIMEExpectingUpdateSelection() { + public static boolean getAndClearLatinIMEExpectingUpdateSelection() { boolean returnValue = sLatinIMEExpectingUpdateSelection; sLatinIMEExpectingUpdateSelection = false; return returnValue; @@ -702,51 +1016,10 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang // Play it safe. Remove privacy-sensitive events. researchLogger.publishLogUnit(researchLogger.mCurrentLogUnit, true); researchLogger.mCurrentLogUnit = new LogUnit(); + getInstance().stop(); } } - private static final String[] EVENTKEYS_LATINIME_ONSTARTINPUTVIEWINTERNAL = { - "LatinIMEOnStartInputViewInternal", "uuid", "packageName", "inputType", "imeOptions", - "fieldId", "display", "model", "prefs", "versionCode", "versionName", "outputFormatVersion" - }; - public static void latinIME_onStartInputViewInternal(final EditorInfo editorInfo, - final SharedPreferences prefs) { - final ResearchLogger researchLogger = getInstance(); - researchLogger.start(); - if (editorInfo != null) { - final Context context = researchLogger.mContext; - try { - final PackageInfo packageInfo; - packageInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), - 0); - final Integer versionCode = packageInfo.versionCode; - final String versionName = packageInfo.versionName; - final Object[] values = { - researchLogger.mUUIDString, editorInfo.packageName, - Integer.toHexString(editorInfo.inputType), - Integer.toHexString(editorInfo.imeOptions), editorInfo.fieldId, - Build.DISPLAY, Build.MODEL, prefs, versionCode, versionName, - OUTPUT_FORMAT_VERSION - }; - researchLogger.enqueueEvent(EVENTKEYS_LATINIME_ONSTARTINPUTVIEWINTERNAL, values); - } catch (NameNotFoundException e) { - e.printStackTrace(); - } - } - } - - private static String getUUID(final SharedPreferences prefs) { - String uuidString = prefs.getString(PREF_RESEARCH_LOGGER_UUID_STRING, null); - if (null == uuidString) { - UUID uuid = UUID.randomUUID(); - uuidString = uuid.toString(); - Editor editor = prefs.edit(); - editor.putString(PREF_RESEARCH_LOGGER_UUID_STRING, uuidString); - editor.apply(); - } - return uuidString; - } - private static final String[] EVENTKEYS_LATINIME_ONUPDATESELECTION = { "LatinIMEOnUpdateSelection", "lastSelectionStart", "lastSelectionEnd", "oldSelStart", "oldSelEnd", "newSelStart", "newSelEnd", "composingSpanStart", "composingSpanEnd", @@ -856,23 +1129,24 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang EVENTKEYS_NULLVALUES); } - private static final String[] EVENTKEYS_LATINKEYBOARDVIEW_ONLONGPRESS = { - "LatinKeyboardViewOnLongPress" + private static final String[] EVENTKEYS_MAINKEYBOARDVIEW_ONLONGPRESS = { + "MainKeyboardViewOnLongPress" }; - public static void latinKeyboardView_onLongPress() { - getInstance().enqueueEvent(EVENTKEYS_LATINKEYBOARDVIEW_ONLONGPRESS, EVENTKEYS_NULLVALUES); + public static void mainKeyboardView_onLongPress() { + getInstance().enqueueEvent(EVENTKEYS_MAINKEYBOARDVIEW_ONLONGPRESS, EVENTKEYS_NULLVALUES); } - private static final String[] EVENTKEYS_LATINKEYBOARDVIEW_SETKEYBOARD = { - "LatinKeyboardViewSetKeyboard", "elementId", "locale", "orientation", "width", + private static final String[] EVENTKEYS_MAINKEYBOARDVIEW_SETKEYBOARD = { + "MainKeyboardViewSetKeyboard", "elementId", "locale", "orientation", "width", "modeName", "action", "navigateNext", "navigatePrevious", "clobberSettingsKey", "passwordInput", "shortcutKeyEnabled", "hasShortcutKey", "languageSwitchKeyEnabled", "isMultiLine", "tw", "th", "keys" }; - public static void latinKeyboardView_setKeyboard(final Keyboard keyboard) { + public static void mainKeyboardView_setKeyboard(final Keyboard keyboard) { if (keyboard != null) { final KeyboardId kid = keyboard.mId; final boolean isPasswordView = kid.passwordInput(); + getInstance().setIsPasswordView(isPasswordView); final Object[] values = { KeyboardId.elementIdToName(kid.mElementId), kid.mLocale + ":" + kid.mSubtype.getExtraValueOf(KEYBOARD_LAYOUT_SET), @@ -892,7 +1166,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang keyboard.mOccupiedHeight, keyboard.mKeys }; - getInstance().enqueueEvent(EVENTKEYS_LATINKEYBOARDVIEW_SETKEYBOARD, values); + getInstance().enqueueEvent(EVENTKEYS_MAINKEYBOARDVIEW_SETKEYBOARD, values); getInstance().setIsPasswordView(isPasswordView); } } @@ -984,16 +1258,16 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang } } - private static final String[] EVENTKEYS_SUGGESTIONSVIEW_SETSUGGESTIONS = { - "SuggestionsViewSetSuggestions", "suggestedWords" + private static final String[] EVENTKEYS_SUGGESTIONSTRIPVIEW_SETSUGGESTIONS = { + "SuggestionStripViewSetSuggestions", "suggestedWords" }; - public static void suggestionsView_setSuggestions(final SuggestedWords suggestedWords) { + public static void suggestionStripView_setSuggestions(final SuggestedWords suggestedWords) { if (suggestedWords != null) { final Object[] values = { suggestedWords }; - getInstance().enqueuePotentiallyPrivateEvent(EVENTKEYS_SUGGESTIONSVIEW_SETSUGGESTIONS, - values); + getInstance().enqueuePotentiallyPrivateEvent( + EVENTKEYS_SUGGESTIONSTRIPVIEW_SETSUGGESTIONS, values); } } |