Merge "ResearchLogger: make logging more reliable (esp on startup)"
commit
48ded4e3b1
|
@ -223,15 +223,15 @@
|
|||
<string name="notify_recorded_timestamp">Recorded timestamp</string>
|
||||
|
||||
<!-- Title for dialog option to let users cancel logging and delete log for this session [CHAR LIMIT=35] -->
|
||||
<string name="do_not_log_this_session">Do not log this session</string>
|
||||
<string name="do_not_log_this_session">Suspend logging</string>
|
||||
<!-- Title for dialog option to let users reenable logging [CHAR LIMIT=35] -->
|
||||
<string name="enable_session_logging">Enable session logging</string>
|
||||
<string name="enable_session_logging">Enable logging</string>
|
||||
<!-- Title for dialog option to let users log all events in this session [CHAR LIMIT=35] -->
|
||||
<string name="log_whole_session_history">Log whole session history</string>
|
||||
<!-- Toast notification that the system is processing the request to delete the log for this session [CHAR LIMIT=35] -->
|
||||
<string name="notify_session_log_deleting">Deleting session log</string>
|
||||
<!-- Toast notification that the system has successfully deleted the log for this session [CHAR LIMIT=35] -->
|
||||
<string name="notify_session_log_deleted">Session log deleted</string>
|
||||
<string name="notify_logging_suspended">Logging temporarily suspended. To disable permanently, go to Android Keyboard Settings</string>
|
||||
<!-- Toast notification that the system has failed to delete the log for this session [CHAR LIMIT=35] -->
|
||||
<string name="notify_session_log_not_deleted">Session log NOT deleted</string>
|
||||
<!-- Toast notification that the system has recorded the whole session history [CHAR LIMIT=35] -->
|
||||
|
@ -240,7 +240,6 @@
|
|||
<string name="notify_session_history_not_logged">Error: Session history NOT logged</string>
|
||||
<!-- Toast notification that the system is enabling logging [CHAR LIMIT=35] -->
|
||||
<string name="notify_session_logging_enabled">Session logging enabled</string>
|
||||
|
||||
<!-- Preference for input language selection -->
|
||||
<string name="select_language">Input languages</string>
|
||||
|
||||
|
|
|
@ -618,7 +618,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
|
|||
+ ((editorInfo.inputType & InputType.TYPE_TEXT_FLAG_CAP_WORDS) != 0));
|
||||
}
|
||||
if (ProductionFlag.IS_EXPERIMENTAL) {
|
||||
ResearchLogger.getInstance().start();
|
||||
ResearchLogger.latinIME_onStartInputViewInternal(editorInfo, mPrefs);
|
||||
}
|
||||
if (InputAttributes.inPrivateImeOptions(null, NO_MICROPHONE_COMPAT, editorInfo)) {
|
||||
|
@ -711,7 +710,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
|
|||
|
||||
LatinImeLogger.commit();
|
||||
if (ProductionFlag.IS_EXPERIMENTAL) {
|
||||
ResearchLogger.getInstance().stop();
|
||||
ResearchLogger.getInstance().latinIME_onFinishInputInternal();
|
||||
}
|
||||
|
||||
KeyboardView inputView = mKeyboardSwitcher.getKeyboardView();
|
||||
|
|
|
@ -55,13 +55,14 @@ public class ResearchLog {
|
|||
|
||||
final ScheduledExecutorService mExecutor;
|
||||
/* package */ final File mFile;
|
||||
private JsonWriter mJsonWriter = NULL_JSON_WRITER; // should never be null
|
||||
private JsonWriter mJsonWriter = NULL_JSON_WRITER;
|
||||
|
||||
private int mLoggingState;
|
||||
private static final int LOGGING_STATE_UNSTARTED = 0;
|
||||
private static final int LOGGING_STATE_RUNNING = 1;
|
||||
private static final int LOGGING_STATE_STOPPING = 2;
|
||||
private static final int LOGGING_STATE_STOPPED = 3;
|
||||
private static final int LOGGING_STATE_READY = 1; // don't create file until necessary
|
||||
private static final int LOGGING_STATE_RUNNING = 2;
|
||||
private static final int LOGGING_STATE_STOPPING = 3;
|
||||
private static final int LOGGING_STATE_STOPPED = 4;
|
||||
private static final long FLUSH_DELAY_IN_MS = 1000 * 5;
|
||||
|
||||
private static class NullOutputStream extends OutputStream {
|
||||
|
@ -94,11 +95,9 @@ public class ResearchLog {
|
|||
public synchronized void start() throws IOException {
|
||||
switch (mLoggingState) {
|
||||
case LOGGING_STATE_UNSTARTED:
|
||||
mJsonWriter = new JsonWriter(new BufferedWriter(new FileWriter(mFile)));
|
||||
mJsonWriter.setLenient(true);
|
||||
mJsonWriter.beginArray();
|
||||
mLoggingState = LOGGING_STATE_RUNNING;
|
||||
mLoggingState = LOGGING_STATE_READY;
|
||||
break;
|
||||
case LOGGING_STATE_READY:
|
||||
case LOGGING_STATE_RUNNING:
|
||||
case LOGGING_STATE_STOPPING:
|
||||
case LOGGING_STATE_STOPPED:
|
||||
|
@ -111,6 +110,7 @@ public class ResearchLog {
|
|||
case LOGGING_STATE_UNSTARTED:
|
||||
mLoggingState = LOGGING_STATE_STOPPED;
|
||||
break;
|
||||
case LOGGING_STATE_READY:
|
||||
case LOGGING_STATE_RUNNING:
|
||||
mExecutor.submit(new Callable<Object>() {
|
||||
@Override
|
||||
|
@ -120,14 +120,13 @@ public class ResearchLog {
|
|||
mJsonWriter.flush();
|
||||
mJsonWriter.close();
|
||||
} finally {
|
||||
// the contentprovider only exports data if the writable
|
||||
// bit is cleared.
|
||||
boolean success = mFile.setWritable(false, false);
|
||||
mLoggingState = LOGGING_STATE_STOPPED;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
});
|
||||
removeAnyScheduledFlush();
|
||||
mExecutor.shutdown();
|
||||
mLoggingState = LOGGING_STATE_STOPPING;
|
||||
break;
|
||||
|
@ -139,27 +138,26 @@ public class ResearchLog {
|
|||
public boolean isAlive() {
|
||||
switch (mLoggingState) {
|
||||
case LOGGING_STATE_UNSTARTED:
|
||||
case LOGGING_STATE_READY:
|
||||
case LOGGING_STATE_RUNNING:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void waitUntilStopped(int timeoutInMs) throws InterruptedException {
|
||||
public void waitUntilStopped(final int timeoutInMs) throws InterruptedException {
|
||||
removeAnyScheduledFlush();
|
||||
mExecutor.shutdown();
|
||||
mExecutor.awaitTermination(timeoutInMs, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
private boolean isAbortSuccessful;
|
||||
public boolean isAbortSuccessful() {
|
||||
return isAbortSuccessful;
|
||||
}
|
||||
|
||||
public synchronized void abort() {
|
||||
switch (mLoggingState) {
|
||||
case LOGGING_STATE_UNSTARTED:
|
||||
mLoggingState = LOGGING_STATE_STOPPED;
|
||||
isAbortSuccessful = true;
|
||||
break;
|
||||
case LOGGING_STATE_READY:
|
||||
case LOGGING_STATE_RUNNING:
|
||||
mExecutor.submit(new Callable<Object>() {
|
||||
@Override
|
||||
|
@ -173,6 +171,7 @@ public class ResearchLog {
|
|||
return null;
|
||||
}
|
||||
});
|
||||
removeAnyScheduledFlush();
|
||||
mExecutor.shutdown();
|
||||
mLoggingState = LOGGING_STATE_STOPPING;
|
||||
break;
|
||||
|
@ -181,10 +180,16 @@ public class ResearchLog {
|
|||
}
|
||||
}
|
||||
|
||||
private boolean isAbortSuccessful;
|
||||
public boolean isAbortSuccessful() {
|
||||
return isAbortSuccessful;
|
||||
}
|
||||
|
||||
/* package */ synchronized void flush() {
|
||||
switch (mLoggingState) {
|
||||
case LOGGING_STATE_UNSTARTED:
|
||||
break;
|
||||
case LOGGING_STATE_READY:
|
||||
case LOGGING_STATE_RUNNING:
|
||||
removeAnyScheduledFlush();
|
||||
mExecutor.submit(mFlushCallable);
|
||||
|
@ -197,7 +202,9 @@ public class ResearchLog {
|
|||
private Callable<Object> mFlushCallable = new Callable<Object>() {
|
||||
@Override
|
||||
public Object call() throws Exception {
|
||||
mJsonWriter.flush();
|
||||
if (mLoggingState == LOGGING_STATE_RUNNING) {
|
||||
mJsonWriter.flush();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
@ -220,6 +227,7 @@ public class ResearchLog {
|
|||
switch (mLoggingState) {
|
||||
case LOGGING_STATE_UNSTARTED:
|
||||
break;
|
||||
case LOGGING_STATE_READY:
|
||||
case LOGGING_STATE_RUNNING:
|
||||
mExecutor.submit(new Callable<Object>() {
|
||||
@Override
|
||||
|
@ -239,6 +247,7 @@ public class ResearchLog {
|
|||
switch (mLoggingState) {
|
||||
case LOGGING_STATE_UNSTARTED:
|
||||
break;
|
||||
case LOGGING_STATE_READY:
|
||||
case LOGGING_STATE_RUNNING:
|
||||
mExecutor.submit(new Callable<Object>() {
|
||||
@Override
|
||||
|
@ -260,6 +269,11 @@ public class ResearchLog {
|
|||
void outputEvent(final String[] keys, final Object[] values) {
|
||||
// not thread safe.
|
||||
try {
|
||||
if (mJsonWriter == NULL_JSON_WRITER) {
|
||||
mJsonWriter = new JsonWriter(new BufferedWriter(new FileWriter(mFile)));
|
||||
mJsonWriter.setLenient(true);
|
||||
mJsonWriter.beginArray();
|
||||
}
|
||||
mJsonWriter.beginObject();
|
||||
mJsonWriter.name(CURRENT_TIME_KEY).value(System.currentTimeMillis());
|
||||
mJsonWriter.name(UPTIME_KEY).value(SystemClock.uptimeMillis());
|
||||
|
|
|
@ -44,7 +44,6 @@ import com.android.inputmethod.latin.RichInputConnection.Range;
|
|||
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,13 +63,15 @@ 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
|
||||
/* package */ 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";
|
||||
/* 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 = false;
|
||||
|
||||
// constants related to specific log points
|
||||
private static final String WHITESPACE_SEPARATORS = " \t\n\r";
|
||||
|
@ -92,6 +93,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
|
|||
|
||||
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 +103,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;
|
||||
|
@ -124,7 +127,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 +134,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);
|
||||
|
||||
|
@ -146,6 +153,11 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
|
|||
}
|
||||
}
|
||||
mKeyboardSwitcher = keyboardSwitcher;
|
||||
mContext = ims;
|
||||
mPrefs = prefs;
|
||||
|
||||
// TODO: force user to decide at splash screen instead of defaulting to on.
|
||||
setLoggingAllowed(true);
|
||||
}
|
||||
|
||||
private void cleanupLoggingDir(final File dir, final long time) {
|
||||
|
@ -166,8 +178,10 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
|
|||
return new File(filesDir, sb.toString());
|
||||
}
|
||||
|
||||
public void start() {
|
||||
if (!sIsLogging) {
|
||||
private void start() {
|
||||
updateSuspendedState();
|
||||
requestIndicatorRedraw();
|
||||
if (!isAllowedToLog()) {
|
||||
// Log.w(TAG, "not in usability mode; not logging");
|
||||
return;
|
||||
}
|
||||
|
@ -175,10 +189,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 +203,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 +234,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
|
|||
if (mMainResearchLog.isAbortSuccessful()) {
|
||||
didAbortMainLog = true;
|
||||
}
|
||||
mMainResearchLog = null;
|
||||
}
|
||||
boolean didAbortIntentionalLog = false;
|
||||
if (mIntentionalResearchLog != null) {
|
||||
|
@ -221,6 +247,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
|
|||
if (mIntentionalResearchLog.isAbortSuccessful()) {
|
||||
didAbortIntentionalLog = true;
|
||||
}
|
||||
mIntentionalResearchLog = null;
|
||||
}
|
||||
return didAbortMainLog && didAbortIntentionalLog;
|
||||
}
|
||||
|
@ -247,6 +274,34 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
|
|||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
|
||||
if (key == null || prefs == null) {
|
||||
|
@ -256,13 +311,15 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
|
|||
if (sIsLogging == false) {
|
||||
abort();
|
||||
}
|
||||
requestIndicatorRedraw();
|
||||
}
|
||||
|
||||
/* package */ void presentResearchDialog(final LatinIME latinIME) {
|
||||
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) :
|
||||
showEnable ? latinIME.getString(R.string.enable_session_logging) :
|
||||
latinIME.getString(R.string.do_not_log_this_session),
|
||||
latinIME.getString(R.string.log_whole_session_history),
|
||||
};
|
||||
|
@ -277,25 +334,25 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
|
|||
Toast.LENGTH_LONG).show();
|
||||
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.notify_session_logging_enabled,
|
||||
Toast.LENGTH_LONG).show();
|
||||
} else {
|
||||
Toast toast = Toast.makeText(latinIME,
|
||||
R.string.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();
|
||||
}
|
||||
Toast.makeText(latinIME, R.string.notify_logging_suspended,
|
||||
Toast.LENGTH_LONG).show();
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
|
@ -328,13 +385,15 @@ 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) {
|
||||
if (mKeyboardSwitcher != null) {
|
||||
mKeyboardSwitcher.getKeyboardView().invalidateAllKeys();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -467,6 +526,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 +601,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,9 +623,62 @@ 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_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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
// Regular logging methods
|
||||
|
||||
private static final String[] EVENTKEYS_LATINKEYBOARDVIEW_PROCESSMOTIONEVENT = {
|
||||
"LatinKeyboardViewProcessMotionEvent", "action", "eventTime", "id", "x", "y", "size",
|
||||
"pressure"
|
||||
|
@ -611,19 +741,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"
|
||||
};
|
||||
|
@ -702,51 +819,10 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
|
|||
// Play it safe. Remove privacy-sensitive events.
|
||||
researchLogger.publishLogUnit(researchLogger.mCurrentLogUnit, true);
|
||||
researchLogger.mCurrentLogUnit = new LogUnit();
|
||||
getInstance().restart();
|
||||
}
|
||||
}
|
||||
|
||||
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",
|
||||
|
@ -873,6 +949,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
|
|||
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),
|
||||
|
|
|
@ -208,7 +208,8 @@ public class Settings extends InputMethodSettingsFragment
|
|||
if (ProductionFlag.IS_EXPERIMENTAL) {
|
||||
if (usabilityStudyPref instanceof CheckBoxPreference) {
|
||||
CheckBoxPreference checkbox = (CheckBoxPreference)usabilityStudyPref;
|
||||
checkbox.setChecked(prefs.getBoolean(PREF_USABILITY_STUDY_MODE, true));
|
||||
checkbox.setChecked(prefs.getBoolean(PREF_USABILITY_STUDY_MODE,
|
||||
ResearchLogger.DEFAULT_USABILITY_STUDY_MODE));
|
||||
checkbox.setSummary(R.string.settings_warning_researcher_mode);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue