Merge "add research log ui control"
This commit is contained in:
commit
9b300f0caa
7 changed files with 177 additions and 33 deletions
|
@ -26,6 +26,8 @@
|
||||||
<string name="english_ime_settings">Android keyboard settings</string>
|
<string name="english_ime_settings">Android keyboard settings</string>
|
||||||
<!-- Title for Latin keyboard input options dialog [CHAR LIMIT=25] -->
|
<!-- Title for Latin keyboard input options dialog [CHAR LIMIT=25] -->
|
||||||
<string name="english_ime_input_options">Input options</string>
|
<string name="english_ime_input_options">Input options</string>
|
||||||
|
<!-- Title for Latin keyboard research log dialog, which contains special commands for users that contribute data for research. [CHAR LIMIT=25] -->
|
||||||
|
<string name="english_ime_research_log">Research Log Commands</string>
|
||||||
|
|
||||||
<!-- Name of Android spell checker service -->
|
<!-- Name of Android spell checker service -->
|
||||||
<string name="spell_checker_service_name">Android spell checker</string>
|
<string name="spell_checker_service_name">Android spell checker</string>
|
||||||
|
@ -233,6 +235,20 @@
|
||||||
<!-- Title for input language selection screen -->
|
<!-- Title for input language selection screen -->
|
||||||
<string name="language_selection_title">Input languages</string>
|
<string name="language_selection_title">Input languages</string>
|
||||||
|
|
||||||
|
<!-- Title for dialog option that lets user mark a particular time in the log for later review by experts [CHAR LIMIT=25] -->
|
||||||
|
<string name="note_timestamp_for_researchlog">Note timestamp in log</string>
|
||||||
|
<!-- Toast notification message that the time has been marked for later review. [CHAR LIMIT=25] -->
|
||||||
|
<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=25] -->
|
||||||
|
<string name="do_not_log_this_session">Do not log this session</string>
|
||||||
|
<!-- Toast notification that the system is processing the request to delete the log for this session [CHAR LIMIT=25] -->
|
||||||
|
<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=25] -->
|
||||||
|
<string name="notify_session_log_deleted">Session log deleted</string>
|
||||||
|
<!-- Toast notification that the system has failed to delete the log for this session [CHAR LIMIT=25] -->
|
||||||
|
<string name="notify_session_log_not_deleted">Session log NOT deleted</string>
|
||||||
|
|
||||||
<!-- Preference for input language selection -->
|
<!-- Preference for input language selection -->
|
||||||
<string name="select_language">Input languages</string>
|
<string name="select_language">Input languages</string>
|
||||||
|
|
||||||
|
|
|
@ -22,23 +22,8 @@
|
||||||
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
|
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
|
||||||
>
|
>
|
||||||
<!-- Base key style for the key which may have settings or tab key as popup key. -->
|
<!-- Base key style for the key which may have settings or tab key as popup key. -->
|
||||||
<switch>
|
<include
|
||||||
<case
|
latin:keyboardLayout="@xml/key_styles_f1" />
|
||||||
latin:clobberSettingsKey="true"
|
|
||||||
>
|
|
||||||
<key-style
|
|
||||||
latin:styleName="f1MoreKeysStyle"
|
|
||||||
latin:backgroundType="functional" />
|
|
||||||
</case>
|
|
||||||
<!-- clobberSettingsKey="false" -->
|
|
||||||
<default>
|
|
||||||
<key-style
|
|
||||||
latin:styleName="f1MoreKeysStyle"
|
|
||||||
latin:keyLabelFlags="hasPopupHint"
|
|
||||||
latin:moreKeys="!text/settings_as_more_key"
|
|
||||||
latin:backgroundType="functional" />
|
|
||||||
</default>
|
|
||||||
</switch>
|
|
||||||
<!-- Functional key styles -->
|
<!-- Functional key styles -->
|
||||||
<switch>
|
<switch>
|
||||||
<case
|
<case
|
||||||
|
|
43
java/res/xml/key_styles_f1.xml
Normal file
43
java/res/xml/key_styles_f1.xml
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
/*
|
||||||
|
**
|
||||||
|
** Copyright 2012, The Android Open Source Project
|
||||||
|
**
|
||||||
|
** Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
** you may not use this file except in compliance with the License.
|
||||||
|
** You may obtain a copy of the License at
|
||||||
|
**
|
||||||
|
** http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
**
|
||||||
|
** Unless required by applicable law or agreed to in writing, software
|
||||||
|
** distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
** See the License for the specific language governing permissions and
|
||||||
|
** limitations under the License.
|
||||||
|
*/
|
||||||
|
-->
|
||||||
|
|
||||||
|
<merge
|
||||||
|
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
|
||||||
|
>
|
||||||
|
<!-- Base key style for the key which may have settings or tab key as popup key. -->
|
||||||
|
<!-- Kept as a separate file for cleaner overriding by an overlay. -->
|
||||||
|
<switch>
|
||||||
|
<case
|
||||||
|
latin:clobberSettingsKey="true"
|
||||||
|
>
|
||||||
|
<key-style
|
||||||
|
latin:styleName="f1MoreKeysStyle"
|
||||||
|
latin:backgroundType="functional" />
|
||||||
|
</case>
|
||||||
|
<!-- clobberSettingsKey="false" -->
|
||||||
|
<default>
|
||||||
|
<key-style
|
||||||
|
latin:styleName="f1MoreKeysStyle"
|
||||||
|
latin:keyLabelFlags="hasPopupHint"
|
||||||
|
latin:moreKeys="!text/settings_as_more_key"
|
||||||
|
latin:backgroundType="functional" />
|
||||||
|
</default>
|
||||||
|
</switch>
|
||||||
|
</merge>
|
|
@ -89,7 +89,8 @@ public class Keyboard {
|
||||||
private static final int MINIMUM_LETTER_CODE = CODE_TAB;
|
private static final int MINIMUM_LETTER_CODE = CODE_TAB;
|
||||||
|
|
||||||
/** Special keys code. Must be negative.
|
/** Special keys code. Must be negative.
|
||||||
* These should be aligned with values/keycodes.xml
|
* These should be aligned with KeyboardCodesSet.ID_TO_NAME[],
|
||||||
|
* KeyboardCodesSet.DEFAULT[] and KeyboardCodesSet.RTL[]
|
||||||
*/
|
*/
|
||||||
public static final int CODE_SHIFT = -1;
|
public static final int CODE_SHIFT = -1;
|
||||||
public static final int CODE_SWITCH_ALPHA_SYMBOL = -2;
|
public static final int CODE_SWITCH_ALPHA_SYMBOL = -2;
|
||||||
|
@ -101,8 +102,9 @@ public class Keyboard {
|
||||||
public static final int CODE_ACTION_NEXT = -8;
|
public static final int CODE_ACTION_NEXT = -8;
|
||||||
public static final int CODE_ACTION_PREVIOUS = -9;
|
public static final int CODE_ACTION_PREVIOUS = -9;
|
||||||
public static final int CODE_LANGUAGE_SWITCH = -10;
|
public static final int CODE_LANGUAGE_SWITCH = -10;
|
||||||
|
public static final int CODE_RESEARCH = -11;
|
||||||
// Code value representing the code is not specified.
|
// Code value representing the code is not specified.
|
||||||
public static final int CODE_UNSPECIFIED = -11;
|
public static final int CODE_UNSPECIFIED = -12;
|
||||||
|
|
||||||
public final KeyboardId mId;
|
public final KeyboardId mId;
|
||||||
public final int mThemeId;
|
public final int mThemeId;
|
||||||
|
|
|
@ -52,6 +52,7 @@ public class KeyboardCodesSet {
|
||||||
"key_action_next",
|
"key_action_next",
|
||||||
"key_action_previous",
|
"key_action_previous",
|
||||||
"key_language_switch",
|
"key_language_switch",
|
||||||
|
"key_research",
|
||||||
"key_unspecified",
|
"key_unspecified",
|
||||||
"key_left_parenthesis",
|
"key_left_parenthesis",
|
||||||
"key_right_parenthesis",
|
"key_right_parenthesis",
|
||||||
|
@ -86,6 +87,7 @@ public class KeyboardCodesSet {
|
||||||
Keyboard.CODE_ACTION_NEXT,
|
Keyboard.CODE_ACTION_NEXT,
|
||||||
Keyboard.CODE_ACTION_PREVIOUS,
|
Keyboard.CODE_ACTION_PREVIOUS,
|
||||||
Keyboard.CODE_LANGUAGE_SWITCH,
|
Keyboard.CODE_LANGUAGE_SWITCH,
|
||||||
|
Keyboard.CODE_RESEARCH,
|
||||||
Keyboard.CODE_UNSPECIFIED,
|
Keyboard.CODE_UNSPECIFIED,
|
||||||
CODE_LEFT_PARENTHESIS,
|
CODE_LEFT_PARENTHESIS,
|
||||||
CODE_RIGHT_PARENTHESIS,
|
CODE_RIGHT_PARENTHESIS,
|
||||||
|
@ -112,6 +114,7 @@ public class KeyboardCodesSet {
|
||||||
DEFAULT[11],
|
DEFAULT[11],
|
||||||
DEFAULT[12],
|
DEFAULT[12],
|
||||||
DEFAULT[13],
|
DEFAULT[13],
|
||||||
|
DEFAULT[14],
|
||||||
CODE_RIGHT_PARENTHESIS,
|
CODE_RIGHT_PARENTHESIS,
|
||||||
CODE_LEFT_PARENTHESIS,
|
CODE_LEFT_PARENTHESIS,
|
||||||
CODE_GREATER_THAN_SIGN,
|
CODE_GREATER_THAN_SIGN,
|
||||||
|
|
|
@ -1332,6 +1332,11 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
|
||||||
case Keyboard.CODE_LANGUAGE_SWITCH:
|
case Keyboard.CODE_LANGUAGE_SWITCH:
|
||||||
handleLanguageSwitchKey();
|
handleLanguageSwitchKey();
|
||||||
break;
|
break;
|
||||||
|
case Keyboard.CODE_RESEARCH:
|
||||||
|
if (ProductionFlag.IS_EXPERIMENTAL) {
|
||||||
|
ResearchLogger.getInstance().presentResearchDialog(this);
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
if (primaryCode == Keyboard.CODE_TAB
|
if (primaryCode == Keyboard.CODE_TAB
|
||||||
&& mInputAttributes.mEditorAction == EditorInfo.IME_ACTION_NEXT) {
|
&& mInputAttributes.mEditorAction == EditorInfo.IME_ACTION_NEXT) {
|
||||||
|
@ -2446,10 +2451,10 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
|
||||||
final AlertDialog.Builder builder = new AlertDialog.Builder(this)
|
final AlertDialog.Builder builder = new AlertDialog.Builder(this)
|
||||||
.setItems(items, listener)
|
.setItems(items, listener)
|
||||||
.setTitle(title);
|
.setTitle(title);
|
||||||
showOptionDialogInternal(builder.create());
|
showOptionDialog(builder.create());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void showOptionDialogInternal(AlertDialog dialog) {
|
/* package */ void showOptionDialog(AlertDialog dialog) {
|
||||||
final IBinder windowToken = mKeyboardSwitcher.getKeyboardView().getWindowToken();
|
final IBinder windowToken = mKeyboardSwitcher.getKeyboardView().getWindowToken();
|
||||||
if (windowToken == null) return;
|
if (windowToken == null) return;
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,8 @@ package com.android.inputmethod.latin;
|
||||||
|
|
||||||
import static com.android.inputmethod.latin.Constants.Subtype.ExtraValue.KEYBOARD_LAYOUT_SET;
|
import static com.android.inputmethod.latin.Constants.Subtype.ExtraValue.KEYBOARD_LAYOUT_SET;
|
||||||
|
|
||||||
|
import android.app.AlertDialog;
|
||||||
|
import android.content.DialogInterface;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.content.SharedPreferences.Editor;
|
import android.content.SharedPreferences.Editor;
|
||||||
import android.inputmethodservice.InputMethodService;
|
import android.inputmethodservice.InputMethodService;
|
||||||
|
@ -33,9 +35,9 @@ import android.view.MotionEvent;
|
||||||
import android.view.inputmethod.CompletionInfo;
|
import android.view.inputmethod.CompletionInfo;
|
||||||
import android.view.inputmethod.EditorInfo;
|
import android.view.inputmethod.EditorInfo;
|
||||||
import android.view.inputmethod.InputConnection;
|
import android.view.inputmethod.InputConnection;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
import com.android.inputmethod.keyboard.Key;
|
import com.android.inputmethod.keyboard.Key;
|
||||||
import com.android.inputmethod.keyboard.KeyDetector;
|
|
||||||
import com.android.inputmethod.keyboard.Keyboard;
|
import com.android.inputmethod.keyboard.Keyboard;
|
||||||
import com.android.inputmethod.keyboard.KeyboardId;
|
import com.android.inputmethod.keyboard.KeyboardId;
|
||||||
import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
|
import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
|
||||||
|
@ -134,12 +136,16 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
|
||||||
}
|
}
|
||||||
if (prefs != null) {
|
if (prefs != null) {
|
||||||
sIsLogging = prefs.getBoolean(PREF_USABILITY_STUDY_MODE, false);
|
sIsLogging = prefs.getBoolean(PREF_USABILITY_STUDY_MODE, false);
|
||||||
prefs.registerOnSharedPreferenceChangeListener(sInstance);
|
prefs.registerOnSharedPreferenceChangeListener(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized void start() {
|
public synchronized void start() {
|
||||||
Log.d(TAG, "start called");
|
Log.d(TAG, "start called");
|
||||||
|
if (!sIsLogging) {
|
||||||
|
// Log.w(TAG, "not in usability mode; not logging");
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (mFilesDir == null || !mFilesDir.exists()) {
|
if (mFilesDir == null || !mFilesDir.exists()) {
|
||||||
Log.w(TAG, "IME storage directory does not exist. Cannot start logging.");
|
Log.w(TAG, "IME storage directory does not exist. Cannot start logging.");
|
||||||
} else {
|
} else {
|
||||||
|
@ -192,16 +198,17 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
|
||||||
e1.printStackTrace();
|
e1.printStackTrace();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
} finally {
|
||||||
mJsonWriter = NULL_JSON_WRITER;
|
mJsonWriter = NULL_JSON_WRITER;
|
||||||
mFile = null;
|
mFile = null;
|
||||||
mLoggingState = LOGGING_STATE_OFF;
|
mLoggingState = LOGGING_STATE_OFF;
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
Log.d(TAG, "logfile closed");
|
Log.d(TAG, "logfile closed");
|
||||||
}
|
}
|
||||||
Log.d(TAG, "finished stop(), notifying");
|
Log.d(TAG, "finished stop(), notifying");
|
||||||
synchronized (ResearchLogger.this) {
|
synchronized (ResearchLogger.this) {
|
||||||
ResearchLogger.this.notify();
|
ResearchLogger.this.notify();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -213,6 +220,38 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public synchronized boolean abort() {
|
||||||
|
Log.d(TAG, "abort called");
|
||||||
|
boolean isLogFileDeleted = false;
|
||||||
|
if (mLoggingHandler != null && mLoggingState == LOGGING_STATE_ON) {
|
||||||
|
mLoggingState = LOGGING_STATE_STOPPING;
|
||||||
|
try {
|
||||||
|
Log.d(TAG, "closing jsonwriter");
|
||||||
|
mJsonWriter.endArray();
|
||||||
|
mJsonWriter.close();
|
||||||
|
} catch (IllegalStateException e1) {
|
||||||
|
// assume that this is just the json not being terminated properly.
|
||||||
|
// ignore
|
||||||
|
e1.printStackTrace();
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
} finally {
|
||||||
|
mJsonWriter = NULL_JSON_WRITER;
|
||||||
|
// delete file
|
||||||
|
final boolean isDeleted = mFile.delete();
|
||||||
|
if (isDeleted) {
|
||||||
|
isLogFileDeleted = true;
|
||||||
|
}
|
||||||
|
mFile = null;
|
||||||
|
mLoggingState = LOGGING_STATE_OFF;
|
||||||
|
if (DEBUG) {
|
||||||
|
Log.d(TAG, "logfile closed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return isLogFileDeleted;
|
||||||
|
}
|
||||||
|
|
||||||
/* package */ synchronized void flush() {
|
/* package */ synchronized void flush() {
|
||||||
try {
|
try {
|
||||||
mJsonWriter.flush();
|
mJsonWriter.flush();
|
||||||
|
@ -227,6 +266,50 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
sIsLogging = prefs.getBoolean(PREF_USABILITY_STUDY_MODE, false);
|
sIsLogging = prefs.getBoolean(PREF_USABILITY_STUDY_MODE, false);
|
||||||
|
if (sIsLogging == false) {
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* package */ void presentResearchDialog(final LatinIME latinIME) {
|
||||||
|
final CharSequence title = latinIME.getString(R.string.english_ime_research_log);
|
||||||
|
final CharSequence[] items = new CharSequence[] {
|
||||||
|
latinIME.getString(R.string.note_timestamp_for_researchlog),
|
||||||
|
latinIME.getString(R.string.do_not_log_this_session),
|
||||||
|
};
|
||||||
|
final DialogInterface.OnClickListener listener = new DialogInterface.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(DialogInterface di, int position) {
|
||||||
|
di.dismiss();
|
||||||
|
switch (position) {
|
||||||
|
case 0:
|
||||||
|
ResearchLogger.getInstance().userTimestamp();
|
||||||
|
Toast.makeText(latinIME, R.string.notify_recorded_timestamp,
|
||||||
|
Toast.LENGTH_LONG).show();
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
Toast toast = Toast.makeText(latinIME,
|
||||||
|
R.string.notify_session_log_deleting, Toast.LENGTH_LONG);
|
||||||
|
toast.show();
|
||||||
|
final ResearchLogger logger = ResearchLogger.getInstance();
|
||||||
|
boolean isLogDeleted = logger.abort();
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
final AlertDialog.Builder builder = new AlertDialog.Builder(latinIME)
|
||||||
|
.setItems(items, listener)
|
||||||
|
.setTitle(title);
|
||||||
|
latinIME.showOptionDialog(builder.create());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final String CURRENT_TIME_KEY = "_ct";
|
private static final String CURRENT_TIME_KEY = "_ct";
|
||||||
|
@ -756,4 +839,11 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
|
||||||
getInstance().writeEvent(EVENTKEYS_SUGGESTIONSVIEW_SETSUGGESTIONS, values);
|
getInstance().writeEvent(EVENTKEYS_SUGGESTIONSVIEW_SETSUGGESTIONS, values);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static final String[] EVENTKEYS_USER_TIMESTAMP = {
|
||||||
|
"UserTimestamp"
|
||||||
|
};
|
||||||
|
public void userTimestamp() {
|
||||||
|
getInstance().writeEvent(EVENTKEYS_USER_TIMESTAMP, EVENTKEYS_NULLVALUES);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue