Merge "[B9] Pass the client id parameter for dict info requests"
diff --git a/java/res/layout/research_feedback_fragment_layout.xml b/java/res/layout/research_feedback_fragment_layout.xml
index 2725e7f..2915a77 100644
--- a/java/res/layout/research_feedback_fragment_layout.xml
+++ b/java/res/layout/research_feedback_fragment_layout.xml
@@ -63,7 +63,7 @@
android:minLines="2"
android:scrollbars="vertical"
android:hint="@string/research_feedback_hint"
- android:inputType="textMultiLine">
+ android:inputType="textMultiLine|textCapSentences">
<requestFocus />
</EditText>
<CheckBox
diff --git a/java/res/values-es-rUS/strings.xml b/java/res/values-es-rUS/strings.xml
index 51a6dcc..53d7598 100644
--- a/java/res/values-es-rUS/strings.xml
+++ b/java/res/values-es-rUS/strings.xml
@@ -40,7 +40,7 @@
<string name="show_language_switch_key" msgid="5915478828318774384">"Tecla de selección de idioma"</string>
<string name="show_language_switch_key_summary" msgid="7343403647474265713">"Mostrar cuando se habiliten varios idiomas de entrada"</string>
<string name="sliding_key_input_preview" msgid="6604262359510068370">"Mostrar indicador p. deslizar"</string>
- <string name="sliding_key_input_preview_summary" msgid="6340524345729093886">"Mostrar indic. visual mientras se desliza de tecl. símb. o mayús"</string>
+ <string name="sliding_key_input_preview_summary" msgid="6340524345729093886">"Mostrar indic. visual al deslizar de teclas símbolo o mayúscula"</string>
<string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"Retraso en rechazo de alerta de tecla"</string>
<string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Sin demora"</string>
<string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Predeterminada"</string>
diff --git a/java/res/values-hr/strings.xml b/java/res/values-hr/strings.xml
index 78fba96..8432ed5 100644
--- a/java/res/values-hr/strings.xml
+++ b/java/res/values-hr/strings.xml
@@ -40,7 +40,7 @@
<string name="show_language_switch_key" msgid="5915478828318774384">"Tipka za izmjenjivanje jezika"</string>
<string name="show_language_switch_key_summary" msgid="7343403647474265713">"Prikaži kada je omogućen unos na više jezika"</string>
<string name="sliding_key_input_preview" msgid="6604262359510068370">"Prikaži pokazivač klizanja"</string>
- <string name="sliding_key_input_preview_summary" msgid="6340524345729093886">"Prikaži vizualni znak tijekom klizanja od tipki Shift ili Simbol"</string>
+ <string name="sliding_key_input_preview_summary" msgid="6340524345729093886">"Prikaži vizualni znak tijekom klizanja od tipke Shift ili tipki sa znakovima"</string>
<string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"Odgoda prikaza tipki"</string>
<string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Bez odgode"</string>
<string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Zadano"</string>
diff --git a/java/res/values-ro/strings.xml b/java/res/values-ro/strings.xml
index bb80542..5c6ff3f 100644
--- a/java/res/values-ro/strings.xml
+++ b/java/res/values-ro/strings.xml
@@ -40,7 +40,7 @@
<string name="show_language_switch_key" msgid="5915478828318774384">"Tastă comutare limbi"</string>
<string name="show_language_switch_key_summary" msgid="7343403647474265713">"Afişaţi când sunt activate mai multe limbi de intrare"</string>
<string name="sliding_key_input_preview" msgid="6604262359510068370">"Afișați indicator glisare"</string>
- <string name="sliding_key_input_preview_summary" msgid="6340524345729093886">"Afișați sugestie vizuală la glisarea de la Shift sau Simbol"</string>
+ <string name="sliding_key_input_preview_summary" msgid="6340524345729093886">"Afișați un indicator în timpul glisării de la Shift sau tasta de simboluri"</string>
<string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"Înt. înch. pop-up esenţ."</string>
<string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Fără întârziere"</string>
<string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Prestabilit"</string>
diff --git a/java/res/values-zh-rCN/strings.xml b/java/res/values-zh-rCN/strings.xml
index 6ee06d8..bc94938 100644
--- a/java/res/values-zh-rCN/strings.xml
+++ b/java/res/values-zh-rCN/strings.xml
@@ -39,7 +39,7 @@
<string name="include_other_imes_in_language_switch_list_summary" msgid="840637129103317635">"语言切换键也可用于切换其他输入法"</string>
<string name="show_language_switch_key" msgid="5915478828318774384">"语言切换键"</string>
<string name="show_language_switch_key_summary" msgid="7343403647474265713">"启用了多种输入语言时显示"</string>
- <string name="sliding_key_input_preview" msgid="6604262359510068370">"显示滑动指示器"</string>
+ <string name="sliding_key_input_preview" msgid="6604262359510068370">"显示滑动指示效果"</string>
<string name="sliding_key_input_preview_summary" msgid="6340524345729093886">"从 Shift 键或符号键滑动时显示视觉提示"</string>
<string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"弹出字符隐藏延迟"</string>
<string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"无延迟"</string>
diff --git a/java/res/values/research_strings.xml b/java/res/values/research_strings.xml
index f67943e..e738711 100644
--- a/java/res/values/research_strings.xml
+++ b/java/res/values/research_strings.xml
@@ -21,8 +21,20 @@
<!-- Contents of note explaining what data is collected and how. -->
<!-- TODO: remove translatable=false attribute once text is stable -->
<string name="research_splash_content" translatable="false"></string>
+ <!-- Account type allowed for inclusion in user-invoked feedback logs [CHAR LIMIT=38] -->
<string name="research_account_type" translatable="false"></string>
+ <!-- Account domain allowed for inclusion in user-invoked feedback logs [CHAR LIMIT=38] -->
<string name="research_allowed_account_domain" translatable="false"></string>
+
+ <!-- Menu option that lets user send feedback for research purposes about the IME [CHAR LIMIT=38] -->
+ <!-- TODO: remove translatable=false attribute once text is stable -->
+ <string name="research_feedback_menu_option" translatable="false">Send feedback</string>
+ <!-- Title of dialog box that lets user send feedback for research purposes about the IME [CHAR LIMIT=38] -->
+ <!-- TODO: remove translatable=false attribute once text is stable -->
+ <string name="research_feedback_dialog_title" translatable="false">Send feedback</string>
+ <!-- Hint to user about the text entry field where they should enter research feedback [CHAR LIMIT=40] -->
+ <!-- TODO: remove translatable=false attribute once text is stable -->
+ <string name="research_feedback_hint" translatable="false">Enter your feedback here.</string>
<!-- Message informing the user that the feedback string must not be empty [CHAR LIMIT=100] -->
<!-- TODO: remove translatable=false attribute once text is stable -->
<string name="research_feedback_empty_feedback_error_message" translatable="false">The feedback field must not be empty.</string>
diff --git a/java/res/values/strings.xml b/java/res/values/strings.xml
index bab612b..ee79b45 100644
--- a/java/res/values/strings.xml
+++ b/java/res/values/strings.xml
@@ -71,7 +71,7 @@
<!-- Option to enable sliding key input indicator. The user can see a rubber band-like effect during sliding key input. [CHAR LIMIT=30]-->
<string name="sliding_key_input_preview">Show slide indicator</string>
- <!-- Option summary to enable sliding key input indicator. The user can see a rubber band-like effect during sliding key input. [CHAR LIMIT=65]-->
+ <!-- Option summary to enable sliding key input indicator. The user can see a rubber band-like effect during sliding key input. [CHAR LIMIT=66]-->
<string name="sliding_key_input_preview_summary">Display visual cue while sliding from Shift or Symbol keys</string>
<!-- Option for the dismiss delay of the key popup [CHAR LIMIT=25] -->
@@ -266,12 +266,6 @@
<!-- TODO: remove translatable=false attribute once text is stable -->
<string name="research_notify_session_logging_enabled" translatable="false">Session logging enabled</string>
- <!-- Menu option that lets user send feedback for research purposes about the IME [CHAR LIMIT=38] -->
- <!-- TODO: remove translatable=false attribute once text is stable -->
- <string name="research_feedback_menu_option" translatable="false">Send feedback</string>
- <!-- Dialog box title that lets user send feedback for research purposes about the IME [CHAR LIMIT=38] -->
- <!-- TODO: remove translatable=false attribute once text is stable -->
- <string name="research_feedback_dialog_title" translatable="false">Send feedback</string>
<!-- Text for checkbox option to include user data in feedback for research purposes [CHAR LIMIT=50] -->
<!-- TODO: remove translatable=false attribute once text is stable -->
<string name="research_feedback_include_history_label" translatable="false">Include session history</string>
@@ -281,9 +275,6 @@
<!-- Text for checkbox option to include a recording in feedback for research purposes [CHAR LIMIT=50] -->
<!-- TODO: remove translatable=false attribute once text is stable -->
<string name="research_feedback_include_recording_label" translatable="false">Include recorded demonstration</string>
- <!-- Hint to user about the text entry field where they should enter research feedback [CHAR LIMIT=40] -->
- <!-- TODO: remove translatable=false attribute once text is stable -->
- <string name="research_feedback_hint" translatable="false">Enter your feedback here.</string>
<!-- Dialog button choice to send research feedback [CHAR LIMIT=35] -->
<!-- TODO: remove translatable=false attribute once text is stable -->
<string name="research_feedback_send" translatable="false">Send</string>
diff --git a/java/src/com/android/inputmethod/compat/CompatUtils.java b/java/src/com/android/inputmethod/compat/CompatUtils.java
index a82103a..5a2b6bd 100644
--- a/java/src/com/android/inputmethod/compat/CompatUtils.java
+++ b/java/src/com/android/inputmethod/compat/CompatUtils.java
@@ -16,7 +16,6 @@
package com.android.inputmethod.compat;
-import android.content.Intent;
import android.text.TextUtils;
import android.util.Log;
@@ -26,23 +25,9 @@
public final class CompatUtils {
private static final String TAG = CompatUtils.class.getSimpleName();
- private static final String EXTRA_INPUT_METHOD_ID = "input_method_id";
- // TODO: Can these be constants instead of literal String constants?
- private static final String INPUT_METHOD_SUBTYPE_SETTINGS =
- "android.settings.INPUT_METHOD_SUBTYPE_SETTINGS";
- public static Intent getInputLanguageSelectionIntent(final String inputMethodId,
- final int flagsForSubtypeSettings) {
- // Refer to android.provider.Settings.ACTION_INPUT_METHOD_SUBTYPE_SETTINGS
- final String action = INPUT_METHOD_SUBTYPE_SETTINGS;
- final Intent intent = new Intent(action);
- if (!TextUtils.isEmpty(inputMethodId)) {
- intent.putExtra(EXTRA_INPUT_METHOD_ID, inputMethodId);
- }
- if (flagsForSubtypeSettings > 0) {
- intent.setFlags(flagsForSubtypeSettings);
- }
- return intent;
+ private CompatUtils() {
+ // This utility class is not publicly instantiable.
}
public static Class<?> getClass(final String className) {
diff --git a/java/src/com/android/inputmethod/latin/AdditionalSubtypeSettings.java b/java/src/com/android/inputmethod/latin/AdditionalSubtypeSettings.java
index f787722..ff5e339 100644
--- a/java/src/com/android/inputmethod/latin/AdditionalSubtypeSettings.java
+++ b/java/src/com/android/inputmethod/latin/AdditionalSubtypeSettings.java
@@ -44,8 +44,6 @@
import android.widget.SpinnerAdapter;
import android.widget.Toast;
-import com.android.inputmethod.compat.CompatUtils;
-
import java.util.ArrayList;
import java.util.TreeSet;
@@ -519,7 +517,7 @@
.setPositiveButton(R.string.enable, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
- final Intent intent = CompatUtils.getInputLanguageSelectionIntent(
+ final Intent intent = IntentUtils.getInputLanguageSelectionIntent(
mRichImm.getInputMethodIdOfThisIme(),
Intent.FLAG_ACTIVITY_NEW_TASK
| Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
diff --git a/java/src/com/android/inputmethod/latin/IntentUtils.java b/java/src/com/android/inputmethod/latin/IntentUtils.java
new file mode 100644
index 0000000..d175af5
--- /dev/null
+++ b/java/src/com/android/inputmethod/latin/IntentUtils.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2013 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.
+ */
+
+package com.android.inputmethod.latin;
+
+import android.content.Intent;
+import android.text.TextUtils;
+
+public final class IntentUtils {
+ private static final String EXTRA_INPUT_METHOD_ID = "input_method_id";
+ // TODO: Can these be constants instead of literal String constants?
+ private static final String INPUT_METHOD_SUBTYPE_SETTINGS =
+ "android.settings.INPUT_METHOD_SUBTYPE_SETTINGS";
+
+ private IntentUtils() {
+ // This utility class is not publicly instantiable.
+ }
+
+ public static Intent getInputLanguageSelectionIntent(final String inputMethodId,
+ final int flagsForSubtypeSettings) {
+ // Refer to android.provider.Settings.ACTION_INPUT_METHOD_SUBTYPE_SETTINGS
+ final String action = INPUT_METHOD_SUBTYPE_SETTINGS;
+ final Intent intent = new Intent(action);
+ if (!TextUtils.isEmpty(inputMethodId)) {
+ intent.putExtra(EXTRA_INPUT_METHOD_ID, inputMethodId);
+ }
+ if (flagsForSubtypeSettings > 0) {
+ intent.setFlags(flagsForSubtypeSettings);
+ }
+ return intent;
+ }
+}
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index 0821732..1c49bb0 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -62,7 +62,6 @@
import com.android.inputmethod.accessibility.AccessibilityUtils;
import com.android.inputmethod.accessibility.AccessibleKeyboardViewProxy;
import com.android.inputmethod.annotations.UsedForTesting;
-import com.android.inputmethod.compat.CompatUtils;
import com.android.inputmethod.compat.InputMethodServiceCompatUtils;
import com.android.inputmethod.compat.SuggestionSpanUtils;
import com.android.inputmethod.event.EventInterpreter;
@@ -2512,7 +2511,7 @@
di.dismiss();
switch (position) {
case 0:
- Intent intent = CompatUtils.getInputLanguageSelectionIntent(
+ final Intent intent = IntentUtils.getInputLanguageSelectionIntent(
mRichImm.getInputMethodIdOfThisIme(),
Intent.FLAG_ACTIVITY_NEW_TASK
| Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
diff --git a/java/src/com/android/inputmethod/research/FeedbackFragment.java b/java/src/com/android/inputmethod/research/FeedbackFragment.java
index 69ddf82..39f9c87 100644
--- a/java/src/com/android/inputmethod/research/FeedbackFragment.java
+++ b/java/src/com/android/inputmethod/research/FeedbackFragment.java
@@ -36,8 +36,8 @@
public class FeedbackFragment extends Fragment implements OnClickListener {
private static final String TAG = FeedbackFragment.class.getSimpleName();
- private static final String KEY_FEEDBACK_STRING = "FeedbackString";
- private static final String KEY_INCLUDE_ACCOUNT_NAME = "IncludeAccountName";
+ public static final String KEY_FEEDBACK_STRING = "FeedbackString";
+ public static final String KEY_INCLUDE_ACCOUNT_NAME = "IncludeAccountName";
public static final String KEY_HAS_USER_RECORDING = "HasRecording";
private EditText mEditText;
diff --git a/java/src/com/android/inputmethod/research/LogStatement.java b/java/src/com/android/inputmethod/research/LogStatement.java
index 1d83e1a..059146a 100644
--- a/java/src/com/android/inputmethod/research/LogStatement.java
+++ b/java/src/com/android/inputmethod/research/LogStatement.java
@@ -16,6 +16,18 @@
package com.android.inputmethod.research;
+import android.content.SharedPreferences;
+import android.util.JsonWriter;
+import android.util.Log;
+import android.view.MotionEvent;
+import android.view.inputmethod.CompletionInfo;
+
+import com.android.inputmethod.keyboard.Key;
+import com.android.inputmethod.latin.SuggestedWords;
+import com.android.inputmethod.latin.define.ProductionFlag;
+
+import java.io.IOException;
+
/**
* A template for typed information stored in the logs.
*
@@ -24,6 +36,9 @@
* actual values are stored separately.
*/
class LogStatement {
+ private static final String TAG = LogStatement.class.getSimpleName();
+ private static final boolean DEBUG = false && ProductionFlag.IS_EXPERIMENTAL_DEBUG;
+
// Constants for particular statements
public static final String TYPE_POINTER_TRACKER_CALL_LISTENER_ON_CODE_INPUT =
"PointerTrackerCallListenerOnCodeInput";
@@ -36,6 +51,11 @@
public static final String TYPE_MOTION_EVENT = "MotionEvent";
public static final String KEY_IS_LOGGING_RELATED = "isLoggingRelated";
+ // Keys for internal key/value pairs
+ private static final String CURRENT_TIME_KEY = "_ct";
+ private static final String UPTIME_KEY = "_ut";
+ private static final String EVENT_TYPE_KEY = "_ty";
+
// Name specifying the LogStatement type.
private final String mType;
@@ -142,4 +162,61 @@
}
return false;
}
+
+ /**
+ * Write the contents out through jsonWriter.
+ *
+ * Note that this method is not thread safe for the same jsonWriter. Callers must ensure
+ * thread safety.
+ */
+ public boolean outputToLocked(final JsonWriter jsonWriter, final Long time,
+ final Object... values) {
+ if (DEBUG) {
+ if (mKeys.length != values.length) {
+ Log.d(TAG, "Key and Value list sizes do not match. " + mType);
+ }
+ }
+ try {
+ jsonWriter.beginObject();
+ jsonWriter.name(CURRENT_TIME_KEY).value(System.currentTimeMillis());
+ jsonWriter.name(UPTIME_KEY).value(time);
+ jsonWriter.name(EVENT_TYPE_KEY).value(mType);
+ final int length = values.length;
+ for (int i = 0; i < length; i++) {
+ jsonWriter.name(mKeys[i]);
+ final Object value = values[i];
+ if (value instanceof CharSequence) {
+ jsonWriter.value(value.toString());
+ } else if (value instanceof Number) {
+ jsonWriter.value((Number) value);
+ } else if (value instanceof Boolean) {
+ jsonWriter.value((Boolean) value);
+ } else if (value instanceof CompletionInfo[]) {
+ JsonUtils.writeJson((CompletionInfo[]) value, jsonWriter);
+ } else if (value instanceof SharedPreferences) {
+ JsonUtils.writeJson((SharedPreferences) value, jsonWriter);
+ } else if (value instanceof Key[]) {
+ JsonUtils.writeJson((Key[]) value, jsonWriter);
+ } else if (value instanceof SuggestedWords) {
+ JsonUtils.writeJson((SuggestedWords) value, jsonWriter);
+ } else if (value instanceof MotionEvent) {
+ JsonUtils.writeJson((MotionEvent) value, jsonWriter);
+ } else if (value == null) {
+ jsonWriter.nullValue();
+ } else {
+ if (DEBUG) {
+ Log.w(TAG, "Unrecognized type to be logged: "
+ + (value == null ? "<null>" : value.getClass().getName()));
+ }
+ jsonWriter.nullValue();
+ }
+ }
+ jsonWriter.endObject();
+ } catch (IOException e) {
+ e.printStackTrace();
+ Log.w(TAG, "Error in JsonWriter; skipping LogStatement");
+ return false;
+ }
+ return true;
+ }
}
diff --git a/java/src/com/android/inputmethod/research/LogUnit.java b/java/src/com/android/inputmethod/research/LogUnit.java
index 2e732fc..a584a3a 100644
--- a/java/src/com/android/inputmethod/research/LogUnit.java
+++ b/java/src/com/android/inputmethod/research/LogUnit.java
@@ -17,13 +17,11 @@
package com.android.inputmethod.research;
import android.content.SharedPreferences;
+import android.os.SystemClock;
import android.text.TextUtils;
import android.util.JsonWriter;
import android.util.Log;
-import android.view.MotionEvent;
-import android.view.inputmethod.CompletionInfo;
-import com.android.inputmethod.keyboard.Key;
import com.android.inputmethod.latin.SuggestedWords;
import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
import com.android.inputmethod.latin.define.ProductionFlag;
@@ -153,11 +151,10 @@
jsonWriter = researchLog.getValidJsonWriterLocked();
outputLogUnitStart(jsonWriter, canIncludePrivateData);
}
- outputLogStatementToLocked(jsonWriter, mLogStatementList.get(i), mValuesList.get(i),
- mTimeList.get(i));
+ logStatement.outputToLocked(jsonWriter, mTimeList.get(i), mValuesList.get(i));
if (DEBUG) {
- outputLogStatementToLocked(debugJsonWriter, mLogStatementList.get(i),
- mValuesList.get(i), mTimeList.get(i));
+ logStatement.outputToLocked(debugJsonWriter, mTimeList.get(i),
+ mValuesList.get(i));
}
}
if (jsonWriter != null) {
@@ -180,97 +177,34 @@
}
}
- private static final String CURRENT_TIME_KEY = "_ct";
- private static final String UPTIME_KEY = "_ut";
- private static final String EVENT_TYPE_KEY = "_ty";
private static final String WORD_KEY = "_wo";
private static final String CORRECTION_TYPE_KEY = "_corType";
private static final String LOG_UNIT_BEGIN_KEY = "logUnitStart";
private static final String LOG_UNIT_END_KEY = "logUnitEnd";
+ final LogStatement LOGSTATEMENT_LOG_UNIT_BEGIN_WITH_PRIVATE_DATA =
+ new LogStatement(LOG_UNIT_BEGIN_KEY, false /* isPotentiallyPrivate */,
+ false /* isPotentiallyRevealing */, WORD_KEY, CORRECTION_TYPE_KEY);
+ final LogStatement LOGSTATEMENT_LOG_UNIT_BEGIN_WITHOUT_PRIVATE_DATA =
+ new LogStatement(LOG_UNIT_BEGIN_KEY, false /* isPotentiallyPrivate */,
+ false /* isPotentiallyRevealing */);
private void outputLogUnitStart(final JsonWriter jsonWriter,
final boolean canIncludePrivateData) {
- try {
- jsonWriter.beginObject();
- jsonWriter.name(CURRENT_TIME_KEY).value(System.currentTimeMillis());
- if (canIncludePrivateData) {
- jsonWriter.name(WORD_KEY).value(getWord());
- jsonWriter.name(CORRECTION_TYPE_KEY).value(getCorrectionType());
- }
- jsonWriter.name(EVENT_TYPE_KEY).value(LOG_UNIT_BEGIN_KEY);
- jsonWriter.endObject();
- } catch (IOException e) {
- e.printStackTrace();
- Log.w(TAG, "Error in JsonWriter; cannot write LogUnitStart");
+ final LogStatement logStatement;
+ if (canIncludePrivateData) {
+ LOGSTATEMENT_LOG_UNIT_BEGIN_WITH_PRIVATE_DATA.outputToLocked(jsonWriter,
+ SystemClock.uptimeMillis(), getWord(), getCorrectionType());
+ } else {
+ LOGSTATEMENT_LOG_UNIT_BEGIN_WITHOUT_PRIVATE_DATA.outputToLocked(jsonWriter,
+ SystemClock.uptimeMillis());
}
}
+ final LogStatement LOGSTATEMENT_LOG_UNIT_END =
+ new LogStatement(LOG_UNIT_END_KEY, false /* isPotentiallyPrivate */,
+ false /* isPotentiallyRevealing */);
private void outputLogUnitStop(final JsonWriter jsonWriter) {
- try {
- jsonWriter.beginObject();
- jsonWriter.name(CURRENT_TIME_KEY).value(System.currentTimeMillis());
- jsonWriter.name(EVENT_TYPE_KEY).value(LOG_UNIT_END_KEY);
- jsonWriter.endObject();
- } catch (IOException e) {
- e.printStackTrace();
- Log.w(TAG, "Error in JsonWriter; cannot write LogUnitStop");
- }
- }
-
- /**
- * Write the logStatement and its contents out through jsonWriter.
- *
- * Note that this method is not thread safe for the same jsonWriter. Callers must ensure
- * thread safety.
- */
- private boolean outputLogStatementToLocked(final JsonWriter jsonWriter,
- final LogStatement logStatement, final Object[] values, final Long time) {
- if (DEBUG) {
- if (logStatement.getKeys().length != values.length) {
- Log.d(TAG, "Key and Value list sizes do not match. " + logStatement.getType());
- }
- }
- try {
- jsonWriter.beginObject();
- jsonWriter.name(CURRENT_TIME_KEY).value(System.currentTimeMillis());
- jsonWriter.name(UPTIME_KEY).value(time);
- jsonWriter.name(EVENT_TYPE_KEY).value(logStatement.getType());
- final String[] keys = logStatement.getKeys();
- final int length = values.length;
- for (int i = 0; i < length; i++) {
- jsonWriter.name(keys[i]);
- final Object value = values[i];
- if (value instanceof CharSequence) {
- jsonWriter.value(value.toString());
- } else if (value instanceof Number) {
- jsonWriter.value((Number) value);
- } else if (value instanceof Boolean) {
- jsonWriter.value((Boolean) value);
- } else if (value instanceof CompletionInfo[]) {
- JsonUtils.writeJson((CompletionInfo[]) value, jsonWriter);
- } else if (value instanceof SharedPreferences) {
- JsonUtils.writeJson((SharedPreferences) value, jsonWriter);
- } else if (value instanceof Key[]) {
- JsonUtils.writeJson((Key[]) value, jsonWriter);
- } else if (value instanceof SuggestedWords) {
- JsonUtils.writeJson((SuggestedWords) value, jsonWriter);
- } else if (value instanceof MotionEvent) {
- JsonUtils.writeJson((MotionEvent) value, jsonWriter);
- } else if (value == null) {
- jsonWriter.nullValue();
- } else {
- Log.w(TAG, "Unrecognized type to be logged: "
- + (value == null ? "<null>" : value.getClass().getName()));
- jsonWriter.nullValue();
- }
- }
- jsonWriter.endObject();
- } catch (IOException e) {
- e.printStackTrace();
- Log.w(TAG, "Error in JsonWriter; skipping LogStatement");
- return false;
- }
- return true;
+ LOGSTATEMENT_LOG_UNIT_END.outputToLocked(jsonWriter, SystemClock.uptimeMillis());
}
/**
diff --git a/java/src/com/android/inputmethod/research/MotionEventReader.java b/java/src/com/android/inputmethod/research/MotionEventReader.java
index 26a1d7f..e59adfa 100644
--- a/java/src/com/android/inputmethod/research/MotionEventReader.java
+++ b/java/src/com/android/inputmethod/research/MotionEventReader.java
@@ -19,6 +19,8 @@
import android.util.JsonReader;
import android.util.Log;
import android.view.MotionEvent;
+import android.view.MotionEvent.PointerCoords;
+import android.view.MotionEvent.PointerProperties;
import com.android.inputmethod.latin.define.ProductionFlag;
@@ -33,6 +35,14 @@
public class MotionEventReader {
private static final String TAG = MotionEventReader.class.getSimpleName();
private static final boolean DEBUG = false && ProductionFlag.IS_EXPERIMENTAL_DEBUG;
+ // Assumes that MotionEvent.ACTION_MASK does not have all bits set.`
+ private static final int UNINITIALIZED_ACTION = ~MotionEvent.ACTION_MASK;
+ // No legitimate int is negative
+ private static final int UNINITIALIZED_INT = -1;
+ // No legitimate long is negative
+ private static final long UNINITIALIZED_LONG = -1L;
+ // No legitimate float is negative
+ private static final float UNINITIALIZED_FLOAT = -1.0f;
public ReplayData readMotionEventData(final File file) {
final ReplayData replayData = new ReplayData();
@@ -55,19 +65,82 @@
static class ReplayData {
final ArrayList<Integer> mActions = new ArrayList<Integer>();
- final ArrayList<Integer> mXCoords = new ArrayList<Integer>();
- final ArrayList<Integer> mYCoords = new ArrayList<Integer>();
+ final ArrayList<PointerProperties[]> mPointerPropertiesArrays
+ = new ArrayList<PointerProperties[]>();
+ final ArrayList<PointerCoords[]> mPointerCoordsArrays = new ArrayList<PointerCoords[]>();
final ArrayList<Long> mTimes = new ArrayList<Long>();
}
- private void readLogStatement(final JsonReader jsonReader, final ReplayData replayData)
- throws IOException {
+ /**
+ * Read motion data from a logStatement and store it in {@code replayData}.
+ *
+ * Two kinds of logStatements can be read. In the first variant, the MotionEvent data is
+ * represented as attributes at the top level like so:
+ *
+ * <pre>
+ * {
+ * "_ct": 1359590400000,
+ * "_ut": 4381933,
+ * "_ty": "MotionEvent",
+ * "action": "UP",
+ * "isLoggingRelated": false,
+ * "x": 100,
+ * "y": 200
+ * }
+ * </pre>
+ *
+ * In the second variant, there is a separate attribute for the MotionEvent that includes
+ * historical data if present:
+ *
+ * <pre>
+ * {
+ * "_ct": 135959040000,
+ * "_ut": 4382702,
+ * "_ty": "MotionEvent",
+ * "action": "MOVE",
+ * "isLoggingRelated": false,
+ * "motionEvent": {
+ * "pointerIds": [
+ * 0
+ * ],
+ * "xyt": [
+ * {
+ * "t": 4382551,
+ * "d": [
+ * {
+ * "x": 141.25,
+ * "y": 151.8485107421875,
+ * "toma": 101.82337188720703,
+ * "tomi": 101.82337188720703,
+ * "o": 0.0
+ * }
+ * ]
+ * },
+ * {
+ * "t": 4382559,
+ * "d": [
+ * {
+ * "x": 140.7266082763672,
+ * "y": 151.8485107421875,
+ * "toma": 101.82337188720703,
+ * "tomi": 101.82337188720703,
+ * "o": 0.0
+ * }
+ * ]
+ * }
+ * ]
+ * }
+ * },
+ * </pre>
+ */
+ /* package for test */ void readLogStatement(final JsonReader jsonReader,
+ final ReplayData replayData) throws IOException {
String logStatementType = null;
- Integer actionType = null;
- Integer x = null;
- Integer y = null;
- Long time = null;
- boolean loggingRelated = false;
+ int actionType = UNINITIALIZED_ACTION;
+ int x = UNINITIALIZED_INT;
+ int y = UNINITIALIZED_INT;
+ long time = UNINITIALIZED_LONG;
+ boolean isLoggingRelated = false;
jsonReader.beginObject();
while (jsonReader.hasNext()) {
@@ -90,7 +163,18 @@
actionType = MotionEvent.ACTION_MOVE;
}
} else if (key.equals("loggingRelated")) {
- loggingRelated = jsonReader.nextBoolean();
+ isLoggingRelated = jsonReader.nextBoolean();
+ } else if (logStatementType != null && logStatementType.equals("MotionEvent")
+ && key.equals("motionEvent")) {
+ if (actionType == UNINITIALIZED_ACTION) {
+ Log.e(TAG, "no actionType assigned in MotionEvent json");
+ }
+ // Second variant of LogStatement.
+ if (isLoggingRelated) {
+ jsonReader.skipValue();
+ } else {
+ readEmbeddedMotionEvent(jsonReader, replayData, actionType);
+ }
} else {
if (DEBUG) {
Log.w(TAG, "Unknown JSON key in LogStatement: " + key);
@@ -100,14 +184,149 @@
}
jsonReader.endObject();
- if (logStatementType != null && time != null && x != null && y != null && actionType != null
- && logStatementType.equals("MotionEvent")
- && !loggingRelated) {
- replayData.mActions.add(actionType);
- replayData.mXCoords.add(x);
- replayData.mYCoords.add(y);
- replayData.mTimes.add(time);
+ if (logStatementType != null && time != UNINITIALIZED_LONG && x != UNINITIALIZED_INT
+ && y != UNINITIALIZED_INT && actionType != UNINITIALIZED_ACTION
+ && logStatementType.equals("MotionEvent") && !isLoggingRelated) {
+ // First variant of LogStatement.
+ final PointerProperties pointerProperties = new PointerProperties();
+ pointerProperties.id = 0;
+ pointerProperties.toolType = MotionEvent.TOOL_TYPE_UNKNOWN;
+ final PointerProperties[] pointerPropertiesArray = {
+ pointerProperties
+ };
+ final PointerCoords pointerCoords = new PointerCoords();
+ pointerCoords.x = x;
+ pointerCoords.y = y;
+ pointerCoords.pressure = 1.0f;
+ pointerCoords.size = 1.0f;
+ final PointerCoords[] pointerCoordsArray = {
+ pointerCoords
+ };
+ addMotionEventData(replayData, actionType, time, pointerPropertiesArray,
+ pointerCoordsArray);
}
}
+ private void readEmbeddedMotionEvent(final JsonReader jsonReader, final ReplayData replayData,
+ final int actionType) throws IOException {
+ jsonReader.beginObject();
+ PointerProperties[] pointerPropertiesArray = null;
+ while (jsonReader.hasNext()) { // pointerIds/xyt
+ final String name = jsonReader.nextName();
+ if (name.equals("pointerIds")) {
+ pointerPropertiesArray = readPointerProperties(jsonReader);
+ } else if (name.equals("xyt")) {
+ readPointerData(jsonReader, replayData, actionType, pointerPropertiesArray);
+ }
+ }
+ jsonReader.endObject();
+ }
+
+ private PointerProperties[] readPointerProperties(final JsonReader jsonReader)
+ throws IOException {
+ final ArrayList<PointerProperties> pointerPropertiesArrayList =
+ new ArrayList<PointerProperties>();
+ jsonReader.beginArray();
+ while (jsonReader.hasNext()) {
+ final PointerProperties pointerProperties = new PointerProperties();
+ pointerProperties.id = jsonReader.nextInt();
+ pointerProperties.toolType = MotionEvent.TOOL_TYPE_UNKNOWN;
+ pointerPropertiesArrayList.add(pointerProperties);
+ }
+ jsonReader.endArray();
+ return pointerPropertiesArrayList.toArray(
+ new PointerProperties[pointerPropertiesArrayList.size()]);
+ }
+
+ private void readPointerData(final JsonReader jsonReader, final ReplayData replayData,
+ final int actionType, final PointerProperties[] pointerPropertiesArray)
+ throws IOException {
+ if (pointerPropertiesArray == null) {
+ Log.e(TAG, "PointerIDs must be given before xyt data in json for MotionEvent");
+ jsonReader.skipValue();
+ return;
+ }
+ long time = UNINITIALIZED_LONG;
+ jsonReader.beginArray();
+ while (jsonReader.hasNext()) { // Array of historical data
+ jsonReader.beginObject();
+ final ArrayList<PointerCoords> pointerCoordsArrayList = new ArrayList<PointerCoords>();
+ while (jsonReader.hasNext()) { // Time/data object
+ final String name = jsonReader.nextName();
+ if (name.equals("t")) {
+ time = jsonReader.nextLong();
+ } else if (name.equals("d")) {
+ jsonReader.beginArray();
+ while (jsonReader.hasNext()) { // array of data per pointer
+ final PointerCoords pointerCoords = readPointerCoords(jsonReader);
+ if (pointerCoords != null) {
+ pointerCoordsArrayList.add(pointerCoords);
+ }
+ }
+ jsonReader.endArray();
+ } else {
+ jsonReader.skipValue();
+ }
+ }
+ jsonReader.endObject();
+ // Data was recorded as historical events, but must be split apart into
+ // separate MotionEvents for replaying
+ if (time != UNINITIALIZED_LONG) {
+ addMotionEventData(replayData, actionType, time, pointerPropertiesArray,
+ pointerCoordsArrayList.toArray(
+ new PointerCoords[pointerCoordsArrayList.size()]));
+ } else {
+ Log.e(TAG, "Time not assigned in json for MotionEvent");
+ }
+ }
+ jsonReader.endArray();
+ }
+
+ private PointerCoords readPointerCoords(final JsonReader jsonReader) throws IOException {
+ jsonReader.beginObject();
+ float x = UNINITIALIZED_FLOAT;
+ float y = UNINITIALIZED_FLOAT;
+ while (jsonReader.hasNext()) { // x,y
+ final String name = jsonReader.nextName();
+ if (name.equals("x")) {
+ x = (float) jsonReader.nextDouble();
+ } else if (name.equals("y")) {
+ y = (float) jsonReader.nextDouble();
+ } else {
+ jsonReader.skipValue();
+ }
+ }
+ jsonReader.endObject();
+
+ if (Float.compare(x, UNINITIALIZED_FLOAT) == 0
+ || Float.compare(y, UNINITIALIZED_FLOAT) == 0) {
+ Log.w(TAG, "missing x or y value in MotionEvent json");
+ return null;
+ }
+ final PointerCoords pointerCoords = new PointerCoords();
+ pointerCoords.x = x;
+ pointerCoords.y = y;
+ pointerCoords.pressure = 1.0f;
+ pointerCoords.size = 1.0f;
+ return pointerCoords;
+ }
+
+ /**
+ * Tests that {@code x} is uninitialized.
+ *
+ * Assumes that {@code x} will never be given a valid value less than 0, and that
+ * UNINITIALIZED_FLOAT is less than 0.0f.
+ */
+ private boolean isUninitializedFloat(final float x) {
+ return x < 0.0f;
+ }
+
+ private void addMotionEventData(final ReplayData replayData, final int actionType,
+ final long time, final PointerProperties[] pointerProperties,
+ final PointerCoords[] pointerCoords) {
+ replayData.mActions.add(actionType);
+ replayData.mTimes.add(time);
+ replayData.mPointerPropertiesArrays.add(pointerProperties);
+ replayData.mPointerCoordsArrays.add(pointerCoords);
+ }
}
diff --git a/java/src/com/android/inputmethod/research/Replayer.java b/java/src/com/android/inputmethod/research/Replayer.java
index 611abb2..a9b7a9d 100644
--- a/java/src/com/android/inputmethod/research/Replayer.java
+++ b/java/src/com/android/inputmethod/research/Replayer.java
@@ -22,6 +22,8 @@
import android.os.SystemClock;
import android.util.Log;
import android.view.MotionEvent;
+import android.view.MotionEvent.PointerCoords;
+import android.view.MotionEvent.PointerProperties;
import com.android.inputmethod.keyboard.KeyboardSwitcher;
import com.android.inputmethod.keyboard.MainKeyboardView;
@@ -62,7 +64,6 @@
if (mIsReplaying) {
return;
}
-
mIsReplaying = true;
final int numActions = replayData.mActions.size();
if (DEBUG) {
@@ -95,25 +96,36 @@
case MSG_MOTION_EVENT:
final int index = msg.arg1;
final int action = replayData.mActions.get(index);
- final int x = replayData.mXCoords.get(index);
- final int y = replayData.mYCoords.get(index);
+ final PointerProperties[] pointerPropertiesArray =
+ replayData.mPointerPropertiesArrays.get(index);
+ final PointerCoords[] pointerCoordsArray =
+ replayData.mPointerCoordsArrays.get(index);
final long origTime = replayData.mTimes.get(index);
if (action == MotionEvent.ACTION_DOWN) {
mOrigDownTime = origTime;
}
final MotionEvent me = MotionEvent.obtain(mOrigDownTime + timeAdjustment,
- origTime + timeAdjustment, action, x, y, 0);
+ origTime + timeAdjustment, action,
+ pointerPropertiesArray.length, pointerPropertiesArray,
+ pointerCoordsArray, 0, 0, 1.0f, 1.0f, 0, 0, 0, 0);
mainKeyboardView.processMotionEvent(me);
me.recycle();
break;
case MSG_DONE:
mIsReplaying = false;
+ ResearchLogger.getInstance().requestIndicatorRedraw();
break;
}
}
};
+ handler.post(new Runnable() {
+ @Override
+ public void run() {
+ ResearchLogger.getInstance().requestIndicatorRedraw();
+ }
+ });
for (int i = 0; i < numActions; i++) {
final Message msg = Message.obtain(handler, MSG_MOTION_EVENT, i, 0);
final long msgTime = replayData.mTimes.get(i) + timeAdjustment;
@@ -130,4 +142,8 @@
handler.postAtTime(callback, presentDoneTime + 1);
}
}
+
+ public boolean isReplaying() {
+ return mIsReplaying;
+ }
}
diff --git a/java/src/com/android/inputmethod/research/ResearchLogger.java b/java/src/com/android/inputmethod/research/ResearchLogger.java
index da41001..364ab2d 100644
--- a/java/src/com/android/inputmethod/research/ResearchLogger.java
+++ b/java/src/com/android/inputmethod/research/ResearchLogger.java
@@ -115,6 +115,12 @@
// private info.
private static final boolean LOG_FULL_TEXTVIEW_CONTENTS = false
&& ProductionFlag.IS_EXPERIMENTAL_DEBUG;
+ // Whether the feedback dialog preserves the editable text across invocations. Should be false
+ // for normal research builds so users do not have to delete the same feedback string they
+ // entered earlier. Should be true for builds internal to a development team so when the text
+ // field holds a channel name, the developer does not have to re-enter it when using the
+ // feedback mechanism to generate multiple tests.
+ private static final boolean FEEDBACK_DIALOG_SHOULD_PRESERVE_TEXT_FIELD = false;
public static final boolean DEFAULT_USABILITY_STUDY_MODE = false;
/* package */ static boolean sIsLogging = false;
private static final int OUTPUT_FORMAT_VERSION = 5;
@@ -140,6 +146,7 @@
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 String PREF_RESEARCH_SAVED_CHANNEL = "pref_research_saved_channel";
private static final ResearchLogger sInstance = new ResearchLogger();
private static String sAccountType = null;
@@ -591,12 +598,20 @@
mFeedbackLogBuffer = null;
mFeedbackLog = null;
- Intent intent = new Intent();
+ final Intent intent = new Intent();
intent.setClass(mLatinIME, FeedbackActivity.class);
- if (mFeedbackDialogBundle != null) {
- Log.d(TAG, "putting extra in feedbackdialogbundle");
- intent.putExtras(mFeedbackDialogBundle);
+ if (mFeedbackDialogBundle == null) {
+ // Restore feedback field with channel name
+ final Bundle bundle = new Bundle();
+ bundle.putBoolean(FeedbackFragment.KEY_INCLUDE_ACCOUNT_NAME, true);
+ bundle.putBoolean(FeedbackFragment.KEY_HAS_USER_RECORDING, false);
+ if (FEEDBACK_DIALOG_SHOULD_PRESERVE_TEXT_FIELD) {
+ final String savedChannelName = mPrefs.getString(PREF_RESEARCH_SAVED_CHANNEL, "");
+ bundle.putString(FeedbackFragment.KEY_FEEDBACK_STRING, savedChannelName);
+ }
+ mFeedbackDialogBundle = bundle;
}
+ intent.putExtras(mFeedbackDialogBundle);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
latinIME.startActivity(intent);
}
@@ -787,6 +802,18 @@
}
}, 1000);
}
+
+ if (FEEDBACK_DIALOG_SHOULD_PRESERVE_TEXT_FIELD) {
+ // Use feedback string as a channel name to label feedback strings. Here we record the
+ // string for prepopulating the field next time.
+ final String channelName = feedbackContents;
+ if (mPrefs == null) {
+ return;
+ }
+ final Editor e = mPrefs.edit();
+ e.putString(PREF_RESEARCH_SAVED_CHANNEL, channelName);
+ e.apply();
+ }
}
public void uploadNow() {
@@ -819,7 +846,8 @@
}
private boolean isAllowedToLog() {
- return !mIsPasswordView && !mIsLoggingSuspended && sIsLogging && !mInFeedbackDialog;
+ return !mIsPasswordView && !mIsLoggingSuspended && sIsLogging && !mInFeedbackDialog
+ && !isReplaying();
}
public void requestIndicatorRedraw() {
@@ -832,15 +860,30 @@
mMainKeyboardView.invalidateAllKeys();
}
+ private boolean isReplaying() {
+ return mReplayer.isReplaying();
+ }
+
+ private int getIndicatorColor() {
+ if (isMakingUserRecording()) {
+ return Color.YELLOW;
+ }
+ if (isReplaying()) {
+ return Color.GREEN;
+ }
+ return Color.RED;
+ }
+
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 the indicator only decorates the main
// keyboard, not every keyboard.
- if (IS_SHOWING_INDICATOR && isAllowedToLog() && view instanceof MainKeyboardView) {
+ if (IS_SHOWING_INDICATOR && (isAllowedToLog() || isReplaying())
+ && view instanceof MainKeyboardView) {
final int savedColor = paint.getColor();
- paint.setColor(isMakingUserRecording() ? Color.YELLOW : Color.RED);
+ paint.setColor(getIndicatorColor());
final Style savedStyle = paint.getStyle();
paint.setStyle(Style.STROKE);
final float savedStrokeWidth = paint.getStrokeWidth();
@@ -960,15 +1003,23 @@
}
}
+ /**
+ * Publish all the logUnits in the logBuffer, without doing any privacy filtering.
+ */
/* package for test */ void publishLogBuffer(final LogBuffer logBuffer,
- final ResearchLog researchLog, final boolean isIncludingPrivateData) {
- publishLogUnits(logBuffer.getLogUnits(), researchLog, isIncludingPrivateData);
+ final ResearchLog researchLog, final boolean canIncludePrivateData) {
+ publishLogUnits(logBuffer.getLogUnits(), researchLog, canIncludePrivateData);
}
private static final LogStatement LOGSTATEMENT_LOG_SEGMENT_OPENING =
new LogStatement("logSegmentStart", false, false, "isIncludingPrivateData");
private static final LogStatement LOGSTATEMENT_LOG_SEGMENT_CLOSING =
new LogStatement("logSegmentEnd", false, false);
+ /**
+ * Publish all LogUnits in a list.
+ *
+ * Any privacy checks should be performed before calling this method.
+ */
/* package for test */ void publishLogUnits(final List<LogUnit> logUnits,
final ResearchLog researchLog, final boolean canIncludePrivateData) {
final LogUnit openingLogUnit = new LogUnit();
@@ -1349,7 +1400,7 @@
final int index, final String suggestion, final boolean isBatchMode) {
final ResearchLogger researchLogger = getInstance();
if (!replacedWord.equals(suggestion.toString())) {
- // The user choose something other than what was already there.
+ // The user chose something other than what was already there.
researchLogger.setCurrentLogUnitContainsCorrection();
researchLogger.setCurrentLogUnitCorrectionType(LogUnit.CORRECTIONTYPE_TYPO);
}
diff --git a/tests/Android.mk b/tests/Android.mk
index 6634070..5baebbd 100644
--- a/tests/Android.mk
+++ b/tests/Android.mk
@@ -19,8 +19,6 @@
LOCAL_MODULE_TAGS := tests
LOCAL_CERTIFICATE := shared
-LOCAL_JAVA_LIBRARIES := android.test.runner
-
# Do not compress dictionary files to mmap dict data runtime
LOCAL_AAPT_FLAGS += -0 .dict
# Do not compress test data file
@@ -33,4 +31,6 @@
LOCAL_INSTRUMENTATION_FOR := LatinIME
+LOCAL_SDK_VERSION := current
+
include $(BUILD_PACKAGE)
diff --git a/tests/src/com/android/inputmethod/keyboard/MoreKeysKeyboardBuilderFixedOrderTests.java b/tests/src/com/android/inputmethod/keyboard/MoreKeysKeyboardBuilderFixedOrderTests.java
index 2a244a7..49ef3a2 100644
--- a/tests/src/com/android/inputmethod/keyboard/MoreKeysKeyboardBuilderFixedOrderTests.java
+++ b/tests/src/com/android/inputmethod/keyboard/MoreKeysKeyboardBuilderFixedOrderTests.java
@@ -17,9 +17,11 @@
package com.android.inputmethod.keyboard;
import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
import com.android.inputmethod.keyboard.MoreKeysKeyboard.MoreKeysKeyboardParams;
+@SmallTest
public class MoreKeysKeyboardBuilderFixedOrderTests extends AndroidTestCase {
private static final int WIDTH = 10;
private static final int HEIGHT = 10;
diff --git a/tests/src/com/android/inputmethod/keyboard/MoreKeysKeyboardBuilderTests.java b/tests/src/com/android/inputmethod/keyboard/MoreKeysKeyboardBuilderTests.java
index e6c76db..93883dc 100644
--- a/tests/src/com/android/inputmethod/keyboard/MoreKeysKeyboardBuilderTests.java
+++ b/tests/src/com/android/inputmethod/keyboard/MoreKeysKeyboardBuilderTests.java
@@ -17,9 +17,11 @@
package com.android.inputmethod.keyboard;
import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
import com.android.inputmethod.keyboard.MoreKeysKeyboard.MoreKeysKeyboardParams;
+@SmallTest
public class MoreKeysKeyboardBuilderTests extends AndroidTestCase {
private static final int WIDTH = 10;
private static final int HEIGHT = 10;
diff --git a/tests/src/com/android/inputmethod/keyboard/SpacebarTextTests.java b/tests/src/com/android/inputmethod/keyboard/SpacebarTextTests.java
index 05b1376..d0426eb 100644
--- a/tests/src/com/android/inputmethod/keyboard/SpacebarTextTests.java
+++ b/tests/src/com/android/inputmethod/keyboard/SpacebarTextTests.java
@@ -19,6 +19,7 @@
import android.content.Context;
import android.content.res.Resources;
import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
import android.view.inputmethod.InputMethodSubtype;
import com.android.inputmethod.latin.AdditionalSubtype;
@@ -31,6 +32,7 @@
import java.util.ArrayList;
import java.util.Locale;
+@SmallTest
public class SpacebarTextTests extends AndroidTestCase {
// Locale to subtypes list.
private final ArrayList<InputMethodSubtype> mSubtypesList = CollectionUtils.newArrayList();
diff --git a/tests/src/com/android/inputmethod/keyboard/internal/KeySpecParserCsvTests.java b/tests/src/com/android/inputmethod/keyboard/internal/KeySpecParserCsvTests.java
index 1346c00..cee62ca 100644
--- a/tests/src/com/android/inputmethod/keyboard/internal/KeySpecParserCsvTests.java
+++ b/tests/src/com/android/inputmethod/keyboard/internal/KeySpecParserCsvTests.java
@@ -18,6 +18,7 @@
import android.app.Instrumentation;
import android.test.InstrumentationTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
import com.android.inputmethod.latin.CollectionUtils;
@@ -26,6 +27,7 @@
import java.util.Arrays;
import java.util.Locale;
+@SmallTest
public class KeySpecParserCsvTests extends InstrumentationTestCase {
private final KeyboardTextsSet mTextsSet = new KeyboardTextsSet();
diff --git a/tests/src/com/android/inputmethod/keyboard/internal/KeySpecParserTests.java b/tests/src/com/android/inputmethod/keyboard/internal/KeySpecParserTests.java
index 5bba961..a5b61b3 100644
--- a/tests/src/com/android/inputmethod/keyboard/internal/KeySpecParserTests.java
+++ b/tests/src/com/android/inputmethod/keyboard/internal/KeySpecParserTests.java
@@ -21,12 +21,14 @@
import static com.android.inputmethod.latin.Constants.CODE_UNSPECIFIED;
import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
import com.android.inputmethod.latin.Constants;
import java.util.Arrays;
import java.util.Locale;
+@SmallTest
public class KeySpecParserTests extends AndroidTestCase {
private final KeyboardCodesSet mCodesSet = new KeyboardCodesSet();
private final KeyboardTextsSet mTextsSet = new KeyboardTextsSet();
diff --git a/tests/src/com/android/inputmethod/keyboard/internal/KeyboardStateMultiTouchTests.java b/tests/src/com/android/inputmethod/keyboard/internal/KeyboardStateMultiTouchTests.java
index 053bcb5..5fbe6d4 100644
--- a/tests/src/com/android/inputmethod/keyboard/internal/KeyboardStateMultiTouchTests.java
+++ b/tests/src/com/android/inputmethod/keyboard/internal/KeyboardStateMultiTouchTests.java
@@ -16,6 +16,9 @@
package com.android.inputmethod.keyboard.internal;
+import android.test.suitebuilder.annotation.SmallTest;
+
+@SmallTest
public class KeyboardStateMultiTouchTests extends KeyboardStateTestsBase {
// Chording input in alphabet.
public void testChordingAlphabet() {
diff --git a/tests/src/com/android/inputmethod/keyboard/internal/KeyboardStateSingleTouchTests.java b/tests/src/com/android/inputmethod/keyboard/internal/KeyboardStateSingleTouchTests.java
index 74ff879..637d475 100644
--- a/tests/src/com/android/inputmethod/keyboard/internal/KeyboardStateSingleTouchTests.java
+++ b/tests/src/com/android/inputmethod/keyboard/internal/KeyboardStateSingleTouchTests.java
@@ -16,6 +16,9 @@
package com.android.inputmethod.keyboard.internal;
+import android.test.suitebuilder.annotation.SmallTest;
+
+@SmallTest
public class KeyboardStateSingleTouchTests extends KeyboardStateTestsBase {
// Shift key in alphabet.
public void testShiftAlphabet() {
diff --git a/tests/src/com/android/inputmethod/keyboard/internal/PointerTrackerQueueTests.java b/tests/src/com/android/inputmethod/keyboard/internal/PointerTrackerQueueTests.java
index 2c3e3a5..e7068af 100644
--- a/tests/src/com/android/inputmethod/keyboard/internal/PointerTrackerQueueTests.java
+++ b/tests/src/com/android/inputmethod/keyboard/internal/PointerTrackerQueueTests.java
@@ -17,7 +17,9 @@
package com.android.inputmethod.keyboard.internal;
import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+@SmallTest
public class PointerTrackerQueueTests extends AndroidTestCase {
public static class Element implements PointerTrackerQueue.Element {
public static int sPhantomUpCount;
diff --git a/tests/src/com/android/inputmethod/latin/BlueUnderlineTests.java b/tests/src/com/android/inputmethod/latin/BlueUnderlineTests.java
index 6b4d52d..594b5d6 100644
--- a/tests/src/com/android/inputmethod/latin/BlueUnderlineTests.java
+++ b/tests/src/com/android/inputmethod/latin/BlueUnderlineTests.java
@@ -16,9 +16,11 @@
package com.android.inputmethod.latin;
+import android.test.suitebuilder.annotation.LargeTest;
import android.text.style.SuggestionSpan;
import android.text.style.UnderlineSpan;
+@LargeTest
public class BlueUnderlineTests extends InputTestsBase {
public void testBlueUnderline() {
diff --git a/tests/src/com/android/inputmethod/latin/EditDistanceTests.java b/tests/src/com/android/inputmethod/latin/EditDistanceTests.java
index c053a49..0b7fcbb 100644
--- a/tests/src/com/android/inputmethod/latin/EditDistanceTests.java
+++ b/tests/src/com/android/inputmethod/latin/EditDistanceTests.java
@@ -17,7 +17,9 @@
package com.android.inputmethod.latin;
import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+@SmallTest
public class EditDistanceTests extends AndroidTestCase {
@Override
protected void setUp() throws Exception {
diff --git a/tests/src/com/android/inputmethod/latin/ForgettingCurveTests.java b/tests/src/com/android/inputmethod/latin/ForgettingCurveTests.java
index a2e71c1..3259312 100644
--- a/tests/src/com/android/inputmethod/latin/ForgettingCurveTests.java
+++ b/tests/src/com/android/inputmethod/latin/ForgettingCurveTests.java
@@ -17,7 +17,9 @@
package com.android.inputmethod.latin;
import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+@SmallTest
public class ForgettingCurveTests extends AndroidTestCase {
public void testFcToFreq() {
for (int i = 0; i < Byte.MAX_VALUE; ++i) {
diff --git a/tests/src/com/android/inputmethod/latin/FusionDictionaryTests.java b/tests/src/com/android/inputmethod/latin/FusionDictionaryTests.java
index 123959b..fd58476 100644
--- a/tests/src/com/android/inputmethod/latin/FusionDictionaryTests.java
+++ b/tests/src/com/android/inputmethod/latin/FusionDictionaryTests.java
@@ -17,6 +17,7 @@
package com.android.inputmethod.latin;
import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
import com.android.inputmethod.latin.makedict.FusionDictionary;
import com.android.inputmethod.latin.makedict.FusionDictionary.Node;
@@ -26,6 +27,7 @@
/**
* Unit test for FusionDictionary
*/
+@SmallTest
public class FusionDictionaryTests extends AndroidTestCase {
public void testFindWordInTree() {
FusionDictionary dict = new FusionDictionary(new Node(),
diff --git a/tests/src/com/android/inputmethod/latin/InputLogicTests.java b/tests/src/com/android/inputmethod/latin/InputLogicTests.java
index 6412a9d..d7b2407 100644
--- a/tests/src/com/android/inputmethod/latin/InputLogicTests.java
+++ b/tests/src/com/android/inputmethod/latin/InputLogicTests.java
@@ -16,6 +16,9 @@
package com.android.inputmethod.latin;
+import android.test.suitebuilder.annotation.LargeTest;
+
+@LargeTest
public class InputLogicTests extends InputTestsBase {
public void testTypeWord() {
diff --git a/tests/src/com/android/inputmethod/latin/InputLogicTestsNonEnglish.java b/tests/src/com/android/inputmethod/latin/InputLogicTestsNonEnglish.java
index 42823f5..e012f79 100644
--- a/tests/src/com/android/inputmethod/latin/InputLogicTestsNonEnglish.java
+++ b/tests/src/com/android/inputmethod/latin/InputLogicTestsNonEnglish.java
@@ -16,8 +16,11 @@
package com.android.inputmethod.latin;
+import android.test.suitebuilder.annotation.LargeTest;
+
import com.android.inputmethod.latin.suggestions.SuggestionStripView;
+@LargeTest
public class InputLogicTestsNonEnglish extends InputTestsBase {
final String NEXT_WORD_PREDICTION_OPTION = "next_word_prediction";
diff --git a/tests/src/com/android/inputmethod/latin/InputPointersTests.java b/tests/src/com/android/inputmethod/latin/InputPointersTests.java
index cc55076..44526a3 100644
--- a/tests/src/com/android/inputmethod/latin/InputPointersTests.java
+++ b/tests/src/com/android/inputmethod/latin/InputPointersTests.java
@@ -17,9 +17,11 @@
package com.android.inputmethod.latin;
import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
import java.util.Arrays;
+@SmallTest
public class InputPointersTests extends AndroidTestCase {
private static final int DEFAULT_CAPACITY = 48;
diff --git a/tests/src/com/android/inputmethod/latin/InputTestsBase.java b/tests/src/com/android/inputmethod/latin/InputTestsBase.java
index 10d415b..c440587 100644
--- a/tests/src/com/android/inputmethod/latin/InputTestsBase.java
+++ b/tests/src/com/android/inputmethod/latin/InputTestsBase.java
@@ -31,16 +31,12 @@
import android.view.ViewGroup;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputConnection;
-import android.view.inputmethod.InputMethodInfo;
-import android.view.inputmethod.InputMethodManager;
-import android.view.inputmethod.InputMethodSubtype;
import android.widget.FrameLayout;
import android.widget.TextView;
import com.android.inputmethod.keyboard.Key;
import com.android.inputmethod.keyboard.Keyboard;
-import java.util.HashMap;
import java.util.Locale;
public class InputTestsBase extends ServiceTestCase<LatinIME> {
diff --git a/tests/src/com/android/inputmethod/latin/PunctuationTests.java b/tests/src/com/android/inputmethod/latin/PunctuationTests.java
index 0eb3ba4..38203e8 100644
--- a/tests/src/com/android/inputmethod/latin/PunctuationTests.java
+++ b/tests/src/com/android/inputmethod/latin/PunctuationTests.java
@@ -16,8 +16,11 @@
package com.android.inputmethod.latin;
+import android.test.suitebuilder.annotation.LargeTest;
+
import com.android.inputmethod.latin.R;
+@LargeTest
public class PunctuationTests extends InputTestsBase {
final String NEXT_WORD_PREDICTION_OPTION = "next_word_prediction";
diff --git a/tests/src/com/android/inputmethod/latin/ResizableIntArrayTests.java b/tests/src/com/android/inputmethod/latin/ResizableIntArrayTests.java
index 995fc14..7c415df 100644
--- a/tests/src/com/android/inputmethod/latin/ResizableIntArrayTests.java
+++ b/tests/src/com/android/inputmethod/latin/ResizableIntArrayTests.java
@@ -17,7 +17,9 @@
package com.android.inputmethod.latin;
import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+@SmallTest
public class ResizableIntArrayTests extends AndroidTestCase {
private static final int DEFAULT_CAPACITY = 48;
diff --git a/tests/src/com/android/inputmethod/latin/RichInputConnectionTests.java b/tests/src/com/android/inputmethod/latin/RichInputConnectionTests.java
index ad99379..9b8fc6d 100644
--- a/tests/src/com/android/inputmethod/latin/RichInputConnectionTests.java
+++ b/tests/src/com/android/inputmethod/latin/RichInputConnectionTests.java
@@ -18,6 +18,7 @@
import android.inputmethodservice.InputMethodService;
import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
import android.view.inputmethod.ExtractedText;
import android.view.inputmethod.ExtractedTextRequest;
import android.view.inputmethod.InputConnection;
@@ -25,6 +26,7 @@
import com.android.inputmethod.latin.RichInputConnection.Range;
+@SmallTest
public class RichInputConnectionTests extends AndroidTestCase {
// The following is meant to be a reasonable default for
diff --git a/tests/src/com/android/inputmethod/latin/StringUtilsTests.java b/tests/src/com/android/inputmethod/latin/StringUtilsTests.java
index 3142bd6..f3fbb3e 100644
--- a/tests/src/com/android/inputmethod/latin/StringUtilsTests.java
+++ b/tests/src/com/android/inputmethod/latin/StringUtilsTests.java
@@ -17,10 +17,12 @@
package com.android.inputmethod.latin;
import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
import android.text.TextUtils;
import java.util.Locale;
+@SmallTest
public class StringUtilsTests extends AndroidTestCase {
public void testContainsInArray() {
assertFalse("empty array", StringUtils.containsInArray("key", new String[0]));
diff --git a/tests/src/com/android/inputmethod/latin/SubtypeLocaleTests.java b/tests/src/com/android/inputmethod/latin/SubtypeLocaleTests.java
index e37fef7..e406e84 100644
--- a/tests/src/com/android/inputmethod/latin/SubtypeLocaleTests.java
+++ b/tests/src/com/android/inputmethod/latin/SubtypeLocaleTests.java
@@ -19,6 +19,7 @@
import android.content.Context;
import android.content.res.Resources;
import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
import android.view.inputmethod.InputMethodSubtype;
import com.android.inputmethod.latin.LocaleUtils.RunInLocale;
@@ -26,6 +27,7 @@
import java.util.ArrayList;
import java.util.Locale;
+@SmallTest
public class SubtypeLocaleTests extends AndroidTestCase {
// Locale to subtypes list.
private final ArrayList<InputMethodSubtype> mSubtypesList = CollectionUtils.newArrayList();
diff --git a/tests/src/com/android/inputmethod/latin/UserHistoryDictIOUtilsTests.java b/tests/src/com/android/inputmethod/latin/UserHistoryDictIOUtilsTests.java
index 66c9e18..dd28fab 100644
--- a/tests/src/com/android/inputmethod/latin/UserHistoryDictIOUtilsTests.java
+++ b/tests/src/com/android/inputmethod/latin/UserHistoryDictIOUtilsTests.java
@@ -16,17 +16,17 @@
package com.android.inputmethod.latin;
+import android.content.Context;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.util.Log;
+
import com.android.inputmethod.latin.UserHistoryDictIOUtils.BigramDictionaryInterface;
import com.android.inputmethod.latin.UserHistoryDictIOUtils.OnAddWordListener;
-import com.android.inputmethod.latin.makedict.BinaryDictInputOutput;
import com.android.inputmethod.latin.makedict.FormatSpec;
import com.android.inputmethod.latin.makedict.FusionDictionary;
import com.android.inputmethod.latin.makedict.FusionDictionary.CharGroup;
-import android.content.Context;
-import android.test.AndroidTestCase;
-import android.util.Log;
-
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
@@ -39,6 +39,7 @@
/**
* Unit tests for UserHistoryDictIOUtils
*/
+@LargeTest
public class UserHistoryDictIOUtilsTests extends AndroidTestCase
implements BigramDictionaryInterface {
diff --git a/tests/src/com/android/inputmethod/latin/UserHistoryDictionaryTests.java b/tests/src/com/android/inputmethod/latin/UserHistoryDictionaryTests.java
index 7536f64..594ba0e 100644
--- a/tests/src/com/android/inputmethod/latin/UserHistoryDictionaryTests.java
+++ b/tests/src/com/android/inputmethod/latin/UserHistoryDictionaryTests.java
@@ -16,15 +16,13 @@
package com.android.inputmethod.latin;
-import com.android.inputmethod.latin.UserHistoryDictionary;
-
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
import android.util.Log;
import java.io.File;
-import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
@@ -33,6 +31,7 @@
/**
* Unit tests for UserHistoryDictionary
*/
+@LargeTest
public class UserHistoryDictionaryTests extends AndroidTestCase {
private static final String TAG = UserHistoryDictionaryTests.class.getSimpleName();
private SharedPreferences mPrefs;
diff --git a/tests/src/com/android/inputmethod/latin/makedict/BinaryDictIOTests.java b/tests/src/com/android/inputmethod/latin/makedict/BinaryDictIOTests.java
index d080ed6..f3694ea 100644
--- a/tests/src/com/android/inputmethod/latin/makedict/BinaryDictIOTests.java
+++ b/tests/src/com/android/inputmethod/latin/makedict/BinaryDictIOTests.java
@@ -16,6 +16,12 @@
package com.android.inputmethod.latin.makedict;
+import android.test.AndroidTestCase;
+import android.test.MoreAsserts;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.util.Log;
+import android.util.SparseArray;
+
import com.android.inputmethod.latin.CollectionUtils;
import com.android.inputmethod.latin.UserHistoryDictIOUtils;
import com.android.inputmethod.latin.makedict.BinaryDictInputOutput.FusionDictionaryBufferInterface;
@@ -24,11 +30,6 @@
import com.android.inputmethod.latin.makedict.FusionDictionary.Node;
import com.android.inputmethod.latin.makedict.FusionDictionary.WeightedString;
-import android.test.AndroidTestCase;
-import android.test.MoreAsserts;
-import android.util.Log;
-import android.util.SparseArray;
-
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
@@ -47,6 +48,7 @@
/**
* Unit tests for BinaryDictInputOutput
*/
+@LargeTest
public class BinaryDictIOTests extends AndroidTestCase {
private static final String TAG = BinaryDictIOTests.class.getSimpleName();
private static final int MAX_UNIGRAMS = 1000;
diff --git a/tests/src/com/android/inputmethod/latin/makedict/BinaryDictIOUtilsTests.java b/tests/src/com/android/inputmethod/latin/makedict/BinaryDictIOUtilsTests.java
index 3185168..25575ba 100644
--- a/tests/src/com/android/inputmethod/latin/makedict/BinaryDictIOUtilsTests.java
+++ b/tests/src/com/android/inputmethod/latin/makedict/BinaryDictIOUtilsTests.java
@@ -16,32 +16,30 @@
package com.android.inputmethod.latin.makedict;
+import android.test.AndroidTestCase;
+import android.test.MoreAsserts;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.util.Log;
+
import com.android.inputmethod.latin.CollectionUtils;
import com.android.inputmethod.latin.makedict.BinaryDictInputOutput.ByteBufferWrapper;
-import com.android.inputmethod.latin.makedict.BinaryDictInputOutput.CharEncoding;
import com.android.inputmethod.latin.makedict.BinaryDictInputOutput.FusionDictionaryBufferInterface;
import com.android.inputmethod.latin.makedict.FormatSpec.FileHeader;
import com.android.inputmethod.latin.makedict.FusionDictionary.Node;
import com.android.inputmethod.latin.makedict.FusionDictionary.WeightedString;
-import android.test.AndroidTestCase;
-import android.test.MoreAsserts;
-import android.util.Log;
-
import java.io.BufferedOutputStream;
-import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
-import java.io.FileWriter;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.channels.FileChannel;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.HashMap;
import java.util.Random;
+@LargeTest
public class BinaryDictIOUtilsTests extends AndroidTestCase {
private static final String TAG = BinaryDictIOUtilsTests.class.getSimpleName();
private static final FormatSpec.FormatOptions FORMAT_OPTIONS =
diff --git a/tests/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerServiceTest.java b/tests/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerServiceTest.java
index 21406d3..1ea6b2e 100644
--- a/tests/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerServiceTest.java
+++ b/tests/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerServiceTest.java
@@ -16,12 +16,12 @@
package com.android.inputmethod.latin.spellcheck;
-import android.text.SpannableStringBuilder;
-import android.text.style.CharacterStyle;
+import android.test.suitebuilder.annotation.LargeTest;
import android.text.style.SuggestionSpan;
import com.android.inputmethod.latin.InputTestsBase;
+@LargeTest
public class AndroidSpellCheckerServiceTest extends InputTestsBase {
public void testSpellchecker() {
mTextView.onAttachedToWindow();
diff --git a/tests/src/com/android/inputmethod/research/MotionEventReaderTests.java b/tests/src/com/android/inputmethod/research/MotionEventReaderTests.java
new file mode 100644
index 0000000..e5b9bc0
--- /dev/null
+++ b/tests/src/com/android/inputmethod/research/MotionEventReaderTests.java
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2013 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.
+ */
+
+package com.android.inputmethod.research;
+
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.util.JsonReader;
+
+import com.android.inputmethod.research.MotionEventReader.ReplayData;
+
+import java.io.IOException;
+import java.io.StringReader;
+
+@SmallTest
+public class MotionEventReaderTests extends AndroidTestCase {
+ private MotionEventReader mMotionEventReader = new MotionEventReader();
+ private ReplayData mReplayData;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mReplayData = new ReplayData();
+ }
+
+ private JsonReader jsonReaderForString(final String s) {
+ return new JsonReader(new StringReader(s));
+ }
+
+ public void testTopLevelDataVariant() {
+ final JsonReader jsonReader = jsonReaderForString(
+ "{"
+ + "\"_ct\": 1359590400000,"
+ + "\"_ut\": 4381933,"
+ + "\"_ty\": \"MotionEvent\","
+ + "\"action\": \"UP\","
+ + "\"isLoggingRelated\": false,"
+ + "\"x\": 100.0,"
+ + "\"y\": 200.0"
+ + "}"
+ );
+ try {
+ mMotionEventReader.readLogStatement(jsonReader, mReplayData);
+ } catch (IOException e) {
+ e.printStackTrace();
+ fail("IOException thrown");
+ }
+ assertEquals("x set correctly", (int) mReplayData.mPointerCoordsArrays.get(0)[0].x, 100);
+ assertEquals("y set correctly", (int) mReplayData.mPointerCoordsArrays.get(0)[0].y, 200);
+ assertEquals("only one pointer", mReplayData.mPointerCoordsArrays.get(0).length, 1);
+ assertEquals("only one MotionEvent", mReplayData.mPointerCoordsArrays.size(), 1);
+ }
+
+ public void testNestedDataVariant() {
+ final JsonReader jsonReader = jsonReaderForString(
+ "{"
+ + " \"_ct\": 135959040000,"
+ + " \"_ut\": 4382702,"
+ + " \"_ty\": \"MotionEvent\","
+ + " \"action\": \"MOVE\","
+ + " \"isLoggingRelated\": false,"
+ + " \"motionEvent\": {"
+ + " \"pointerIds\": ["
+ + " 0"
+ + " ],"
+ + " \"xyt\": ["
+ + " {"
+ + " \"t\": 4382551,"
+ + " \"d\": ["
+ + " {"
+ + " \"x\": 100.0,"
+ + " \"y\": 200.0,"
+ + " \"toma\": 999.0,"
+ + " \"tomi\": 999.0,"
+ + " \"o\": 0.0"
+ + " }"
+ + " ]"
+ + " },"
+ + " {"
+ + " \"t\": 4382559,"
+ + " \"d\": ["
+ + " {"
+ + " \"x\": 300.0,"
+ + " \"y\": 400.0,"
+ + " \"toma\": 999.0,"
+ + " \"tomi\": 999.0,"
+ + " \"o\": 0.0"
+ + " }"
+ + " ]"
+ + " }"
+ + " ]"
+ + " }"
+ + "}"
+ );
+ try {
+ mMotionEventReader.readLogStatement(jsonReader, mReplayData);
+ } catch (IOException e) {
+ e.printStackTrace();
+ fail("IOException thrown");
+ }
+ assertEquals("x1 set correctly", (int) mReplayData.mPointerCoordsArrays.get(0)[0].x, 100);
+ assertEquals("y1 set correctly", (int) mReplayData.mPointerCoordsArrays.get(0)[0].y, 200);
+ assertEquals("x2 set correctly", (int) mReplayData.mPointerCoordsArrays.get(1)[0].x, 300);
+ assertEquals("y2 set correctly", (int) mReplayData.mPointerCoordsArrays.get(1)[0].y, 400);
+ assertEquals("only one pointer", mReplayData.mPointerCoordsArrays.get(0).length, 1);
+ assertEquals("two MotionEvents", mReplayData.mPointerCoordsArrays.size(), 2);
+ }
+
+ public void testNestedDataVariantMultiPointer() {
+ final JsonReader jsonReader = jsonReaderForString(
+ "{"
+ + " \"_ct\": 135959040000,"
+ + " \"_ut\": 4382702,"
+ + " \"_ty\": \"MotionEvent\","
+ + " \"action\": \"MOVE\","
+ + " \"isLoggingRelated\": false,"
+ + " \"motionEvent\": {"
+ + " \"pointerIds\": ["
+ + " 1"
+ + " ],"
+ + " \"xyt\": ["
+ + " {"
+ + " \"t\": 4382551,"
+ + " \"d\": ["
+ + " {"
+ + " \"x\": 100.0,"
+ + " \"y\": 200.0,"
+ + " \"toma\": 999.0,"
+ + " \"tomi\": 999.0,"
+ + " \"o\": 0.0"
+ + " },"
+ + " {"
+ + " \"x\": 300.0,"
+ + " \"y\": 400.0,"
+ + " \"toma\": 999.0,"
+ + " \"tomi\": 999.0,"
+ + " \"o\": 0.0"
+ + " }"
+ + " ]"
+ + " }"
+ + " ]"
+ + " }"
+ + "}"
+ );
+ try {
+ mMotionEventReader.readLogStatement(jsonReader, mReplayData);
+ } catch (IOException e) {
+ e.printStackTrace();
+ fail("IOException thrown");
+ }
+ assertEquals("x1 set correctly", (int) mReplayData.mPointerCoordsArrays.get(0)[0].x, 100);
+ assertEquals("y1 set correctly", (int) mReplayData.mPointerCoordsArrays.get(0)[0].y, 200);
+ assertEquals("x2 set correctly", (int) mReplayData.mPointerCoordsArrays.get(0)[1].x, 300);
+ assertEquals("y2 set correctly", (int) mReplayData.mPointerCoordsArrays.get(0)[1].y, 400);
+ assertEquals("two pointers", mReplayData.mPointerCoordsArrays.get(0).length, 2);
+ assertEquals("one MotionEvent", mReplayData.mPointerCoordsArrays.size(), 1);
+ }
+}