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>
|
||||
<!-- Title for Latin keyboard input options dialog [CHAR LIMIT=25] -->
|
||||
<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 -->
|
||||
<string name="spell_checker_service_name">Android spell checker</string>
|
||||
|
@ -233,6 +235,20 @@
|
|||
<!-- Title for input language selection screen -->
|
||||
<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 -->
|
||||
<string name="select_language">Input languages</string>
|
||||
|
||||
|
|
|
@ -22,23 +22,8 @@
|
|||
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. -->
|
||||
<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>
|
||||
<include
|
||||
latin:keyboardLayout="@xml/key_styles_f1" />
|
||||
<!-- Functional key styles -->
|
||||
<switch>
|
||||
<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;
|
||||
|
||||
/** 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_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_PREVIOUS = -9;
|
||||
public static final int CODE_LANGUAGE_SWITCH = -10;
|
||||
public static final int CODE_RESEARCH = -11;
|
||||
// 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 int mThemeId;
|
||||
|
|
|
@ -52,6 +52,7 @@ public class KeyboardCodesSet {
|
|||
"key_action_next",
|
||||
"key_action_previous",
|
||||
"key_language_switch",
|
||||
"key_research",
|
||||
"key_unspecified",
|
||||
"key_left_parenthesis",
|
||||
"key_right_parenthesis",
|
||||
|
@ -86,6 +87,7 @@ public class KeyboardCodesSet {
|
|||
Keyboard.CODE_ACTION_NEXT,
|
||||
Keyboard.CODE_ACTION_PREVIOUS,
|
||||
Keyboard.CODE_LANGUAGE_SWITCH,
|
||||
Keyboard.CODE_RESEARCH,
|
||||
Keyboard.CODE_UNSPECIFIED,
|
||||
CODE_LEFT_PARENTHESIS,
|
||||
CODE_RIGHT_PARENTHESIS,
|
||||
|
@ -112,6 +114,7 @@ public class KeyboardCodesSet {
|
|||
DEFAULT[11],
|
||||
DEFAULT[12],
|
||||
DEFAULT[13],
|
||||
DEFAULT[14],
|
||||
CODE_RIGHT_PARENTHESIS,
|
||||
CODE_LEFT_PARENTHESIS,
|
||||
CODE_GREATER_THAN_SIGN,
|
||||
|
|
|
@ -1332,6 +1332,11 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
|
|||
case Keyboard.CODE_LANGUAGE_SWITCH:
|
||||
handleLanguageSwitchKey();
|
||||
break;
|
||||
case Keyboard.CODE_RESEARCH:
|
||||
if (ProductionFlag.IS_EXPERIMENTAL) {
|
||||
ResearchLogger.getInstance().presentResearchDialog(this);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (primaryCode == Keyboard.CODE_TAB
|
||||
&& 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)
|
||||
.setItems(items, listener)
|
||||
.setTitle(title);
|
||||
showOptionDialogInternal(builder.create());
|
||||
showOptionDialog(builder.create());
|
||||
}
|
||||
|
||||
private void showOptionDialogInternal(AlertDialog dialog) {
|
||||
/* package */ void showOptionDialog(AlertDialog dialog) {
|
||||
final IBinder windowToken = mKeyboardSwitcher.getKeyboardView().getWindowToken();
|
||||
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 android.app.AlertDialog;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.SharedPreferences.Editor;
|
||||
import android.inputmethodservice.InputMethodService;
|
||||
|
@ -33,9 +35,9 @@ import android.view.MotionEvent;
|
|||
import android.view.inputmethod.CompletionInfo;
|
||||
import android.view.inputmethod.EditorInfo;
|
||||
import android.view.inputmethod.InputConnection;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.android.inputmethod.keyboard.Key;
|
||||
import com.android.inputmethod.keyboard.KeyDetector;
|
||||
import com.android.inputmethod.keyboard.Keyboard;
|
||||
import com.android.inputmethod.keyboard.KeyboardId;
|
||||
import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
|
||||
|
@ -134,12 +136,16 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
|
|||
}
|
||||
if (prefs != null) {
|
||||
sIsLogging = prefs.getBoolean(PREF_USABILITY_STUDY_MODE, false);
|
||||
prefs.registerOnSharedPreferenceChangeListener(sInstance);
|
||||
prefs.registerOnSharedPreferenceChangeListener(this);
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void start() {
|
||||
Log.d(TAG, "start called");
|
||||
if (!sIsLogging) {
|
||||
// Log.w(TAG, "not in usability mode; not logging");
|
||||
return;
|
||||
}
|
||||
if (mFilesDir == null || !mFilesDir.exists()) {
|
||||
Log.w(TAG, "IME storage directory does not exist. Cannot start logging.");
|
||||
} else {
|
||||
|
@ -192,16 +198,17 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
|
|||
e1.printStackTrace();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
mJsonWriter = NULL_JSON_WRITER;
|
||||
mFile = null;
|
||||
mLoggingState = LOGGING_STATE_OFF;
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "logfile closed");
|
||||
}
|
||||
Log.d(TAG, "finished stop(), notifying");
|
||||
synchronized (ResearchLogger.this) {
|
||||
ResearchLogger.this.notify();
|
||||
} finally {
|
||||
mJsonWriter = NULL_JSON_WRITER;
|
||||
mFile = null;
|
||||
mLoggingState = LOGGING_STATE_OFF;
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "logfile closed");
|
||||
}
|
||||
Log.d(TAG, "finished stop(), notifying");
|
||||
synchronized (ResearchLogger.this) {
|
||||
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() {
|
||||
try {
|
||||
mJsonWriter.flush();
|
||||
|
@ -227,6 +266,50 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
|
|||
return;
|
||||
}
|
||||
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";
|
||||
|
@ -756,4 +839,11 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
|
|||
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