aboutsummaryrefslogtreecommitdiffstats
path: root/java/src
diff options
context:
space:
mode:
Diffstat (limited to 'java/src')
-rw-r--r--java/src/com/android/inputmethod/compat/TextViewCompatUtils.java44
-rw-r--r--java/src/com/android/inputmethod/compat/ViewCompatUtils.java68
-rw-r--r--java/src/com/android/inputmethod/latin/WordComposer.java4
-rw-r--r--java/src/com/android/inputmethod/latin/setup/SetupActivity.java311
-rw-r--r--java/src/com/android/inputmethod/latin/setup/SetupStepIndicatorView.java56
-rw-r--r--java/src/com/android/inputmethod/research/LogUnit.java6
-rw-r--r--java/src/com/android/inputmethod/research/LoggingUtils.java38
-rw-r--r--java/src/com/android/inputmethod/research/MainLogBuffer.java42
-rw-r--r--java/src/com/android/inputmethod/research/ResearchLog.java2
-rw-r--r--java/src/com/android/inputmethod/research/ResearchLogger.java30
10 files changed, 551 insertions, 50 deletions
diff --git a/java/src/com/android/inputmethod/compat/TextViewCompatUtils.java b/java/src/com/android/inputmethod/compat/TextViewCompatUtils.java
new file mode 100644
index 000000000..d4f1ea830
--- /dev/null
+++ b/java/src/com/android/inputmethod/compat/TextViewCompatUtils.java
@@ -0,0 +1,44 @@
+/*
+ * 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.compat;
+
+import android.graphics.drawable.Drawable;
+import android.widget.TextView;
+
+import java.lang.reflect.Method;
+
+public final class TextViewCompatUtils {
+ // Note that TextView.setCompoundDrawablesRelative(Drawable,Drawable,Drawable,Drawable) has
+ // been introduced in API level 17 (Build.VERSION_CODE.JELLY_BEAN_MR1).
+ private static final Method METHOD_setCompoundDrawablesRelative = CompatUtils.getMethod(
+ TextView.class, "setCompoundDrawablesRelative",
+ Drawable.class, Drawable.class, Drawable.class, Drawable.class);
+
+ private TextViewCompatUtils() {
+ // This utility class is not publicly instantiable.
+ }
+
+ public static void setCompoundDrawablesRelative(final TextView textView, final Drawable start,
+ final Drawable top, final Drawable end, final Drawable bottom) {
+ if (METHOD_setCompoundDrawablesRelative == null) {
+ textView.setCompoundDrawables(start, top, end, bottom);
+ return;
+ }
+ CompatUtils.invoke(textView, null, METHOD_setCompoundDrawablesRelative,
+ start, top, end, bottom);
+ }
+}
diff --git a/java/src/com/android/inputmethod/compat/ViewCompatUtils.java b/java/src/com/android/inputmethod/compat/ViewCompatUtils.java
new file mode 100644
index 000000000..a8fab8855
--- /dev/null
+++ b/java/src/com/android/inputmethod/compat/ViewCompatUtils.java
@@ -0,0 +1,68 @@
+/*
+ * 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.compat;
+
+import android.view.View;
+
+import java.lang.reflect.Method;
+
+public final class ViewCompatUtils {
+ // Note that View.LAYOUT_DIRECTION_LTR and View.LAYOUT_DIRECTION_RTL have been introduced in
+ // API level 17 (Build.VERSION_CODE.JELLY_BEAN_MR1).
+ public static final int LAYOUT_DIRECTION_LTR = (Integer)CompatUtils.getFieldValue(null, 0x0,
+ CompatUtils.getField(View.class, "LAYOUT_DIRECTION_LTR"));
+ public static final int LAYOUT_DIRECTION_RTL = (Integer)CompatUtils.getFieldValue(null, 0x1,
+ CompatUtils.getField(View.class, "LAYOUT_DIRECTION_RTL"));
+
+ // Note that View.getPaddingEnd(), View.setPaddingRelative(int,int,int,int), and
+ // View.getLayoutDirection() have been introduced in API level 17
+ // (Build.VERSION_CODE.JELLY_BEAN_MR1).
+ private static final Method METHOD_getPaddingEnd = CompatUtils.getMethod(
+ View.class, "getPaddingEnd");
+ private static final Method METHOD_setPaddingRelative = CompatUtils.getMethod(
+ View.class, "setPaddingRelative",
+ Integer.TYPE, Integer.TYPE, Integer.TYPE, Integer.TYPE);
+ private static final Method METHOD_getLayoutDirection = CompatUtils.getMethod(
+ View.class, "getLayoutDirection");
+
+ private ViewCompatUtils() {
+ // This utility class is not publicly instantiable.
+ }
+
+ public static int getPaddingEnd(final View view) {
+ if (METHOD_getPaddingEnd == null) {
+ return view.getPaddingRight();
+ }
+ return (Integer)CompatUtils.invoke(view, 0, METHOD_getPaddingEnd);
+ }
+
+ public static void setPaddingRelative(final View view, final int start, final int top,
+ final int end, final int bottom) {
+ if (METHOD_setPaddingRelative == null) {
+ view.setPadding(start, top, end, bottom);
+ return;
+ }
+ CompatUtils.invoke(view, null, METHOD_setPaddingRelative, start, top, end, bottom);
+ }
+
+ public static int getLayoutDirection(final View view) {
+ if (METHOD_getLayoutDirection == null) {
+ return LAYOUT_DIRECTION_LTR;
+ }
+ return (Integer)CompatUtils.invoke(view, 0, METHOD_getLayoutDirection);
+ }
+}
diff --git a/java/src/com/android/inputmethod/latin/WordComposer.java b/java/src/com/android/inputmethod/latin/WordComposer.java
index 31f616dd9..f7cb4346a 100644
--- a/java/src/com/android/inputmethod/latin/WordComposer.java
+++ b/java/src/com/android/inputmethod/latin/WordComposer.java
@@ -16,6 +16,7 @@
package com.android.inputmethod.latin;
+import com.android.inputmethod.annotations.UsedForTesting;
import com.android.inputmethod.keyboard.Key;
import com.android.inputmethod.keyboard.Keyboard;
@@ -177,7 +178,8 @@ public final class WordComposer {
/**
* Internal method to retrieve reasonable proximity info for a character.
*/
- private void addKeyInfo(final int codePoint, final Keyboard keyboard) {
+ @UsedForTesting
+ public void addKeyInfo(final int codePoint, final Keyboard keyboard) {
final int x, y;
final Key key;
if (keyboard != null && (key = keyboard.getKey(codePoint)) != null) {
diff --git a/java/src/com/android/inputmethod/latin/setup/SetupActivity.java b/java/src/com/android/inputmethod/latin/setup/SetupActivity.java
index fab894584..c30ecfb16 100644
--- a/java/src/com/android/inputmethod/latin/setup/SetupActivity.java
+++ b/java/src/com/android/inputmethod/latin/setup/SetupActivity.java
@@ -18,22 +18,323 @@ package com.android.inputmethod.latin.setup;
import android.app.Activity;
import android.content.Intent;
+import android.content.res.Resources;
+import android.graphics.PorterDuff;
+import android.graphics.drawable.Drawable;
import android.os.Bundle;
+import android.os.Message;
+import android.provider.Settings;
+import android.view.View;
+import android.view.inputmethod.InputMethodInfo;
+import android.view.inputmethod.InputMethodManager;
+import android.widget.TextView;
+import com.android.inputmethod.compat.TextViewCompatUtils;
+import com.android.inputmethod.compat.ViewCompatUtils;
+import com.android.inputmethod.latin.CollectionUtils;
+import com.android.inputmethod.latin.R;
+import com.android.inputmethod.latin.RichInputMethodManager;
import com.android.inputmethod.latin.SettingsActivity;
+import com.android.inputmethod.latin.StaticInnerHandlerWrapper;
+
+import java.util.HashMap;
public final class SetupActivity extends Activity {
+ private SetupStepIndicatorView mStepIndicatorView;
+ private final SetupStepGroup mSetupSteps = new SetupStepGroup();
+ private static final String STATE_STEP = "step";
+ private int mStepNo;
+ private static final int STEP_1 = 1;
+ private static final int STEP_2 = 2;
+ private static final int STEP_3 = 3;
+
+ private final SettingsPoolingHandler mHandler = new SettingsPoolingHandler(this);
+
+ static final class SettingsPoolingHandler extends StaticInnerHandlerWrapper<SetupActivity> {
+ private static final int MSG_POLLING_IME_SETTINGS = 0;
+ private static final long IME_SETTINGS_POLLING_INTERVAL = 200;
+
+ public SettingsPoolingHandler(final SetupActivity outerInstance) {
+ super(outerInstance);
+ }
+
+ @Override
+ public void handleMessage(final Message msg) {
+ final SetupActivity setupActivity = getOuterInstance();
+ switch (msg.what) {
+ case MSG_POLLING_IME_SETTINGS:
+ if (setupActivity.isMyImeEnabled()) {
+ setupActivity.invokeSetupWizardOfThisIme();
+ return;
+ }
+ startPollingImeSettings();
+ break;
+ }
+ }
+
+ public void startPollingImeSettings() {
+ sendMessageDelayed(obtainMessage(MSG_POLLING_IME_SETTINGS),
+ IME_SETTINGS_POLLING_INTERVAL);
+ }
+
+ public void cancelPollingImeSettings() {
+ removeMessages(MSG_POLLING_IME_SETTINGS);
+ }
+ }
+
@Override
- protected void onCreate(Bundle savedInstanceState) {
+ protected void onCreate(final Bundle savedInstanceState) {
+ setTheme(android.R.style.Theme_DeviceDefault_Light_NoActionBar);
super.onCreate(savedInstanceState);
- // TODO: Implement setup wizard.
+ setContentView(R.layout.setup_wizard);
+
+ RichInputMethodManager.init(this);
+
+ if (savedInstanceState == null) {
+ mStepNo = determineSetupStepNo();
+ } else {
+ mStepNo = savedInstanceState.getInt(STATE_STEP);
+ }
+
+ if (mStepNo == STEP_3) {
+ // This IME already has been enabled and set as current IME.
+ // TODO: Implement tutorial.
+ invokeSettingsOfThisIme();
+ finish();
+ return;
+ }
+
+ // TODO: Use sans-serif-thin font family depending on the system locale white list and
+ // the SDK version.
+ final TextView titleView = (TextView)findViewById(R.id.setup_title);
+ titleView.setText(getString(R.string.setup_title, getString(R.string.english_ime_name)));
+
+ mStepIndicatorView = (SetupStepIndicatorView)findViewById(R.id.setup_step_indicator);
+
+ final SetupStep step1 = new SetupStep(findViewById(R.id.setup_step1),
+ R.string.setup_step1_title, R.string.setup_step1_instruction,
+ R.drawable.ic_settings_language, R.string.language_settings);
+ step1.setAction(new Runnable() {
+ @Override
+ public void run() {
+ invokeLanguageAndInputSettings();
+ mHandler.startPollingImeSettings();
+ }
+ });
+ mSetupSteps.addStep(STEP_1, step1);
+
+ final SetupStep step2 = new SetupStep(findViewById(R.id.setup_step2),
+ R.string.setup_step2_title, R.string.setup_step2_instruction,
+ 0 /* actionIcon */, R.string.select_input_method);
+ step2.setAction(new Runnable() {
+ @Override
+ public void run() {
+ // Invoke input method picker.
+ RichInputMethodManager.getInstance().getInputMethodManager()
+ .showInputMethodPicker();
+ }
+ });
+ mSetupSteps.addStep(STEP_2, step2);
+
+ final SetupStep step3 = new SetupStep(findViewById(R.id.setup_step3),
+ R.string.setup_step3_title, 0 /* instruction */,
+ R.drawable.sym_keyboard_language_switch, R.string.setup_step3_instruction);
+ step3.setAction(new Runnable() {
+ @Override
+ public void run() {
+ invokeSubtypeEnablerOfThisIme();
+ }
+ });
+ mSetupSteps.addStep(STEP_3, step3);
+ }
+
+ private void invokeSetupWizardOfThisIme() {
+ final Intent intent = new Intent();
+ intent.setClass(this, SetupActivity.class);
+ intent.setFlags(Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
+ | Intent.FLAG_ACTIVITY_CLEAR_TOP);
+ startActivity(intent);
+ }
+
+ private void invokeSettingsOfThisIme() {
final Intent intent = new Intent();
intent.setClass(this, SettingsActivity.class);
- intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
- | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
+ intent.setFlags(Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
| Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
- finish();
+ }
+
+ private void invokeLanguageAndInputSettings() {
+ final Intent intent = new Intent();
+ intent.setAction(Settings.ACTION_INPUT_METHOD_SETTINGS);
+ intent.addCategory(Intent.CATEGORY_DEFAULT);
+ startActivity(intent);
+ }
+
+ private void invokeSubtypeEnablerOfThisIme() {
+ final InputMethodInfo imi =
+ RichInputMethodManager.getInstance().getInputMethodInfoOfThisIme();
+ final Intent intent = new Intent();
+ intent.setAction(Settings.ACTION_INPUT_METHOD_SUBTYPE_SETTINGS);
+ intent.addCategory(Intent.CATEGORY_DEFAULT);
+ intent.putExtra(Settings.EXTRA_INPUT_METHOD_ID, imi.getId());
+ startActivity(intent);
+ }
+
+ private boolean isMyImeEnabled() {
+ final String packageName = getPackageName();
+ final InputMethodManager imm = RichInputMethodManager.getInstance().getInputMethodManager();
+ for (final InputMethodInfo imi : imm.getEnabledInputMethodList()) {
+ if (packageName.equals(imi.getPackageName())) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private boolean isMyImeCurrent() {
+ final InputMethodInfo myImi =
+ RichInputMethodManager.getInstance().getInputMethodInfoOfThisIme();
+ final String currentImeId = Settings.Secure.getString(
+ getContentResolver(), Settings.Secure.DEFAULT_INPUT_METHOD);
+ return myImi.getId().equals(currentImeId);
+ }
+
+ private int determineSetupStepNo() {
+ mHandler.cancelPollingImeSettings();
+ if (!isMyImeEnabled()) {
+ return STEP_1;
+ }
+ if (!isMyImeCurrent()) {
+ return STEP_2;
+ }
+ return STEP_3;
+ }
+
+ @Override
+ protected void onSaveInstanceState(final Bundle outState) {
+ super.onSaveInstanceState(outState);
+ outState.putInt(STATE_STEP, mStepNo);
+ }
+
+ @Override
+ protected void onRestoreInstanceState(final Bundle savedInstanceState) {
+ super.onRestoreInstanceState(savedInstanceState);
+ mStepNo = savedInstanceState.getInt(STATE_STEP);
+ }
+
+ @Override
+ protected void onStart() {
+ super.onStart();
+ mStepNo = determineSetupStepNo();
+ }
+
+ @Override
+ protected void onRestart() {
+ super.onRestart();
+ mStepNo = determineSetupStepNo();
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ updateSetupStepView();
+ }
+
+ @Override
+ public void onWindowFocusChanged(final boolean hasFocus) {
+ super.onWindowFocusChanged(hasFocus);
+ if (!hasFocus) {
+ return;
+ }
+ mStepNo = determineSetupStepNo();
+ updateSetupStepView();
+ }
+
+ private void updateSetupStepView() {
+ final int layoutDirection = ViewCompatUtils.getLayoutDirection(mStepIndicatorView);
+ mStepIndicatorView.setIndicatorPosition(
+ getIndicatorPosition(mStepNo, mSetupSteps.getTotalStep(), layoutDirection));
+ mSetupSteps.enableStep(mStepNo);
+ }
+
+ private static float getIndicatorPosition(final int step, final int totalStep,
+ final int layoutDirection) {
+ final float pos = ((step - STEP_1) * 2 + 1) / (float)(totalStep * 2);
+ return (layoutDirection == ViewCompatUtils.LAYOUT_DIRECTION_RTL) ? 1.0f - pos : pos;
+ }
+
+ static final class SetupStep implements View.OnClickListener {
+ private final View mRootView;
+ private final TextView mActionLabel;
+ private Runnable mAction;
+
+ public SetupStep(final View rootView, final int title, final int instruction,
+ final int actionIcon, final int actionLabel) {
+ mRootView = rootView;
+ final Resources res = rootView.getResources();
+ final String applicationName = res.getString(R.string.english_ime_name);
+
+ final TextView titleView = (TextView)rootView.findViewById(R.id.setup_step_title);
+ titleView.setText(res.getString(title, applicationName));
+
+ final TextView instructionView = (TextView)rootView.findViewById(
+ R.id.setup_step_instruction);
+ if (instruction == 0) {
+ instructionView.setVisibility(View.GONE);
+ } else {
+ instructionView.setText(res.getString(instruction, applicationName));
+ }
+
+ mActionLabel = (TextView)rootView.findViewById(R.id.setup_step_action_label);
+ mActionLabel.setText(res.getString(actionLabel));
+ if (actionIcon == 0) {
+ final int paddingEnd = ViewCompatUtils.getPaddingEnd(mActionLabel);
+ ViewCompatUtils.setPaddingRelative(mActionLabel, paddingEnd, 0, paddingEnd, 0);
+ } else {
+ final int overrideColor = res.getColor(R.color.setup_text_action);
+ final Drawable icon = res.getDrawable(actionIcon);
+ icon.setColorFilter(overrideColor, PorterDuff.Mode.MULTIPLY);
+ icon.setBounds(0, 0, icon.getIntrinsicWidth(), icon.getIntrinsicHeight());
+ TextViewCompatUtils.setCompoundDrawablesRelative(
+ mActionLabel, icon, null, null, null);
+ }
+ }
+
+ public void setEnabled(final boolean enabled) {
+ mRootView.setVisibility(enabled ? View.VISIBLE : View.GONE);
+ }
+
+ public void setAction(final Runnable action) {
+ mActionLabel.setOnClickListener(this);
+ mAction = action;
+ }
+
+ @Override
+ public void onClick(final View v) {
+ if (mAction != null) {
+ mAction.run();
+ }
+ }
+ }
+
+ static final class SetupStepGroup {
+ private final HashMap<Integer, SetupStep> mGroup = CollectionUtils.newHashMap();
+
+ public void addStep(final int stepNo, final SetupStep step) {
+ mGroup.put(stepNo, step);
+ }
+
+ public void enableStep(final int enableStepNo) {
+ for (final Integer stepNo : mGroup.keySet()) {
+ final SetupStep step = mGroup.get(stepNo);
+ step.setEnabled(stepNo == enableStepNo);
+ }
+ }
+
+ public int getTotalStep() {
+ return mGroup.size();
+ }
}
}
diff --git a/java/src/com/android/inputmethod/latin/setup/SetupStepIndicatorView.java b/java/src/com/android/inputmethod/latin/setup/SetupStepIndicatorView.java
new file mode 100644
index 000000000..077a21793
--- /dev/null
+++ b/java/src/com/android/inputmethod/latin/setup/SetupStepIndicatorView.java
@@ -0,0 +1,56 @@
+/*
+ * 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.setup;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Path;
+import android.util.AttributeSet;
+import android.view.View;
+
+import com.android.inputmethod.latin.R;
+
+public final class SetupStepIndicatorView extends View {
+ private final Path mIndicatorPath = new Path();
+ private final Paint mIndicatorPaint = new Paint();
+ private float mXRatio;
+
+ public SetupStepIndicatorView(final Context context, final AttributeSet attrs) {
+ super(context, attrs);
+ mIndicatorPaint.setColor(getResources().getColor(R.color.setup_step_background));
+ mIndicatorPaint.setStyle(Paint.Style.FILL);
+ }
+
+ public void setIndicatorPosition(final float xRatio) {
+ mXRatio = xRatio;
+ invalidate();
+ }
+
+ @Override
+ protected void onDraw(final Canvas canvas) {
+ super.onDraw(canvas);
+ final int xPos = (int)(getWidth() * mXRatio);
+ final int height = getHeight();
+ mIndicatorPath.rewind();
+ mIndicatorPath.moveTo(xPos, 0);
+ mIndicatorPath.lineTo(xPos + height, height);
+ mIndicatorPath.lineTo(xPos - height, height);
+ mIndicatorPath.close();
+ canvas.drawPath(mIndicatorPath, mIndicatorPaint);
+ }
+}
diff --git a/java/src/com/android/inputmethod/research/LogUnit.java b/java/src/com/android/inputmethod/research/LogUnit.java
index 1a9a720f3..e91976a03 100644
--- a/java/src/com/android/inputmethod/research/LogUnit.java
+++ b/java/src/com/android/inputmethod/research/LogUnit.java
@@ -151,10 +151,10 @@ import java.util.List;
continue;
}
// Only retrieve the jsonWriter if we need to. If we don't get this far, then
- // researchLog.getValidJsonWriterLocked() will not ever be called, and the file
- // will not have been opened for writing.
+ // researchLog.getInitializedJsonWriterLocked() will not ever be called, and the
+ // file will not have been opened for writing.
if (jsonWriter == null) {
- jsonWriter = researchLog.getValidJsonWriterLocked();
+ jsonWriter = researchLog.getInitializedJsonWriterLocked();
outputLogUnitStart(jsonWriter, canIncludePrivateData);
}
logStatement.outputToLocked(jsonWriter, mTimeList.get(i), mValuesList.get(i));
diff --git a/java/src/com/android/inputmethod/research/LoggingUtils.java b/java/src/com/android/inputmethod/research/LoggingUtils.java
new file mode 100644
index 000000000..1261d6780
--- /dev/null
+++ b/java/src/com/android/inputmethod/research/LoggingUtils.java
@@ -0,0 +1,38 @@
+/*
+ * 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.view.MotionEvent;
+
+/* package */ class LoggingUtils {
+ private LoggingUtils() {
+ // This utility class is not publicly instantiable.
+ }
+
+ /* package */ static String getMotionEventActionTypeString(final int actionType) {
+ switch (actionType) {
+ case MotionEvent.ACTION_CANCEL: return "CANCEL";
+ case MotionEvent.ACTION_UP: return "UP";
+ case MotionEvent.ACTION_DOWN: return "DOWN";
+ case MotionEvent.ACTION_POINTER_UP: return "POINTER_UP";
+ case MotionEvent.ACTION_POINTER_DOWN: return "POINTER_DOWN";
+ case MotionEvent.ACTION_MOVE: return "MOVE";
+ case MotionEvent.ACTION_OUTSIDE: return "OUTSIDE";
+ default: return "ACTION_" + actionType;
+ }
+ }
+}
diff --git a/java/src/com/android/inputmethod/research/MainLogBuffer.java b/java/src/com/android/inputmethod/research/MainLogBuffer.java
index 3a87bf1df..45b83dd76 100644
--- a/java/src/com/android/inputmethod/research/MainLogBuffer.java
+++ b/java/src/com/android/inputmethod/research/MainLogBuffer.java
@@ -64,15 +64,6 @@ public abstract class MainLogBuffer extends FixedLogBuffer {
// The size of the n-grams logged. E.g. N_GRAM_SIZE = 2 means to sample bigrams.
public static final int N_GRAM_SIZE = 2;
- // Whether all words should be recorded, leaving unsampled word between bigrams. Useful for
- // testing.
- /* package for test */ static final boolean IS_LOGGING_EVERYTHING = false
- && ProductionFlag.IS_EXPERIMENTAL_DEBUG;
-
- // The number of words between n-grams to omit from the log.
- private static final int DEFAULT_NUMBER_OF_WORDS_BETWEEN_SAMPLES =
- IS_LOGGING_EVERYTHING ? 0 : (DEBUG ? 2 : 18);
-
private Suggest mSuggest;
private boolean mIsStopping = false;
@@ -82,17 +73,21 @@ public abstract class MainLogBuffer extends FixedLogBuffer {
// after a sample is taken.
/* package for test */ int mNumWordsUntilSafeToSample;
- public MainLogBuffer() {
- super(N_GRAM_SIZE + DEFAULT_NUMBER_OF_WORDS_BETWEEN_SAMPLES);
- mNumWordsBetweenNGrams = DEFAULT_NUMBER_OF_WORDS_BETWEEN_SAMPLES;
- final Random random = new Random();
- mNumWordsUntilSafeToSample = DEBUG ? 0 : random.nextInt(mNumWordsBetweenNGrams + 1);
+ public MainLogBuffer(final int wordsBetweenSamples, final int numInitialWordsToIgnore) {
+ super(N_GRAM_SIZE + wordsBetweenSamples);
+ mNumWordsBetweenNGrams = wordsBetweenSamples;
+ mNumWordsUntilSafeToSample = DEBUG ? 0 : numInitialWordsToIgnore;
}
public void setSuggest(final Suggest suggest) {
mSuggest = suggest;
}
+ private Dictionary getDictionary() {
+ if (mSuggest == null || !mSuggest.hasMainDictionary()) return null;
+ return mSuggest.getMainDictionary();
+ }
+
public void resetWordCounter() {
mNumWordsUntilSafeToSample = mNumWordsBetweenNGrams;
}
@@ -114,7 +109,7 @@ public abstract class MainLogBuffer extends FixedLogBuffer {
*/
private boolean isSafeNGram(final ArrayList<LogUnit> logUnits, final int minNGramSize) {
// Bypass privacy checks when debugging.
- if (IS_LOGGING_EVERYTHING) {
+ if (ResearchLogger.IS_LOGGING_EVERYTHING) {
if (mIsStopping) {
return true;
}
@@ -137,16 +132,13 @@ public abstract class MainLogBuffer extends FixedLogBuffer {
if (mNumWordsUntilSafeToSample > 0) {
return false;
}
- if (mSuggest == null || !mSuggest.hasMainDictionary()) {
- // Main dictionary is unavailable. Since we cannot check it, we cannot tell if a
- // word is out-of-vocabulary or not. Therefore, we must judge the entire buffer
- // contents to potentially pose a privacy risk.
- return false;
- }
// Reload the dictionary in case it has changed (e.g., because the user has changed
// languages).
- final Dictionary dictionary = mSuggest.getMainDictionary();
+ final Dictionary dictionary = getDictionary();
if (dictionary == null) {
+ // Main dictionary is unavailable. Since we cannot check it, we cannot tell if a
+ // word is out-of-vocabulary or not. Therefore, we must judge the entire buffer
+ // contents to potentially pose a privacy risk.
return false;
}
@@ -220,10 +212,10 @@ public abstract class MainLogBuffer extends FixedLogBuffer {
final boolean canIncludePrivateData);
@Override
- protected void shiftOutWords(int numWords) {
- int oldNumActualWords = getNumActualWords();
+ protected void shiftOutWords(final int numWords) {
+ final int oldNumActualWords = getNumActualWords();
super.shiftOutWords(numWords);
- int numWordsShifted = oldNumActualWords - getNumActualWords();
+ final int numWordsShifted = oldNumActualWords - getNumActualWords();
mNumWordsUntilSafeToSample -= numWordsShifted;
if (DEBUG) {
Log.d(TAG, "wordsUntilSafeToSample now at " + mNumWordsUntilSafeToSample);
diff --git a/java/src/com/android/inputmethod/research/ResearchLog.java b/java/src/com/android/inputmethod/research/ResearchLog.java
index 5114977d8..4dff17530 100644
--- a/java/src/com/android/inputmethod/research/ResearchLog.java
+++ b/java/src/com/android/inputmethod/research/ResearchLog.java
@@ -206,7 +206,7 @@ public class ResearchLog {
* Return a JsonWriter for this ResearchLog. It is initialized the first time this method is
* called. The cached value is returned in future calls.
*/
- public JsonWriter getValidJsonWriterLocked() {
+ public JsonWriter getInitializedJsonWriterLocked() {
try {
if (mJsonWriter == NULL_JSON_WRITER && mFile != null) {
final FileOutputStream fos =
diff --git a/java/src/com/android/inputmethod/research/ResearchLogger.java b/java/src/com/android/inputmethod/research/ResearchLogger.java
index 45212913e..25633d630 100644
--- a/java/src/com/android/inputmethod/research/ResearchLogger.java
+++ b/java/src/com/android/inputmethod/research/ResearchLogger.java
@@ -88,6 +88,7 @@ import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Locale;
+import java.util.Random;
import java.util.UUID;
/**
@@ -132,13 +133,21 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
private static final String USER_RECORDING_FILENAME_SUFFIX = ".txt";
private static final SimpleDateFormat TIMESTAMP_DATEFORMAT =
new SimpleDateFormat("yyyyMMddHHmmssS", Locale.US);
+ // Whether all words should be recorded, leaving unsampled word between bigrams. Useful for
+ // testing.
+ /* package for test */ static final boolean IS_LOGGING_EVERYTHING = false
+ && ProductionFlag.IS_EXPERIMENTAL_DEBUG;
+ // The number of words between n-grams to omit from the log.
+ private static final int NUMBER_OF_WORDS_BETWEEN_SAMPLES =
+ IS_LOGGING_EVERYTHING ? 0 : (DEBUG ? 2 : 18);
+
// Whether to show an indicator on the screen that logging is on. Currently a very small red
// dot in the lower right hand corner. Most users should not notice it.
private static final boolean IS_SHOWING_INDICATOR = true;
// Change the default indicator to something very visible. Currently two red vertical bars on
// either side of they keyboard.
private static final boolean IS_SHOWING_INDICATOR_CLEARLY = false ||
- (MainLogBuffer.IS_LOGGING_EVERYTHING && ProductionFlag.IS_EXPERIMENTAL_DEBUG);
+ (IS_LOGGING_EVERYTHING && ProductionFlag.IS_EXPERIMENTAL_DEBUG);
// FEEDBACK_WORD_BUFFER_SIZE should add 1 because it must also hold the feedback LogUnit itself.
public static final int FEEDBACK_WORD_BUFFER_SIZE = (Integer.MAX_VALUE - 1) + 1;
@@ -464,11 +473,12 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
}
if (mMainLogBuffer == null) {
mMainResearchLog = new ResearchLog(createLogFile(mFilesDir), mLatinIME);
- mMainLogBuffer = new MainLogBuffer() {
+ final int numWordsToIgnore = new Random().nextInt(NUMBER_OF_WORDS_BETWEEN_SAMPLES + 1);
+ mMainLogBuffer = new MainLogBuffer(NUMBER_OF_WORDS_BETWEEN_SAMPLES, numWordsToIgnore) {
@Override
protected void publish(final ArrayList<LogUnit> logUnits,
boolean canIncludePrivateData) {
- canIncludePrivateData |= MainLogBuffer.IS_LOGGING_EVERYTHING;
+ canIncludePrivateData |= IS_LOGGING_EVERYTHING;
final int length = logUnits.size();
for (int i = 0; i < length; i++) {
final LogUnit logUnit = logUnits.get(i);
@@ -1190,7 +1200,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
Integer.toHexString(editorInfo.inputType),
Integer.toHexString(editorInfo.imeOptions), editorInfo.fieldId,
Build.DISPLAY, Build.MODEL, prefs, versionCode, versionName,
- OUTPUT_FORMAT_VERSION, MainLogBuffer.IS_LOGGING_EVERYTHING,
+ OUTPUT_FORMAT_VERSION, IS_LOGGING_EVERYTHING,
ProductionFlag.IS_EXPERIMENTAL_DEBUG);
} catch (NameNotFoundException e) {
e.printStackTrace();
@@ -1226,17 +1236,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
public static void mainKeyboardView_processMotionEvent(final MotionEvent me, final int action,
final long eventTime, final int index, final int id, final int x, final int y) {
if (me != null) {
- final String actionString;
- switch (action) {
- case MotionEvent.ACTION_CANCEL: actionString = "CANCEL"; break;
- case MotionEvent.ACTION_UP: actionString = "UP"; break;
- case MotionEvent.ACTION_DOWN: actionString = "DOWN"; break;
- case MotionEvent.ACTION_POINTER_UP: actionString = "POINTER_UP"; break;
- case MotionEvent.ACTION_POINTER_DOWN: actionString = "POINTER_DOWN"; break;
- case MotionEvent.ACTION_MOVE: actionString = "MOVE"; break;
- case MotionEvent.ACTION_OUTSIDE: actionString = "OUTSIDE"; break;
- default: actionString = "ACTION_" + action; break;
- }
+ final String actionString = LoggingUtils.getMotionEventActionTypeString(action);
final ResearchLogger researchLogger = getInstance();
researchLogger.enqueueEvent(LOGSTATEMENT_MAIN_KEYBOARD_VIEW_PROCESS_MOTION_EVENT,
actionString, false /* IS_LOGGING_RELATED */, MotionEvent.obtain(me));