ResearchLogger: make logging more reliable (esp on startup)

Bug: 6188932
Change-Id: I692e427ba2e6da7bb15f48208304c4a034392a22
main
Kurt Partridge 2012-07-18 13:52:41 -07:00
parent 9370ab9ada
commit 0df487678e
5 changed files with 197 additions and 107 deletions

View File

@ -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>

View File

@ -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();

View File

@ -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 {
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());

View File

@ -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;
}
try {
if (mMainResearchLog == null || !mMainResearchLog.isAlive()) {
mMainResearchLog = new ResearchLog(createLogFile(mFilesDir));
}
try {
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.makeText(latinIME, R.string.notify_logging_suspended,
Toast.LENGTH_LONG).show();
} else {
Toast.makeText(latinIME,
R.string.notify_session_log_not_deleted, Toast.LENGTH_LONG)
.show();
}
}
break;
case 2:
@ -328,15 +385,17 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
}
private boolean isAllowedToLog() {
return !mIsPasswordView && !mIsLoggingSuspended;
return !mIsPasswordView && !mIsLoggingSuspended && sIsLogging;
}
public void requestIndicatorRedraw() {
// invalidate any existing graphics
if (IS_SHOWING_INDICATOR) {
if (mKeyboardSwitcher != null) {
mKeyboardSwitcher.getKeyboardView().invalidateAllKeys();
}
}
}
private static final String CURRENT_TIME_KEY = "_ct";
private static final String UPTIME_KEY = "_ut";
@ -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),

View File

@ -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);
}
}