aboutsummaryrefslogtreecommitdiffstats
path: root/java/src/com
diff options
context:
space:
mode:
Diffstat (limited to 'java/src/com')
-rw-r--r--java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java4
-rw-r--r--java/src/com/android/inputmethod/keyboard/KeyboardView.java5
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/AbstractDrawingPreview.java49
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/GestureFloatingPreviewText.java179
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/PreviewPlacerView.java108
-rw-r--r--java/src/com/android/inputmethod/latin/AudioAndHapticFeedbackManager.java56
-rw-r--r--java/src/com/android/inputmethod/latin/LatinIME.java192
-rw-r--r--java/src/com/android/inputmethod/latin/RichInputConnection.java6
-rw-r--r--java/src/com/android/inputmethod/latin/Settings.java361
-rw-r--r--java/src/com/android/inputmethod/latin/SettingsActivity.java2
-rw-r--r--java/src/com/android/inputmethod/latin/SettingsFragment.java375
-rw-r--r--java/src/com/android/inputmethod/latin/SettingsValues.java24
-rw-r--r--java/src/com/android/inputmethod/latin/UserBinaryDictionary.java25
-rw-r--r--java/src/com/android/inputmethod/latin/VibratorUtils.java50
-rw-r--r--java/src/com/android/inputmethod/research/FixedLogBuffer.java123
-rw-r--r--java/src/com/android/inputmethod/research/JsonUtils.java54
-rw-r--r--java/src/com/android/inputmethod/research/LogBuffer.java96
-rw-r--r--java/src/com/android/inputmethod/research/LogUnit.java3
-rw-r--r--java/src/com/android/inputmethod/research/MainLogBuffer.java22
-rw-r--r--java/src/com/android/inputmethod/research/ResearchLogger.java93
20 files changed, 1113 insertions, 714 deletions
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
index 51517823a..1088fdab4 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
@@ -66,7 +66,8 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions {
new KeyboardTheme(5, R.style.KeyboardTheme_IceCreamSandwich),
};
- private AudioAndHapticFeedbackManager mFeedbackManager;
+ private final AudioAndHapticFeedbackManager mFeedbackManager =
+ AudioAndHapticFeedbackManager.getInstance();
private SubtypeSwitcher mSubtypeSwitcher;
private SharedPreferences mPrefs;
@@ -104,7 +105,6 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions {
private void initInternal(final LatinIME latinIme, final SharedPreferences prefs) {
mLatinIME = latinIme;
mResources = latinIme.getResources();
- mFeedbackManager = new AudioAndHapticFeedbackManager(latinIme);
mPrefs = prefs;
mSubtypeSwitcher = SubtypeSwitcher.getInstance();
mState = new KeyboardState(this);
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardView.java b/java/src/com/android/inputmethod/keyboard/KeyboardView.java
index 61d38745e..b7bee3430 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardView.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardView.java
@@ -50,6 +50,7 @@ import com.android.inputmethod.latin.LatinImeLogger;
import com.android.inputmethod.latin.R;
import com.android.inputmethod.latin.StaticInnerHandlerWrapper;
import com.android.inputmethod.latin.StringUtils;
+import com.android.inputmethod.latin.SuggestedWords;
import com.android.inputmethod.latin.define.ProductionFlag;
import com.android.inputmethod.research.ResearchLogger;
@@ -870,9 +871,9 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy,
mPreviewPlacerView.dismissSlidingKeyInputPreview();
}
- public void showGestureFloatingPreviewText(final String gestureFloatingPreviewText) {
+ public void showGestureFloatingPreviewText(final SuggestedWords suggestedWords) {
locatePreviewPlacerView();
- mPreviewPlacerView.setGestureFloatingPreviewText(gestureFloatingPreviewText);
+ mPreviewPlacerView.setGestureFloatingPreviewText(suggestedWords);
}
public void dismissGestureFloatingPreviewText() {
diff --git a/java/src/com/android/inputmethod/keyboard/internal/AbstractDrawingPreview.java b/java/src/com/android/inputmethod/keyboard/internal/AbstractDrawingPreview.java
new file mode 100644
index 000000000..8a3f0645f
--- /dev/null
+++ b/java/src/com/android/inputmethod/keyboard/internal/AbstractDrawingPreview.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.android.inputmethod.keyboard.internal;
+
+import android.graphics.Canvas;
+
+import com.android.inputmethod.keyboard.PointerTracker;
+
+/**
+ * Abstract base class for previews that are drawn on PreviewPlacerView, e.g.,
+ * GestureFloatingPrevewText, GestureTrail, and SlidingKeyInputPreview.
+ */
+public abstract class AbstractDrawingPreview {
+ private boolean mPreviewEnabled;
+
+ public void setPreviewEnabled(final boolean enabled) {
+ mPreviewEnabled = enabled;
+ }
+
+ public boolean isPreviewEnabled() {
+ return mPreviewEnabled;
+ }
+
+ /**
+ * Draws the preview
+ * @param canvas The canvas where the preview is drawn.
+ */
+ public abstract void onDraw(final Canvas canvas);
+
+ /**
+ * Set the position of the preview.
+ * @param pt The new location of the preview is based on the points in PointerTracker pt.
+ */
+ public abstract void setPreviewPosition(final PointerTracker pt);
+}
diff --git a/java/src/com/android/inputmethod/keyboard/internal/GestureFloatingPreviewText.java b/java/src/com/android/inputmethod/keyboard/internal/GestureFloatingPreviewText.java
new file mode 100644
index 000000000..84cfb389c
--- /dev/null
+++ b/java/src/com/android/inputmethod/keyboard/internal/GestureFloatingPreviewText.java
@@ -0,0 +1,179 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.android.inputmethod.keyboard.internal;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.Paint.Align;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.text.TextUtils;
+
+import com.android.inputmethod.keyboard.PointerTracker;
+import com.android.inputmethod.latin.CoordinateUtils;
+import com.android.inputmethod.latin.R;
+import com.android.inputmethod.latin.ResizableIntArray;
+import com.android.inputmethod.latin.SuggestedWords;
+
+/**
+ * The class for single gesture preview text. The class for multiple gesture preview text will be
+ * derived from it.
+ */
+public class GestureFloatingPreviewText extends AbstractDrawingPreview {
+ private static final class GesturePreviewTextParams {
+ public final int mGesturePreviewTextSize;
+ public final int mGesturePreviewTextColor;
+ public final int mGesturePreviewTextDimmedColor;
+ public final int mGesturePreviewTextOffset;
+ public final int mGesturePreviewTextHeight;
+ public final int mGesturePreviewColor;
+ public final float mGesturePreviewHorizontalPadding;
+ public final float mGesturePreviewVerticalPadding;
+ public final float mGesturePreviewRoundRadius;
+ public final Paint mTextPaint;
+
+ private static final char[] TEXT_HEIGHT_REFERENCE_CHAR = { 'M' };
+
+ public GesturePreviewTextParams(final TypedArray keyboardViewAttr) {
+ mGesturePreviewTextSize = keyboardViewAttr.getDimensionPixelSize(
+ R.styleable.KeyboardView_gestureFloatingPreviewTextSize, 0);
+ mGesturePreviewTextColor = keyboardViewAttr.getColor(
+ R.styleable.KeyboardView_gestureFloatingPreviewTextColor, 0);
+ mGesturePreviewTextOffset = keyboardViewAttr.getDimensionPixelOffset(
+ R.styleable.KeyboardView_gestureFloatingPreviewTextOffset, 0);
+ mGesturePreviewColor = keyboardViewAttr.getColor(
+ R.styleable.KeyboardView_gestureFloatingPreviewColor, 0);
+ mGesturePreviewHorizontalPadding = keyboardViewAttr.getDimension(
+ R.styleable.KeyboardView_gestureFloatingPreviewHorizontalPadding, 0.0f);
+ mGesturePreviewVerticalPadding = keyboardViewAttr.getDimension(
+ R.styleable.KeyboardView_gestureFloatingPreviewVerticalPadding, 0.0f);
+ mGesturePreviewRoundRadius = keyboardViewAttr.getDimension(
+ R.styleable.KeyboardView_gestureFloatingPreviewRoundRadius, 0.0f);
+ mGesturePreviewTextDimmedColor = Color.GRAY;
+
+ final Paint textPaint = new Paint();
+ textPaint.setAntiAlias(true);
+ textPaint.setTextAlign(Align.CENTER);
+ textPaint.setTextSize(mGesturePreviewTextSize);
+ mTextPaint = textPaint;
+ final Rect textRect = new Rect();
+ textPaint.getTextBounds(TEXT_HEIGHT_REFERENCE_CHAR, 0, 1, textRect);
+ mGesturePreviewTextHeight = textRect.height();
+ }
+ }
+
+ protected final GesturePreviewTextParams mParams;
+ protected int mPreviewWordNum;
+ protected final RectF mGesturePreviewRectangle = new RectF();
+ protected int mHighlightedWordIndex;
+
+ private static final int PREVIEW_TEXT_ARRAY_CAPACITY = 10;
+ // These variables store the positions of preview words. In multi-preview mode, the gesture
+ // floating preview at most shows PREVIEW_TEXT_ARRAY_CAPACITY words.
+ protected final ResizableIntArray mPreviewTextXArray = new ResizableIntArray(
+ PREVIEW_TEXT_ARRAY_CAPACITY);
+ protected final ResizableIntArray mPreviewTextYArray = new ResizableIntArray(
+ PREVIEW_TEXT_ARRAY_CAPACITY);
+
+ protected SuggestedWords mSuggestedWords = SuggestedWords.EMPTY;
+ protected final Context mContext;
+ public final int[] mLastPointerCoords = CoordinateUtils.newInstance();
+
+ public GestureFloatingPreviewText(final TypedArray typedArray, final Context context) {
+ mParams = new GesturePreviewTextParams(typedArray);
+ mHighlightedWordIndex = 0;
+ mContext = context;
+ }
+
+ public void setSuggetedWords(final SuggestedWords suggestedWords) {
+ if (suggestedWords == null) {
+ mSuggestedWords = SuggestedWords.EMPTY;
+ } else {
+ mSuggestedWords = suggestedWords;
+ }
+ updatePreviewPosition();
+ }
+
+ protected void drawText(final Canvas canvas, final String text, final float textX,
+ final float textY, final int color) {
+ final Paint paint = mParams.mTextPaint;
+ paint.setColor(color);
+ canvas.drawText(text, textX, textY, paint);
+ }
+
+ @Override
+ public void setPreviewPosition(final PointerTracker pt) {
+ pt.getLastCoordinates(mLastPointerCoords);
+ updatePreviewPosition();
+ }
+
+ /**
+ * Draws gesture preview text
+ * @param canvas The canvas where preview text is drawn.
+ */
+ @Override
+ public void onDraw(final Canvas canvas) {
+ if (!isPreviewEnabled() || mSuggestedWords.isEmpty()
+ || TextUtils.isEmpty(mSuggestedWords.getWord(0))) {
+ return;
+ }
+ final Paint paint = mParams.mTextPaint;
+ paint.setColor(mParams.mGesturePreviewColor);
+ final float round = mParams.mGesturePreviewRoundRadius;
+ canvas.drawRoundRect(mGesturePreviewRectangle, round, round, paint);
+ final String text = mSuggestedWords.getWord(0);
+ final int textX = mPreviewTextXArray.get(0);
+ final int textY = mPreviewTextYArray.get(0);
+ drawText(canvas, text, textX, textY, mParams.mGesturePreviewTextColor);
+ }
+
+ /**
+ * Updates gesture preview text position based on mLastPointerCoords.
+ */
+ protected void updatePreviewPosition() {
+ if (mSuggestedWords.isEmpty() || TextUtils.isEmpty(mSuggestedWords.getWord(0))) {
+ return;
+ }
+ final String text = mSuggestedWords.getWord(0);
+
+ final Paint paint = mParams.mTextPaint;
+ final RectF rectangle = mGesturePreviewRectangle;
+
+ final int textHeight = mParams.mGesturePreviewTextHeight;
+ final float textWidth = paint.measureText(text);
+ final float hPad = mParams.mGesturePreviewHorizontalPadding;
+ final float vPad = mParams.mGesturePreviewVerticalPadding;
+ final float rectWidth = textWidth + hPad * 2.0f;
+ final float rectHeight = textHeight + vPad * 2.0f;
+
+ final int displayWidth = mContext.getResources().getDisplayMetrics().widthPixels;
+ final float rectX = Math.min(
+ Math.max(CoordinateUtils.x(mLastPointerCoords) - rectWidth / 2.0f, 0.0f),
+ displayWidth - rectWidth);
+ final float rectY = CoordinateUtils.y(mLastPointerCoords)
+ - mParams.mGesturePreviewTextOffset - rectHeight;
+ rectangle.set(rectX, rectY, rectX + rectWidth, rectY + rectHeight);
+
+ final int textX = (int)(rectX + hPad + textWidth / 2.0f);
+ final int textY = (int)(rectY + vPad) + textHeight;
+ mPreviewTextXArray.add(0, textX);
+ mPreviewTextYArray.add(0, textY);
+ }
+}
diff --git a/java/src/com/android/inputmethod/keyboard/internal/PreviewPlacerView.java b/java/src/com/android/inputmethod/keyboard/internal/PreviewPlacerView.java
index bc734b08d..a005dc975 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/PreviewPlacerView.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/PreviewPlacerView.java
@@ -22,13 +22,10 @@ import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
-import android.graphics.Paint.Align;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
-import android.graphics.RectF;
import android.os.Message;
-import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.SparseArray;
import android.widget.RelativeLayout;
@@ -39,15 +36,9 @@ import com.android.inputmethod.latin.CollectionUtils;
import com.android.inputmethod.latin.CoordinateUtils;
import com.android.inputmethod.latin.R;
import com.android.inputmethod.latin.StaticInnerHandlerWrapper;
+import com.android.inputmethod.latin.SuggestedWords;
public final class PreviewPlacerView extends RelativeLayout {
- private final int mGestureFloatingPreviewTextColor;
- private final int mGestureFloatingPreviewTextOffset;
- private final int mGestureFloatingPreviewColor;
- private final float mGestureFloatingPreviewHorizontalPadding;
- private final float mGestureFloatingPreviewVerticalPadding;
- private final float mGestureFloatingPreviewRoundRadius;
-
private final int[] mKeyboardViewOrigin = CoordinateUtils.newInstance();
private final SparseArray<GesturePreviewTrail> mGesturePreviewTrails =
@@ -62,16 +53,7 @@ public final class PreviewPlacerView extends RelativeLayout {
private final Canvas mOffscreenCanvas = new Canvas();
private final Rect mOffscreenDirtyRect = new Rect();
private final Rect mGesturePreviewTrailBoundsRect = new Rect(); // per trail
-
- private final Paint mTextPaint;
- private String mGestureFloatingPreviewText;
- private final int mGestureFloatingPreviewTextHeight;
- // {@link RectF} is needed for {@link Canvas#drawRoundRect(RectF, float, float, Paint)}.
- private final RectF mGestureFloatingPreviewRectangle = new RectF();
- private final int[] mLastPointerCoords = CoordinateUtils.newInstance();
- private static final char[] TEXT_HEIGHT_REFERENCE_CHAR = { 'M' };
- private boolean mDrawsGestureFloatingPreviewText;
-
+ private final GestureFloatingPreviewText mGestureFloatingPreviewText;
private boolean mShowSlidingKeyInputPreview;
private final int[] mRubberBandFrom = CoordinateUtils.newInstance();
private final int[] mRubberBandTo = CoordinateUtils.newInstance();
@@ -130,22 +112,11 @@ public final class PreviewPlacerView extends RelativeLayout {
final TypedArray keyboardViewAttr = context.obtainStyledAttributes(
attrs, R.styleable.KeyboardView, defStyle, R.style.KeyboardView);
- final int gestureFloatingPreviewTextSize = keyboardViewAttr.getDimensionPixelSize(
- R.styleable.KeyboardView_gestureFloatingPreviewTextSize, 0);
- mGestureFloatingPreviewTextColor = keyboardViewAttr.getColor(
- R.styleable.KeyboardView_gestureFloatingPreviewTextColor, 0);
- mGestureFloatingPreviewTextOffset = keyboardViewAttr.getDimensionPixelOffset(
- R.styleable.KeyboardView_gestureFloatingPreviewTextOffset, 0);
- mGestureFloatingPreviewColor = keyboardViewAttr.getColor(
- R.styleable.KeyboardView_gestureFloatingPreviewColor, 0);
- mGestureFloatingPreviewHorizontalPadding = keyboardViewAttr.getDimension(
- R.styleable.KeyboardView_gestureFloatingPreviewHorizontalPadding, 0.0f);
- mGestureFloatingPreviewVerticalPadding = keyboardViewAttr.getDimension(
- R.styleable.KeyboardView_gestureFloatingPreviewVerticalPadding, 0.0f);
- mGestureFloatingPreviewRoundRadius = keyboardViewAttr.getDimension(
- R.styleable.KeyboardView_gestureFloatingPreviewRoundRadius, 0.0f);
final int gestureFloatingPreviewTextLingerTimeout = keyboardViewAttr.getInt(
R.styleable.KeyboardView_gestureFloatingPreviewTextLingerTimeout, 0);
+ // TODO: mGestureFloatingPreviewText could be an instance of GestureFloatingPreviewText or
+ // MultiGesturePreviewText, depending on the user's choice in the settings.
+ mGestureFloatingPreviewText = new GestureFloatingPreviewText(keyboardViewAttr, context);
mGesturePreviewTrailParams = new Params(keyboardViewAttr);
keyboardViewAttr.recycle();
@@ -157,15 +128,6 @@ public final class PreviewPlacerView extends RelativeLayout {
gesturePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC));
mGesturePaint = gesturePaint;
- final Paint textPaint = new Paint();
- textPaint.setAntiAlias(true);
- textPaint.setTextAlign(Align.CENTER);
- textPaint.setTextSize(gestureFloatingPreviewTextSize);
- mTextPaint = textPaint;
- final Rect textRect = new Rect();
- textPaint.getTextBounds(TEXT_HEIGHT_REFERENCE_CHAR, 0, 1, textRect);
- mGestureFloatingPreviewTextHeight = textRect.height();
-
final Paint layerPaint = new Paint();
layerPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_OVER));
setLayerType(LAYER_TYPE_HARDWARE, layerPaint);
@@ -181,14 +143,14 @@ public final class PreviewPlacerView extends RelativeLayout {
public void setGesturePreviewMode(final boolean drawsGesturePreviewTrail,
final boolean drawsGestureFloatingPreviewText) {
mDrawsGesturePreviewTrail = drawsGesturePreviewTrail;
- mDrawsGestureFloatingPreviewText = drawsGestureFloatingPreviewText;
+ mGestureFloatingPreviewText.setPreviewEnabled(drawsGestureFloatingPreviewText);
}
public void invalidatePointer(final PointerTracker tracker, final boolean isOldestTracker) {
final boolean needsToUpdateLastPointer =
- isOldestTracker && mDrawsGestureFloatingPreviewText;
+ isOldestTracker && mGestureFloatingPreviewText.isPreviewEnabled();
if (needsToUpdateLastPointer) {
- tracker.getLastCoordinates(mLastPointerCoords);
+ mGestureFloatingPreviewText.setPreviewPosition(tracker);
}
if (mDrawsGesturePreviewTrail) {
@@ -252,6 +214,7 @@ public final class PreviewPlacerView extends RelativeLayout {
super.onDraw(canvas);
final int originX = CoordinateUtils.x(mKeyboardViewOrigin);
final int originY = CoordinateUtils.y(mKeyboardViewOrigin);
+ canvas.translate(originX, originY);
if (mDrawsGesturePreviewTrail) {
mayAllocateOffscreenBuffer();
// Draw gesture trails to offscreen buffer.
@@ -259,11 +222,10 @@ public final class PreviewPlacerView extends RelativeLayout {
mOffscreenCanvas, mGesturePaint, mOffscreenDirtyRect);
// Transfer offscreen buffer to screen.
if (!mOffscreenDirtyRect.isEmpty()) {
- final int offsetY = originY - mOffscreenOffsetY;
- canvas.translate(originX, offsetY);
+ canvas.translate(0, - mOffscreenOffsetY);
canvas.drawBitmap(mOffscreenBuffer, mOffscreenDirtyRect, mOffscreenDirtyRect,
mGesturePaint);
- canvas.translate(-originX, -offsetY);
+ canvas.translate(0, mOffscreenOffsetY);
// Note: Defer clearing the dirty rectangle here because we will get cleared
// rectangle on the canvas.
}
@@ -271,16 +233,11 @@ public final class PreviewPlacerView extends RelativeLayout {
mDrawingHandler.postUpdateGestureTrailPreview();
}
}
- if (mDrawsGestureFloatingPreviewText) {
- canvas.translate(originX, originY);
- drawGestureFloatingPreviewText(canvas, mGestureFloatingPreviewText);
- canvas.translate(-originX, -originY);
- }
+ mGestureFloatingPreviewText.onDraw(canvas);
if (mShowSlidingKeyInputPreview) {
- canvas.translate(originX, originY);
drawSlidingKeyInputPreview(canvas);
- canvas.translate(-originX, -originY);
}
+ canvas.translate(-originX, -originY);
}
private boolean drawGestureTrails(final Canvas offscreenCanvas, final Paint paint,
@@ -322,9 +279,9 @@ public final class PreviewPlacerView extends RelativeLayout {
Math.min(out.bottom, bottom));
}
- public void setGestureFloatingPreviewText(final String gestureFloatingPreviewText) {
- if (!mDrawsGestureFloatingPreviewText) return;
- mGestureFloatingPreviewText = gestureFloatingPreviewText;
+ public void setGestureFloatingPreviewText(final SuggestedWords suggestedWords) {
+ if (!mGestureFloatingPreviewText.isPreviewEnabled()) return;
+ mGestureFloatingPreviewText.setSuggetedWords(suggestedWords);
invalidate();
}
@@ -332,39 +289,6 @@ public final class PreviewPlacerView extends RelativeLayout {
mDrawingHandler.dismissGestureFloatingPreviewText();
}
- private void drawGestureFloatingPreviewText(final Canvas canvas,
- final String gestureFloatingPreviewText) {
- if (TextUtils.isEmpty(gestureFloatingPreviewText)) {
- return;
- }
-
- final Paint paint = mTextPaint;
- final RectF rectangle = mGestureFloatingPreviewRectangle;
-
- // Paint the round rectangle background.
- final int textHeight = mGestureFloatingPreviewTextHeight;
- final float textWidth = paint.measureText(gestureFloatingPreviewText);
- final float hPad = mGestureFloatingPreviewHorizontalPadding;
- final float vPad = mGestureFloatingPreviewVerticalPadding;
- final float rectWidth = textWidth + hPad * 2.0f;
- final float rectHeight = textHeight + vPad * 2.0f;
- final int canvasWidth = canvas.getWidth();
- final float rectX = Math.min(
- Math.max(CoordinateUtils.x(mLastPointerCoords) - rectWidth / 2.0f, 0.0f),
- canvasWidth - rectWidth);
- final float rectY = CoordinateUtils.y(mLastPointerCoords)
- - mGestureFloatingPreviewTextOffset - rectHeight;
- rectangle.set(rectX, rectY, rectX + rectWidth, rectY + rectHeight);
- final float round = mGestureFloatingPreviewRoundRadius;
- paint.setColor(mGestureFloatingPreviewColor);
- canvas.drawRoundRect(rectangle, round, round, paint);
- // Paint the text preview
- paint.setColor(mGestureFloatingPreviewTextColor);
- final float textX = rectX + hPad + textWidth / 2.0f;
- final float textY = rectY + vPad + textHeight;
- canvas.drawText(gestureFloatingPreviewText, textX, textY, paint);
- }
-
private void drawSlidingKeyInputPreview(final Canvas canvas) {
// TODO: Implement rubber band preview
}
diff --git a/java/src/com/android/inputmethod/latin/AudioAndHapticFeedbackManager.java b/java/src/com/android/inputmethod/latin/AudioAndHapticFeedbackManager.java
index 0e7f891ff..6367156ef 100644
--- a/java/src/com/android/inputmethod/latin/AudioAndHapticFeedbackManager.java
+++ b/java/src/com/android/inputmethod/latin/AudioAndHapticFeedbackManager.java
@@ -18,11 +18,10 @@ package com.android.inputmethod.latin;
import android.content.Context;
import android.media.AudioManager;
+import android.os.Vibrator;
import android.view.HapticFeedbackConstants;
import android.view.View;
-import com.android.inputmethod.latin.VibratorUtils;
-
/**
* This class gathers audio feedback and haptic feedback functions.
*
@@ -32,34 +31,61 @@ import com.android.inputmethod.latin.VibratorUtils;
public final class AudioAndHapticFeedbackManager {
public static final int MAX_KEYPRESS_VIBRATION_DURATION = 250; // millisecond
- private final AudioManager mAudioManager;
- private final VibratorUtils mVibratorUtils;
+ private AudioManager mAudioManager;
+ private Vibrator mVibrator;
private SettingsValues mSettingsValues;
private boolean mSoundOn;
- public AudioAndHapticFeedbackManager(final LatinIME latinIme) {
- mVibratorUtils = VibratorUtils.getInstance(latinIme);
- mAudioManager = (AudioManager) latinIme.getSystemService(Context.AUDIO_SERVICE);
+ private static final AudioAndHapticFeedbackManager sInstance =
+ new AudioAndHapticFeedbackManager();
+
+ public static AudioAndHapticFeedbackManager getInstance() {
+ return sInstance;
+ }
+
+ private AudioAndHapticFeedbackManager() {
+ // Intentional empty constructor for singleton.
+ }
+
+ public static void init(final Context context) {
+ sInstance.initInternal(context);
+ }
+
+ private void initInternal(final Context context) {
+ mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
+ mVibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
}
public void hapticAndAudioFeedback(final int primaryCode,
final View viewToPerformHapticFeedbackOn) {
- vibrate(viewToPerformHapticFeedbackOn);
+ vibrateInternal(viewToPerformHapticFeedbackOn);
playKeyClick(primaryCode);
}
+ public boolean hasVibrator() {
+ return mVibrator != null && mVibrator.hasVibrator();
+ }
+
+ public void vibrate(final long milliseconds) {
+ if (mVibrator == null) {
+ return;
+ }
+ mVibrator.vibrate(milliseconds);
+ }
+
private boolean reevaluateIfSoundIsOn() {
if (mSettingsValues == null || !mSettingsValues.mSoundOn || mAudioManager == null) {
return false;
- } else {
- return mAudioManager.getRingerMode() == AudioManager.RINGER_MODE_NORMAL;
}
+ return mAudioManager.getRingerMode() == AudioManager.RINGER_MODE_NORMAL;
}
- private void playKeyClick(int primaryCode) {
+ private void playKeyClick(final int primaryCode) {
// if mAudioManager is null, we can't play a sound anyway, so return
- if (mAudioManager == null) return;
+ if (mAudioManager == null) {
+ return;
+ }
if (mSoundOn) {
final int sound;
switch (primaryCode) {
@@ -80,7 +106,7 @@ public final class AudioAndHapticFeedbackManager {
}
}
- private void vibrate(final View viewToPerformHapticFeedbackOn) {
+ private void vibrateInternal(final View viewToPerformHapticFeedbackOn) {
if (!mSettingsValues.mVibrateOn) {
return;
}
@@ -91,9 +117,9 @@ public final class AudioAndHapticFeedbackManager {
HapticFeedbackConstants.KEYBOARD_TAP,
HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING);
}
- } else if (mVibratorUtils != null) {
- mVibratorUtils.vibrate(mSettingsValues.mKeypressVibrationDuration);
+ return;
}
+ vibrate(mSettingsValues.mKeypressVibrationDuration);
}
public void onSettingsChanged(final SettingsValues settingsValues) {
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index 9d16eb7c5..6eeee9c2a 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -73,7 +73,6 @@ import com.android.inputmethod.keyboard.KeyboardId;
import com.android.inputmethod.keyboard.KeyboardSwitcher;
import com.android.inputmethod.keyboard.KeyboardView;
import com.android.inputmethod.keyboard.MainKeyboardView;
-import com.android.inputmethod.latin.LocaleUtils.RunInLocale;
import com.android.inputmethod.latin.Utils.Stats;
import com.android.inputmethod.latin.define.ProductionFlag;
import com.android.inputmethod.latin.suggestions.SuggestionStripView;
@@ -128,7 +127,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
// Current space state of the input method. This can be any of the above constants.
private int mSpaceState;
- private SettingsValues mCurrentSettings;
+ private final Settings mSettings;
private View mExtractArea;
private View mKeyPreviewBackingView;
@@ -139,8 +138,6 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
private ApplicationInfo mTargetApplicationInfo;
private RichInputMethodManager mRichImm;
- private Resources mResources;
- private SharedPreferences mPrefs;
@UsedForTesting final KeyboardSwitcher mKeyboardSwitcher;
private final SubtypeSwitcher mSubtypeSwitcher;
private final SubtypeState mSubtypeState = new SubtypeState();
@@ -401,6 +398,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
public LatinIME() {
super();
+ mSettings = Settings.getInstance();
mSubtypeSwitcher = SubtypeSwitcher.getInstance();
mKeyboardSwitcher = KeyboardSwitcher.getInstance();
mIsHardwareAcceleratedDrawingEnabled =
@@ -410,9 +408,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
@Override
public void onCreate() {
- mPrefs = PreferenceManager.getDefaultSharedPreferences(this);
- mResources = getResources();
-
+ Settings.init(this);
LatinImeLogger.init(this);
if (ProductionFlag.IS_EXPERIMENTAL) {
ResearchLogger.getInstance().init(this);
@@ -421,6 +417,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
mRichImm = RichInputMethodManager.getInstance();
SubtypeSwitcher.init(this);
KeyboardSwitcher.init(this);
+ AudioAndHapticFeedbackManager.init(this);
AccessibilityUtils.init(this);
super.onCreate();
@@ -431,7 +428,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
loadSettings();
initSuggest();
- mDisplayOrientation = mResources.getConfiguration().orientation;
+ mDisplayOrientation = getResources().getConfiguration().orientation;
// Register to receive ringer mode change and network state change.
// Also receive installation and removal of a dictionary pack.
@@ -458,18 +455,10 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
// Has to be package-visible for unit tests
@UsedForTesting
void loadSettings() {
- // Note that the calling sequence of onCreate() and onCurrentInputMethodSubtypeChanged()
- // is not guaranteed. It may even be called at the same time on a different thread.
- if (null == mPrefs) mPrefs = PreferenceManager.getDefaultSharedPreferences(this);
+ final Locale locale = mSubtypeSwitcher.getCurrentSubtypeLocale();
final InputAttributes inputAttributes =
new InputAttributes(getCurrentInputEditorInfo(), isFullscreenMode());
- final RunInLocale<SettingsValues> job = new RunInLocale<SettingsValues>() {
- @Override
- protected SettingsValues job(Resources res) {
- return new SettingsValues(mPrefs, inputAttributes, LatinIME.this);
- }
- };
- mCurrentSettings = job.runInLocale(mResources, mSubtypeSwitcher.getCurrentSubtypeLocale());
+ mSettings.loadSettings(locale, inputAttributes);
resetContactsDictionary(null == mSuggest ? null : mSuggest.getContactsDictionary());
}
@@ -496,8 +485,8 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
}
mSuggest = new Suggest(this /* Context */, subtypeLocale,
this /* SuggestInitializationListener */);
- if (mCurrentSettings.mCorrectionEnabled) {
- mSuggest.setAutoCorrectionThreshold(mCurrentSettings.mAutoCorrectionThreshold);
+ if (mSettings.getCurrent().mCorrectionEnabled) {
+ mSuggest.setAutoCorrectionThreshold(mSettings.getCurrent().mAutoCorrectionThreshold);
}
mIsMainDictionaryAvailable = DictionaryFactory.isDictionaryAvailable(this, subtypeLocale);
@@ -511,10 +500,8 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
resetContactsDictionary(oldContactsDictionary);
- // Note that the calling sequence of onCreate() and onCurrentInputMethodSubtypeChanged()
- // is not guaranteed. It may even be called at the same time on a different thread.
- if (null == mPrefs) mPrefs = PreferenceManager.getDefaultSharedPreferences(this);
- mUserHistoryDictionary = UserHistoryDictionary.getInstance(this, localeStr, mPrefs);
+ final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
+ mUserHistoryDictionary = UserHistoryDictionary.getInstance(this, localeStr, prefs);
mSuggest.setUserHistoryDictionary(mUserHistoryDictionary);
}
@@ -527,7 +514,8 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
* @param oldContactsDictionary an optional dictionary to use, or null
*/
private void resetContactsDictionary(final ContactsBinaryDictionary oldContactsDictionary) {
- final boolean shouldSetDictionary = (null != mSuggest && mCurrentSettings.mUseContactsDict);
+ final boolean shouldSetDictionary =
+ (null != mSuggest && mSettings.getCurrent().mUseContactsDict);
final ContactsBinaryDictionary dictionaryToUse;
if (!shouldSetDictionary) {
@@ -571,6 +559,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
mSuggest.close();
mSuggest = null;
}
+ mSettings.onDestroy();
unregisterReceiver(mReceiver);
// TODO: The experimental version is not supported by the Dictionary Pack Service yet.
if (!ProductionFlag.IS_EXPERIMENTAL) {
@@ -681,7 +670,8 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
+ ((editorInfo.inputType & InputType.TYPE_TEXT_FLAG_CAP_WORDS) != 0));
}
if (ProductionFlag.IS_EXPERIMENTAL) {
- ResearchLogger.latinIME_onStartInputViewInternal(editorInfo, mPrefs);
+ final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
+ ResearchLogger.latinIME_onStartInputViewInternal(editorInfo, prefs);
}
if (InputAttributes.inPrivateImeOptions(null, NO_MICROPHONE_COMPAT, editorInfo)) {
Log.w(TAG, "Deprecated private IME option specified: "
@@ -713,7 +703,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
accessUtils.onStartInputViewInternal(mainKeyboardView, editorInfo, restarting);
}
- final boolean inputTypeChanged = !mCurrentSettings.isSameInputType(editorInfo);
+ final boolean inputTypeChanged = !mSettings.getCurrent().isSameInputType(editorInfo);
final boolean isDifferentTextField = !restarting || inputTypeChanged;
if (isDifferentTextField) {
mSubtypeSwitcher.updateParametersOnStartInputView();
@@ -743,11 +733,12 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
mainKeyboardView.closing();
loadSettings();
- if (mSuggest != null && mCurrentSettings.mCorrectionEnabled) {
- mSuggest.setAutoCorrectionThreshold(mCurrentSettings.mAutoCorrectionThreshold);
+ if (mSuggest != null && mSettings.getCurrent().mCorrectionEnabled) {
+ mSuggest.setAutoCorrectionThreshold(
+ mSettings.getCurrent().mAutoCorrectionThreshold);
}
- switcher.loadKeyboard(editorInfo, mCurrentSettings);
+ switcher.loadKeyboard(editorInfo, mSettings.getCurrent());
} else if (restarting) {
// TODO: Come up with a more comprehensive way to reset the keyboard layout when
// a keyboard layout set doesn't get reloaded in this method.
@@ -768,11 +759,12 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
mHandler.cancelDoubleSpacePeriodTimer();
mainKeyboardView.setMainDictionaryAvailability(mIsMainDictionaryAvailable);
- mainKeyboardView.setKeyPreviewPopupEnabled(mCurrentSettings.mKeyPreviewPopupOn,
- mCurrentSettings.mKeyPreviewPopupDismissDelay);
- mainKeyboardView.setGestureHandlingEnabledByUser(mCurrentSettings.mGestureInputEnabled);
- mainKeyboardView.setGesturePreviewMode(mCurrentSettings.mGesturePreviewTrailEnabled,
- mCurrentSettings.mGestureFloatingPreviewTextEnabled);
+ mainKeyboardView.setKeyPreviewPopupEnabled(mSettings.getCurrent().mKeyPreviewPopupOn,
+ mSettings.getCurrent().mKeyPreviewPopupDismissDelay);
+ mainKeyboardView.setGestureHandlingEnabledByUser(
+ mSettings.getCurrent().mGestureInputEnabled);
+ mainKeyboardView.setGesturePreviewMode(mSettings.getCurrent().mGesturePreviewTrailEnabled,
+ mSettings.getCurrent().mGestureFloatingPreviewTextEnabled);
// If we have a user dictionary addition in progress, we should check now if we should
// replace the previously committed string with the word that has actually been added
@@ -930,7 +922,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
*/
@Override
public void onExtractedTextClicked() {
- if (mCurrentSettings.isSuggestionsRequested(mDisplayOrientation)) return;
+ if (mSettings.getCurrent().isSuggestionsRequested(mDisplayOrientation)) return;
super.onExtractedTextClicked();
}
@@ -946,7 +938,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
*/
@Override
public void onExtractedCursorMovement(final int dx, final int dy) {
- if (mCurrentSettings.isSuggestionsRequested(mDisplayOrientation)) return;
+ if (mSettings.getCurrent().isSuggestionsRequested(mDisplayOrientation)) return;
super.onExtractedCursorMovement(dx, dy);
}
@@ -974,7 +966,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
}
}
}
- if (!mCurrentSettings.isApplicationSpecifiedCompletionsOn()) return;
+ if (!mSettings.getCurrent().isApplicationSpecifiedCompletionsOn()) return;
mApplicationSpecifiedCompletions = applicationSpecifiedCompletions;
if (applicationSpecifiedCompletions == null) {
clearSuggestionStrip();
@@ -1039,7 +1031,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
}
final int keyboardHeight = mainKeyboardView.getHeight();
final int suggestionsHeight = mSuggestionsContainer.getHeight();
- final int displayHeight = mResources.getDisplayMetrics().heightPixels;
+ final int displayHeight = getResources().getDisplayMetrics().heightPixels;
final Rect rect = new Rect();
mKeyPreviewBackingView.getWindowVisibleDisplayFrame(rect);
final int notificationBarHeight = rect.top;
@@ -1118,10 +1110,10 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
// the composing word, reset the last composed word, tell the inputconnection about it.
private void resetEntireInputState(final int newCursorPosition) {
resetComposingState(true /* alsoResetLastComposedWord */);
- if (mCurrentSettings.mBigramPredictionEnabled) {
+ if (mSettings.getCurrent().mBigramPredictionEnabled) {
clearSuggestionStrip();
} else {
- setSuggestionStrip(mCurrentSettings.mSuggestPuncList, false);
+ setSuggestionStrip(mSettings.getCurrent().mSuggestPuncList, false);
}
mConnection.resetCachesUponCursorMove(newCursorPosition);
}
@@ -1139,7 +1131,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
commitChosenWord(typedWord, LastComposedWord.COMMIT_TYPE_USER_TYPED_WORD,
separatorString);
if (ProductionFlag.IS_EXPERIMENTAL) {
- ResearchLogger.getInstance().onWordComplete(typedWord, Long.MAX_VALUE);
+ ResearchLogger.getInstance().onWordFinished(typedWord);
}
}
}
@@ -1147,7 +1139,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
// Called from the KeyboardSwitcher which needs to know auto caps state to display
// the right layout.
public int getCurrentAutoCapsState() {
- if (!mCurrentSettings.mAutoCap) return Constants.TextUtils.CAP_MODE_OFF;
+ if (!mSettings.getCurrent().mAutoCap) return Constants.TextUtils.CAP_MODE_OFF;
final EditorInfo ei = getCurrentInputEditorInfo();
if (ei == null) return Constants.TextUtils.CAP_MODE_OFF;
@@ -1179,16 +1171,15 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
final String text = lastTwo.charAt(1) + " ";
mConnection.commitText(text, 1);
if (ProductionFlag.IS_EXPERIMENTAL) {
- ResearchLogger.getInstance().onWordComplete(text, Long.MAX_VALUE);
- ResearchLogger.latinIME_swapSwapperAndSpace();
+ ResearchLogger.latinIME_swapSwapperAndSpace(text);
}
mKeyboardSwitcher.updateShiftState();
}
}
private boolean maybeDoubleSpacePeriod() {
- if (!mCurrentSettings.mCorrectionEnabled) return false;
- if (!mCurrentSettings.mUseDoubleSpacePeriod) return false;
+ if (!mSettings.getCurrent().mCorrectionEnabled) return false;
+ if (!mSettings.getCurrent().mUseDoubleSpacePeriod) return false;
if (!mHandler.isAcceptingDoubleSpacePeriod()) return false;
final CharSequence lastThree = mConnection.getTextBeforeCursor(3, 0);
if (lastThree != null && lastThree.length() == 3
@@ -1200,7 +1191,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
final String textToInsert = ". ";
mConnection.commitText(textToInsert, 1);
if (ProductionFlag.IS_EXPERIMENTAL) {
- ResearchLogger.getInstance().onWordComplete(textToInsert, Long.MAX_VALUE);
+ ResearchLogger.latinIME_maybeDoubleSpacePeriod(textToInsert);
}
mKeyboardSwitcher.updateShiftState();
return true;
@@ -1291,7 +1282,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
// TODO: Revise the language switch key behavior to make it much smarter and more reasonable.
private void handleLanguageSwitchKey() {
final IBinder token = getWindow().getWindow().getAttributes().token;
- if (mCurrentSettings.mIncludesOtherImesInLanguageSwitchList) {
+ if (mSettings.getCurrent().mIncludesOtherImesInLanguageSwitchList) {
mRichImm.switchToNextInputMethod(token, false /* onlyCurrentIme */);
return;
}
@@ -1393,7 +1384,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
break;
default:
mSpaceState = SPACE_STATE_NONE;
- if (mCurrentSettings.isWordSeparator(primaryCode)) {
+ if (mSettings.getCurrent().isWordSeparator(primaryCode)) {
didAutoCorrect = handleSeparator(primaryCode, x, y, spaceState);
} else {
if (SPACE_STATE_PHANTOM == spaceState) {
@@ -1449,7 +1440,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
}
mConnection.commitText(text, 1);
if (ProductionFlag.IS_EXPERIMENTAL) {
- ResearchLogger.getInstance().onWordComplete(text, Long.MAX_VALUE);
+ ResearchLogger.latinIME_onTextInput(text);
}
mConnection.endBatchEdit();
// Space state must be updated before calling updateShiftState
@@ -1491,8 +1482,8 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
// should usually be followed by a space, and it should be more readable.
if (Constants.NOT_A_CODE != codePointBeforeCursor
&& !Character.isWhitespace(codePointBeforeCursor)
- && !mCurrentSettings.isPhantomSpacePromotingSymbol(codePointBeforeCursor)
- && !mCurrentSettings.isWeakSpaceStripper(codePointBeforeCursor)) {
+ && !mSettings.getCurrent().isPhantomSpacePromotingSymbol(codePointBeforeCursor)
+ && !mSettings.getCurrent().isWeakSpaceStripper(codePointBeforeCursor)) {
mSpaceState = SPACE_STATE_PHANTOM;
}
}
@@ -1599,9 +1590,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
if (dismissGestureFloatingPreviewText) {
mainKeyboardView.dismissGestureFloatingPreviewText();
} else {
- final String batchInputText = suggestedWords.isEmpty()
- ? null : suggestedWords.getWord(0);
- mainKeyboardView.showGestureFloatingPreviewText(batchInputText);
+ mainKeyboardView.showGestureFloatingPreviewText(suggestedWords);
}
}
@@ -1710,7 +1699,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
}
if (SPACE_STATE_DOUBLE == spaceState) {
mHandler.cancelDoubleSpacePeriodTimer();
- if (mConnection.revertDoubleSpace()) {
+ if (mConnection.revertDoubleSpacePeriod()) {
// No need to reset mSpaceState, it has already be done (that's why we
// receive it as a parameter)
return;
@@ -1749,7 +1738,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
mConnection.deleteSurroundingText(1, 0);
}
}
- if (mCurrentSettings.isSuggestionsRequested(mDisplayOrientation)) {
+ if (mSettings.getCurrent().isSuggestionsRequested(mDisplayOrientation)) {
restartSuggestionsOnWordBeforeCursorIfAtEndOfWord();
}
}
@@ -1763,10 +1752,10 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
} else if ((SPACE_STATE_WEAK == spaceState
|| SPACE_STATE_SWAP_PUNCTUATION == spaceState)
&& isFromSuggestionStrip) {
- if (mCurrentSettings.isWeakSpaceSwapper(code)) {
+ if (mSettings.getCurrent().isWeakSpaceSwapper(code)) {
return true;
} else {
- if (mCurrentSettings.isWeakSpaceStripper(code)) {
+ if (mSettings.getCurrent().isWeakSpaceStripper(code)) {
mConnection.removeTrailingSpace();
}
return false;
@@ -1781,7 +1770,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
boolean isComposingWord = mWordComposer.isComposingWord();
if (SPACE_STATE_PHANTOM == spaceState &&
- !mCurrentSettings.isSymbolExcludedFromWordSeparators(primaryCode)) {
+ !mSettings.getCurrent().isSymbolExcludedFromWordSeparators(primaryCode)) {
if (isComposingWord) {
// Sanity check
throw new RuntimeException("Should not be composing here");
@@ -1793,9 +1782,9 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
// dozen milliseconds. Avoid calling it as much as possible, since we are on the UI
// thread here.
if (!isComposingWord && (isAlphabet(primaryCode)
- || mCurrentSettings.isSymbolExcludedFromWordSeparators(primaryCode))
- && mCurrentSettings.isSuggestionsRequested(mDisplayOrientation) &&
- !mConnection.isCursorTouchingWord(mCurrentSettings)) {
+ || mSettings.getCurrent().isSymbolExcludedFromWordSeparators(primaryCode))
+ && mSettings.getCurrent().isSuggestionsRequested(mDisplayOrientation) &&
+ !mConnection.isCursorTouchingWord(mSettings.getCurrent())) {
// Reset entirely the composing state anyway, then start composing a new word unless
// the character is a single quote. The idea here is, single quote is not a
// separator and it should be treated as a normal character, except in the first
@@ -1849,7 +1838,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
boolean didAutoCorrect = false;
// Handle separator
if (mWordComposer.isComposingWord()) {
- if (mCurrentSettings.mCorrectionEnabled) {
+ if (mSettings.getCurrent().mCorrectionEnabled) {
// TODO: maybe cache Strings in an <String> sparse array or something
commitCurrentAutoCorrection(new String(new int[]{primaryCode}, 0, 1));
didAutoCorrect = true;
@@ -1862,13 +1851,13 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
Constants.SUGGESTION_STRIP_COORDINATE == x);
if (SPACE_STATE_PHANTOM == spaceState &&
- mCurrentSettings.isPhantomSpacePromotingSymbol(primaryCode)) {
+ mSettings.getCurrent().isPhantomSpacePromotingSymbol(primaryCode)) {
promotePhantomSpace();
}
sendKeyCodePoint(primaryCode);
if (Constants.CODE_SPACE == primaryCode) {
- if (mCurrentSettings.isSuggestionsRequested(mDisplayOrientation)) {
+ if (mSettings.getCurrent().isSuggestionsRequested(mDisplayOrientation)) {
if (maybeDoubleSpacePeriod()) {
mSpaceState = SPACE_STATE_DOUBLE;
} else if (!isShowingPunctuationList()) {
@@ -1877,7 +1866,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
}
mHandler.startDoubleSpacePeriodTimer();
- if (!mConnection.isCursorTouchingWord(mCurrentSettings)) {
+ if (!mConnection.isCursorTouchingWord(mSettings.getCurrent())) {
mHandler.postUpdateSuggestionStrip();
}
} else {
@@ -1885,8 +1874,8 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
swapSwapperAndSpace();
mSpaceState = SPACE_STATE_SWAP_PUNCTUATION;
} else if (SPACE_STATE_PHANTOM == spaceState
- && !mCurrentSettings.isWeakSpaceStripper(primaryCode)
- && !mCurrentSettings.isPhantomSpacePromotingSymbol(primaryCode)) {
+ && !mSettings.getCurrent().isWeakSpaceStripper(primaryCode)
+ && !mSettings.getCurrent().isPhantomSpacePromotingSymbol(primaryCode)) {
// If we are in phantom space state, and the user presses a separator, we want to
// stay in phantom space state so that the next keypress has a chance to add the
// space. For example, if I type "Good dat", pick "day" from the suggestion strip
@@ -1933,7 +1922,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
@UsedForTesting
boolean isShowingPunctuationList() {
if (mSuggestionStripView == null) return false;
- return mCurrentSettings.mSuggestPuncList == mSuggestionStripView.getSuggestions();
+ return mSettings.getCurrent().mSuggestPuncList == mSuggestionStripView.getSuggestions();
}
private boolean isSuggestionsStripVisible() {
@@ -1941,11 +1930,11 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
return false;
if (mSuggestionStripView.isShowingAddToDictionaryHint())
return true;
- if (!mCurrentSettings.isSuggestionStripVisibleInOrientation(mDisplayOrientation))
+ if (!mSettings.getCurrent().isSuggestionStripVisibleInOrientation(mDisplayOrientation))
return false;
- if (mCurrentSettings.isApplicationSpecifiedCompletionsOn())
+ if (mSettings.getCurrent().isApplicationSpecifiedCompletionsOn())
return true;
- return mCurrentSettings.isSuggestionsRequested(mDisplayOrientation);
+ return mSettings.getCurrent().isSuggestionsRequested(mDisplayOrientation);
}
private void clearSuggestionStrip() {
@@ -1979,7 +1968,8 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
mHandler.cancelUpdateSuggestionStrip();
// Check if we have a suggestion engine attached.
- if (mSuggest == null || !mCurrentSettings.isSuggestionsRequested(mDisplayOrientation)) {
+ if (mSuggest == null
+ || !mSettings.getCurrent().isSuggestionsRequested(mDisplayOrientation)) {
if (mWordComposer.isComposingWord()) {
Log.w(TAG, "Called updateSuggestionsOrPredictions but suggestions were not "
+ "requested!");
@@ -1987,7 +1977,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
return;
}
- if (!mWordComposer.isComposingWord() && !mCurrentSettings.mBigramPredictionEnabled) {
+ if (!mWordComposer.isComposingWord() && !mSettings.getCurrent().mBigramPredictionEnabled) {
setPunctuationSuggestions();
return;
}
@@ -2008,10 +1998,10 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
// should just skip whitespace if any, so 1.
// TODO: this is slow (2-way IPC) - we should probably cache this instead.
final String prevWord =
- mConnection.getNthPreviousWord(mCurrentSettings.mWordSeparators,
+ mConnection.getNthPreviousWord(mSettings.getCurrent().mWordSeparators,
mWordComposer.isComposingWord() ? 2 : 1);
final SuggestedWords suggestedWords = mSuggest.getSuggestedWords(mWordComposer,
- prevWord, keyboard.getProximityInfo(), mCurrentSettings.mCorrectionEnabled,
+ prevWord, keyboard.getProximityInfo(), mSettings.getCurrent().mCorrectionEnabled,
sessionId);
return maybeRetrieveOlderSuggestions(typedWord, suggestedWords);
}
@@ -2036,7 +2026,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
private SuggestedWords getOlderSuggestions(final String typedWord) {
SuggestedWords previousSuggestions = mSuggestionStripView.getSuggestions();
- if (previousSuggestions == mCurrentSettings.mSuggestPuncList) {
+ if (previousSuggestions == mSettings.getCurrent().mSuggestPuncList) {
previousSuggestions = SuggestedWords.EMPTY;
}
if (typedWord == null) {
@@ -2087,12 +2077,11 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
if (ProductionFlag.IS_INTERNAL) {
Stats.onAutoCorrection(typedWord, autoCorrection, separatorString, mWordComposer);
}
- mExpectingUpdateSelection = true;
if (ProductionFlag.IS_EXPERIMENTAL) {
ResearchLogger.latinIme_commitCurrentAutoCorrection(typedWord, autoCorrection,
separatorString);
}
-
+ mExpectingUpdateSelection = true;
commitChosenWord(autoCorrection, LastComposedWord.COMMIT_TYPE_DECIDED_WORD,
separatorString);
if (!typedWord.equals(autoCorrection)) {
@@ -2135,13 +2124,13 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
// the current batch input text and there is no need for a phantom space.
&& !mWordComposer.isBatchMode()) {
int firstChar = Character.codePointAt(suggestion, 0);
- if ((!mCurrentSettings.isWeakSpaceStripper(firstChar))
- && (!mCurrentSettings.isWeakSpaceSwapper(firstChar))) {
+ if ((!mSettings.getCurrent().isWeakSpaceStripper(firstChar))
+ && (!mSettings.getCurrent().isWeakSpaceSwapper(firstChar))) {
promotePhantomSpace();
}
}
- if (mCurrentSettings.isApplicationSpecifiedCompletionsOn()
+ if (mSettings.getCurrent().isApplicationSpecifiedCompletionsOn()
&& mApplicationSpecifiedCompletions != null
&& index >= 0 && index < mApplicationSpecifiedCompletions.length) {
if (mSuggestionStripView != null) {
@@ -2186,7 +2175,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
}
if (showingAddToDictionaryHint && mIsUserDictionaryAvailable) {
mSuggestionStripView.showAddToDictionaryHint(
- suggestion, mCurrentSettings.mHintToSaveText);
+ suggestion, mSettings.getCurrent().mHintToSaveText);
} else {
// If we're not showing the "Touch again to save", then update the suggestion strip.
mHandler.postUpdateSuggestionStrip();
@@ -2212,10 +2201,10 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
}
private void setPunctuationSuggestions() {
- if (mCurrentSettings.mBigramPredictionEnabled) {
+ if (mSettings.getCurrent().mBigramPredictionEnabled) {
clearSuggestionStrip();
} else {
- setSuggestionStrip(mCurrentSettings.mSuggestPuncList, false);
+ setSuggestionStrip(mSettings.getCurrent().mSuggestPuncList, false);
}
setAutoCorrectionIndicator(false);
setSuggestionStripShown(isSuggestionsStripVisible());
@@ -2228,12 +2217,12 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
// If correction is not enabled, we don't add words to the user history dictionary.
// That's to avoid unintended additions in some sensitive fields, or fields that
// expect to receive non-words.
- if (!mCurrentSettings.mCorrectionEnabled) return null;
+ if (!mSettings.getCurrent().mCorrectionEnabled) return null;
final UserHistoryDictionary userHistoryDictionary = mUserHistoryDictionary;
if (userHistoryDictionary != null) {
final String prevWord
- = mConnection.getNthPreviousWord(mCurrentSettings.mWordSeparators, 2);
+ = mConnection.getNthPreviousWord(mSettings.getCurrent().mWordSeparators, 2);
final String secondWord;
if (mWordComposer.wasAutoCapitalized() && !mWordComposer.isMostlyCaps()) {
secondWord = suggestion.toLowerCase(mSubtypeSwitcher.getCurrentSubtypeLocale());
@@ -2256,7 +2245,8 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
* word, else do nothing.
*/
private void restartSuggestionsOnWordBeforeCursorIfAtEndOfWord() {
- final CharSequence word = mConnection.getWordBeforeCursorIfAtEndOfWord(mCurrentSettings);
+ final CharSequence word =
+ mConnection.getWordBeforeCursorIfAtEndOfWord(mSettings.getCurrent());
if (null != word) {
restartSuggestionsOnWordBeforeCursor(word);
}
@@ -2303,7 +2293,6 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
}
if (ProductionFlag.IS_EXPERIMENTAL) {
ResearchLogger.latinIME_revertCommit(committedWord, originallyTypedWord);
- ResearchLogger.getInstance().onWordComplete(originallyTypedWord, Long.MAX_VALUE);
}
// Don't restart suggestion yet. We'll restart if the user deletes the
// separator.
@@ -2314,14 +2303,14 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
// This essentially inserts a space, and that's it.
public void promotePhantomSpace() {
- if (mCurrentSettings.shouldInsertSpacesAutomatically()) {
+ if (mSettings.getCurrent().shouldInsertSpacesAutomatically()) {
sendKeyCodePoint(Constants.CODE_SPACE);
}
}
// Used by the RingCharBuffer
public boolean isWordSeparator(final int code) {
- return mCurrentSettings.isWordSeparator(code);
+ return mSettings.getCurrent().isWordSeparator(code);
}
// TODO: Make this private
@@ -2334,7 +2323,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
loadSettings();
if (mKeyboardSwitcher.getMainKeyboardView() != null) {
// Reload keyboard because the current language has been changed.
- mKeyboardSwitcher.loadKeyboard(getCurrentInputEditorInfo(), mCurrentSettings);
+ mKeyboardSwitcher.loadKeyboard(getCurrentInputEditorInfo(), mSettings.getCurrent());
}
// Since we just changed languages, we should re-evaluate suggestions with whatever word
// we are currently composing. If we are not composing anything, we may want to display
@@ -2495,7 +2484,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
.append("\nPackage : ").append(mTargetApplicationInfo.packageName)
.append("\nTarget app sdk version : ")
.append(mTargetApplicationInfo.targetSdkVersion)
- .append("\nAttributes : ").append(mCurrentSettings.getInputAttributesDebugString())
+ .append("\nAttributes : ").append(mSettings.getCurrent().mInputAttributes)
.append("\nContext : ").append(context);
throw new RuntimeException(s.toString());
}
@@ -2509,13 +2498,14 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
final Keyboard keyboard = mKeyboardSwitcher.getKeyboard();
final int keyboardMode = keyboard != null ? keyboard.mId.mMode : -1;
p.println(" Keyboard mode = " + keyboardMode);
+ final SettingsValues settingsValues = mSettings.getCurrent();
p.println(" mIsSuggestionsSuggestionsRequested = "
- + mCurrentSettings.isSuggestionsRequested(mDisplayOrientation));
- p.println(" mCorrectionEnabled=" + mCurrentSettings.mCorrectionEnabled);
+ + settingsValues.isSuggestionsRequested(mDisplayOrientation));
+ p.println(" mCorrectionEnabled=" + settingsValues.mCorrectionEnabled);
p.println(" isComposingWord=" + mWordComposer.isComposingWord());
- p.println(" mSoundOn=" + mCurrentSettings.mSoundOn);
- p.println(" mVibrateOn=" + mCurrentSettings.mVibrateOn);
- p.println(" mKeyPreviewPopupOn=" + mCurrentSettings.mKeyPreviewPopupOn);
- p.println(" inputAttributes=" + mCurrentSettings.getInputAttributesDebugString());
+ p.println(" mSoundOn=" + settingsValues.mSoundOn);
+ p.println(" mVibrateOn=" + settingsValues.mVibrateOn);
+ p.println(" mKeyPreviewPopupOn=" + settingsValues.mKeyPreviewPopupOn);
+ p.println(" inputAttributes=" + settingsValues.mInputAttributes);
}
}
diff --git a/java/src/com/android/inputmethod/latin/RichInputConnection.java b/java/src/com/android/inputmethod/latin/RichInputConnection.java
index 9cb24b54e..0d3ebacb1 100644
--- a/java/src/com/android/inputmethod/latin/RichInputConnection.java
+++ b/java/src/com/android/inputmethod/latin/RichInputConnection.java
@@ -643,7 +643,7 @@ public final class RichInputConnection {
return word;
}
- public boolean revertDoubleSpace() {
+ public boolean revertDoubleSpacePeriod() {
if (DEBUG_BATCH_NESTING) checkBatchEdit();
// Here we test whether we indeed have a period and a space before us. This should not
// be needed, but it's there just in case something went wrong.
@@ -660,7 +660,7 @@ public final class RichInputConnection {
final String doubleSpace = " ";
commitText(doubleSpace, 1);
if (ProductionFlag.IS_EXPERIMENTAL) {
- ResearchLogger.getInstance().onWordComplete(doubleSpace, Long.MAX_VALUE);
+ ResearchLogger.richInputConnection_revertDoubleSpacePeriod(doubleSpace);
}
return true;
}
@@ -685,7 +685,7 @@ public final class RichInputConnection {
final String text = " " + textBeforeCursor.subSequence(0, 1);
commitText(text, 1);
if (ProductionFlag.IS_EXPERIMENTAL) {
- ResearchLogger.getInstance().onWordComplete(text, Long.MAX_VALUE);
+ ResearchLogger.richInputConnection_revertSwapPunctuation(text);
}
return true;
}
diff --git a/java/src/com/android/inputmethod/latin/Settings.java b/java/src/com/android/inputmethod/latin/Settings.java
index 222adcb2e..1d9d85b47 100644
--- a/java/src/com/android/inputmethod/latin/Settings.java
+++ b/java/src/com/android/inputmethod/latin/Settings.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008 The Android Open Source Project
+ * 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
@@ -16,27 +16,16 @@
package com.android.inputmethod.latin;
-import android.app.backup.BackupManager;
import android.content.Context;
-import android.content.Intent;
import android.content.SharedPreferences;
import android.content.res.Resources;
-import android.media.AudioManager;
-import android.os.Bundle;
-import android.preference.CheckBoxPreference;
-import android.preference.ListPreference;
-import android.preference.Preference;
-import android.preference.Preference.OnPreferenceClickListener;
-import android.preference.PreferenceGroup;
-import android.preference.PreferenceScreen;
-import android.view.inputmethod.InputMethodSubtype;
+import android.preference.PreferenceManager;
-import com.android.inputmethod.latin.define.ProductionFlag;
-import com.android.inputmethodcommon.InputMethodSettingsFragment;
+import com.android.inputmethod.latin.LocaleUtils.RunInLocale;
-public final class Settings extends InputMethodSettingsFragment
- implements SharedPreferences.OnSharedPreferenceChangeListener {
+import java.util.Locale;
+public final class Settings implements SharedPreferences.OnSharedPreferenceChangeListener {
// In the same order as xml/prefs.xml
public static final String PREF_GENERAL_SETTINGS = "general_settings";
public static final String PREF_AUTO_CAP = "auto_cap";
@@ -77,338 +66,54 @@ public final class Settings extends InputMethodSettingsFragment
public static final String PREF_SELECTED_LANGUAGES = "selected_languages";
public static final String PREF_DEBUG_SETTINGS = "debug_settings";
- private PreferenceScreen mKeypressVibrationDurationSettingsPref;
- private PreferenceScreen mKeypressSoundVolumeSettingsPref;
- private ListPreference mVoicePreference;
- private ListPreference mShowCorrectionSuggestionsPreference;
- private ListPreference mAutoCorrectionThresholdPreference;
- private ListPreference mKeyPreviewPopupDismissDelay;
- // Use bigrams to predict the next word when there is no input for it yet
- private CheckBoxPreference mBigramPrediction;
- private Preference mDebugSettingsPreference;
+ private Resources mRes;
+ private SharedPreferences mPrefs;
+ private Locale mCurrentLocale;
+ private SettingsValues mSettingsValues;
- private static void setPreferenceEnabled(final Preference preference, final boolean enabled) {
- if (preference != null) {
- preference.setEnabled(enabled);
- }
- }
+ private static final Settings sInstance = new Settings();
- private void ensureConsistencyOfAutoCorrectionSettings() {
- final String autoCorrectionOff = getResources().getString(
- R.string.auto_correction_threshold_mode_index_off);
- final String currentSetting = mAutoCorrectionThresholdPreference.getValue();
- setPreferenceEnabled(mBigramPrediction, !currentSetting.equals(autoCorrectionOff));
+ public static Settings getInstance() {
+ return sInstance;
}
- @Override
- public void onCreate(final Bundle icicle) {
- super.onCreate(icicle);
- setInputMethodSettingsCategoryTitle(R.string.language_selection_title);
- setSubtypeEnablerTitle(R.string.select_language);
- addPreferencesFromResource(R.xml.prefs);
-
- final Resources res = getResources();
- final Context context = getActivity();
-
- // When we are called from the Settings application but we are not already running, the
- // {@link SubtypeLocale} class may not have been initialized. It is safe to call
- // {@link SubtypeLocale#init(Context)} multiple times.
- SubtypeLocale.init(context);
- mVoicePreference = (ListPreference) findPreference(PREF_VOICE_MODE);
- mShowCorrectionSuggestionsPreference =
- (ListPreference) findPreference(PREF_SHOW_SUGGESTIONS_SETTING);
- final SharedPreferences prefs = getPreferenceManager().getSharedPreferences();
- prefs.registerOnSharedPreferenceChangeListener(this);
-
- mAutoCorrectionThresholdPreference =
- (ListPreference) findPreference(PREF_AUTO_CORRECTION_THRESHOLD);
- mBigramPrediction = (CheckBoxPreference) findPreference(PREF_BIGRAM_PREDICTIONS);
- ensureConsistencyOfAutoCorrectionSettings();
-
- final PreferenceGroup generalSettings =
- (PreferenceGroup) findPreference(PREF_GENERAL_SETTINGS);
- final PreferenceGroup textCorrectionGroup =
- (PreferenceGroup) findPreference(PREF_CORRECTION_SETTINGS);
- final PreferenceGroup gestureTypingSettings =
- (PreferenceGroup) findPreference(PREF_GESTURE_SETTINGS);
- final PreferenceGroup miscSettings =
- (PreferenceGroup) findPreference(PREF_MISC_SETTINGS);
-
- mDebugSettingsPreference = findPreference(PREF_DEBUG_SETTINGS);
- if (mDebugSettingsPreference != null) {
- if (ProductionFlag.IS_INTERNAL) {
- final Intent debugSettingsIntent = new Intent(Intent.ACTION_MAIN);
- debugSettingsIntent.setClassName(
- context.getPackageName(), DebugSettingsActivity.class.getName());
- mDebugSettingsPreference.setIntent(debugSettingsIntent);
- } else {
- miscSettings.removePreference(mDebugSettingsPreference);
- }
- }
-
- final boolean showVoiceKeyOption = res.getBoolean(
- R.bool.config_enable_show_voice_key_option);
- if (!showVoiceKeyOption) {
- generalSettings.removePreference(mVoicePreference);
- }
-
- final PreferenceGroup advancedSettings =
- (PreferenceGroup) findPreference(PREF_ADVANCED_SETTINGS);
- if (!VibratorUtils.getInstance(context).hasVibrator()) {
- generalSettings.removePreference(findPreference(PREF_VIBRATE_ON));
- if (null != advancedSettings) { // Theoretically advancedSettings cannot be null
- advancedSettings.removePreference(findPreference(PREF_VIBRATION_DURATION_SETTINGS));
- }
- }
-
- final boolean showKeyPreviewPopupOption = res.getBoolean(
- R.bool.config_enable_show_popup_on_keypress_option);
- mKeyPreviewPopupDismissDelay =
- (ListPreference) findPreference(PREF_KEY_PREVIEW_POPUP_DISMISS_DELAY);
- if (!showKeyPreviewPopupOption) {
- generalSettings.removePreference(findPreference(PREF_POPUP_ON));
- if (null != advancedSettings) { // Theoretically advancedSettings cannot be null
- advancedSettings.removePreference(mKeyPreviewPopupDismissDelay);
- }
- } else {
- final String[] entries = new String[] {
- res.getString(R.string.key_preview_popup_dismiss_no_delay),
- res.getString(R.string.key_preview_popup_dismiss_default_delay),
- };
- final String popupDismissDelayDefaultValue = Integer.toString(res.getInteger(
- R.integer.config_key_preview_linger_timeout));
- mKeyPreviewPopupDismissDelay.setEntries(entries);
- mKeyPreviewPopupDismissDelay.setEntryValues(
- new String[] { "0", popupDismissDelayDefaultValue });
- if (null == mKeyPreviewPopupDismissDelay.getValue()) {
- mKeyPreviewPopupDismissDelay.setValue(popupDismissDelayDefaultValue);
- }
- setPreferenceEnabled(mKeyPreviewPopupDismissDelay,
- SettingsValues.isKeyPreviewPopupEnabled(prefs, res));
- }
-
- setPreferenceEnabled(findPreference(PREF_INCLUDE_OTHER_IMES_IN_LANGUAGE_SWITCH_LIST),
- SettingsValues.showsLanguageSwitchKey(prefs));
-
- final PreferenceScreen dictionaryLink =
- (PreferenceScreen) findPreference(PREF_CONFIGURE_DICTIONARIES_KEY);
- final Intent intent = dictionaryLink.getIntent();
-
- final int number = context.getPackageManager().queryIntentActivities(intent, 0).size();
- // TODO: The experimental version is not supported by the Dictionary Pack Service yet
- if (ProductionFlag.IS_EXPERIMENTAL || 0 >= number) {
- textCorrectionGroup.removePreference(dictionaryLink);
- }
-
- final boolean gestureInputEnabledByBuildConfig = res.getBoolean(
- R.bool.config_gesture_input_enabled_by_build_config);
- if (!gestureInputEnabledByBuildConfig) {
- getPreferenceScreen().removePreference(gestureTypingSettings);
- }
-
- mKeypressVibrationDurationSettingsPref =
- (PreferenceScreen) findPreference(PREF_VIBRATION_DURATION_SETTINGS);
- if (mKeypressVibrationDurationSettingsPref != null) {
- mKeypressVibrationDurationSettingsPref.setOnPreferenceClickListener(
- new OnPreferenceClickListener() {
- @Override
- public boolean onPreferenceClick(Preference arg0) {
- showKeypressVibrationDurationSettingsDialog();
- return true;
- }
- });
- mKeypressVibrationDurationSettingsPref.setSummary(
- res.getString(R.string.settings_keypress_vibration_duration,
- SettingsValues.getCurrentVibrationDuration(prefs, res)));
- }
+ public static void init(final Context context) {
+ sInstance.onCreate(context);
+ }
- mKeypressSoundVolumeSettingsPref =
- (PreferenceScreen) findPreference(PREF_KEYPRESS_SOUND_VOLUME);
- if (mKeypressSoundVolumeSettingsPref != null) {
- mKeypressSoundVolumeSettingsPref.setOnPreferenceClickListener(
- new OnPreferenceClickListener() {
- @Override
- public boolean onPreferenceClick(Preference arg0) {
- showKeypressSoundVolumeSettingDialog();
- return true;
- }
- });
- mKeypressSoundVolumeSettingsPref.setSummary(String.valueOf(
- getCurrentKeyPressSoundVolumePercent(prefs, res)));
- }
- refreshEnablingsOfKeypressSoundAndVibrationSettings(prefs, res);
+ private Settings() {
+ // Intentional empty constructor for singleton.
}
- @Override
- public void onResume() {
- super.onResume();
- final boolean isShortcutImeEnabled = SubtypeSwitcher.getInstance().isShortcutImeEnabled();
- if (isShortcutImeEnabled) {
- updateVoiceModeSummary();
- } else {
- getPreferenceScreen().removePreference(mVoicePreference);
- }
- updateShowCorrectionSuggestionsSummary();
- updateKeyPreviewPopupDelaySummary();
- updateCustomInputStylesSummary();
+ private void onCreate(final Context context) {
+ mRes = context.getResources();
+ mPrefs = PreferenceManager.getDefaultSharedPreferences(context);
+ mPrefs.registerOnSharedPreferenceChangeListener(this);
}
- @Override
public void onDestroy() {
- getPreferenceManager().getSharedPreferences().unregisterOnSharedPreferenceChangeListener(
- this);
- super.onDestroy();
+ mPrefs.unregisterOnSharedPreferenceChangeListener(this);
}
@Override
public void onSharedPreferenceChanged(final SharedPreferences prefs, final String key) {
- (new BackupManager(getActivity())).dataChanged();
- if (key.equals(PREF_POPUP_ON)) {
- setPreferenceEnabled(findPreference(PREF_KEY_PREVIEW_POPUP_DISMISS_DELAY),
- prefs.getBoolean(PREF_POPUP_ON, true));
- } else if (key.equals(PREF_SHOW_LANGUAGE_SWITCH_KEY)) {
- setPreferenceEnabled(findPreference(PREF_INCLUDE_OTHER_IMES_IN_LANGUAGE_SWITCH_LIST),
- SettingsValues.showsLanguageSwitchKey(prefs));
- } else if (key.equals(PREF_GESTURE_INPUT)) {
- final boolean gestureInputEnabledByConfig = getResources().getBoolean(
- R.bool.config_gesture_input_enabled_by_build_config);
- if (gestureInputEnabledByConfig) {
- final boolean gestureInputEnabledByUser = prefs.getBoolean(
- PREF_GESTURE_INPUT, true);
- setPreferenceEnabled(findPreference(PREF_GESTURE_PREVIEW_TRAIL),
- gestureInputEnabledByUser);
- setPreferenceEnabled(findPreference(PREF_GESTURE_FLOATING_PREVIEW_TEXT),
- gestureInputEnabledByUser);
- }
- }
- ensureConsistencyOfAutoCorrectionSettings();
- updateVoiceModeSummary();
- updateShowCorrectionSuggestionsSummary();
- updateKeyPreviewPopupDelaySummary();
- refreshEnablingsOfKeypressSoundAndVibrationSettings(prefs, getResources());
+ loadSettings(mCurrentLocale, mSettingsValues.mInputAttributes);
}
- private void updateShowCorrectionSuggestionsSummary() {
- mShowCorrectionSuggestionsPreference.setSummary(
- getResources().getStringArray(R.array.prefs_suggestion_visibilities)
- [mShowCorrectionSuggestionsPreference.findIndexOfValue(
- mShowCorrectionSuggestionsPreference.getValue())]);
- }
-
- private void updateCustomInputStylesSummary() {
- final PreferenceScreen customInputStyles =
- (PreferenceScreen)findPreference(PREF_CUSTOM_INPUT_STYLES);
- final SharedPreferences prefs = getPreferenceManager().getSharedPreferences();
- final Resources res = getResources();
- final String prefSubtype = SettingsValues.getPrefAdditionalSubtypes(prefs, res);
- final InputMethodSubtype[] subtypes =
- AdditionalSubtype.createAdditionalSubtypesArray(prefSubtype);
- final StringBuilder styles = new StringBuilder();
- for (final InputMethodSubtype subtype : subtypes) {
- if (styles.length() > 0) styles.append(", ");
- styles.append(SubtypeLocale.getSubtypeDisplayName(subtype, res));
- }
- customInputStyles.setSummary(styles);
- }
-
- private void updateKeyPreviewPopupDelaySummary() {
- final ListPreference lp = mKeyPreviewPopupDismissDelay;
- final CharSequence[] entries = lp.getEntries();
- if (entries == null || entries.length <= 0) return;
- lp.setSummary(entries[lp.findIndexOfValue(lp.getValue())]);
- }
-
- private void updateVoiceModeSummary() {
- mVoicePreference.setSummary(
- getResources().getStringArray(R.array.voice_input_modes_summary)
- [mVoicePreference.findIndexOfValue(mVoicePreference.getValue())]);
- }
-
- private void refreshEnablingsOfKeypressSoundAndVibrationSettings(
- final SharedPreferences sp, final Resources res) {
- if (mKeypressVibrationDurationSettingsPref != null) {
- final boolean hasVibratorHardware = VibratorUtils.getInstance(getActivity())
- .hasVibrator();
- final boolean vibrateOnByUser = sp.getBoolean(Settings.PREF_VIBRATE_ON,
- res.getBoolean(R.bool.config_default_vibration_enabled));
- setPreferenceEnabled(mKeypressVibrationDurationSettingsPref,
- hasVibratorHardware && vibrateOnByUser);
- }
-
- if (mKeypressSoundVolumeSettingsPref != null) {
- final boolean soundOn = sp.getBoolean(Settings.PREF_SOUND_ON,
- res.getBoolean(R.bool.config_default_sound_enabled));
- setPreferenceEnabled(mKeypressSoundVolumeSettingsPref, soundOn);
- }
- }
-
- private void showKeypressVibrationDurationSettingsDialog() {
- final SharedPreferences sp = getPreferenceManager().getSharedPreferences();
- final Context context = getActivity();
- final PreferenceScreen settingsPref = mKeypressVibrationDurationSettingsPref;
- final SeekBarDialog.Listener listener = new SeekBarDialog.Adapter() {
+ public void loadSettings(final Locale locale, final InputAttributes inputAttributes) {
+ mCurrentLocale = locale;
+ final SharedPreferences prefs = mPrefs;
+ final RunInLocale<SettingsValues> job = new RunInLocale<SettingsValues>() {
@Override
- public void onPositiveButtonClick(final SeekBarDialog dialog) {
- final int ms = dialog.getValue();
- sp.edit().putInt(Settings.PREF_VIBRATION_DURATION_SETTINGS, ms).apply();
- if (settingsPref != null) {
- settingsPref.setSummary(dialog.getValueText());
- }
- }
-
- @Override
- public void onStopTrackingTouch(final SeekBarDialog dialog) {
- final int ms = dialog.getValue();
- VibratorUtils.getInstance(context).vibrate(ms);
+ protected SettingsValues job(final Resources res) {
+ return new SettingsValues(prefs, res, inputAttributes);
}
};
- final int currentMs = SettingsValues.getCurrentVibrationDuration(sp, getResources());
- final SeekBarDialog.Builder builder = new SeekBarDialog.Builder(context);
- builder.setTitle(R.string.prefs_keypress_vibration_duration_settings)
- .setListener(listener)
- .setMaxValue(AudioAndHapticFeedbackManager.MAX_KEYPRESS_VIBRATION_DURATION)
- .setValueFromat(R.string.settings_keypress_vibration_duration)
- .setValue(currentMs)
- .create()
- .show();
- }
-
- private static final int PERCENT_INT = 100;
- private static final float PERCENT_FLOAT = 100.0f;
-
- private static int getCurrentKeyPressSoundVolumePercent(final SharedPreferences sp,
- final Resources res) {
- return (int)(SettingsValues.getCurrentKeypressSoundVolume(sp, res) * PERCENT_FLOAT);
+ mSettingsValues = job.runInLocale(mRes, locale);
}
- private void showKeypressSoundVolumeSettingDialog() {
- final SharedPreferences sp = getPreferenceManager().getSharedPreferences();
- final Context context = getActivity();
- final AudioManager am = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
- final PreferenceScreen settingsPref = mKeypressSoundVolumeSettingsPref;
- final SeekBarDialog.Listener listener = new SeekBarDialog.Adapter() {
- @Override
- public void onPositiveButtonClick(final SeekBarDialog dialog) {
- final float volume = dialog.getValue() / PERCENT_FLOAT;
- sp.edit().putFloat(Settings.PREF_KEYPRESS_SOUND_VOLUME, volume).apply();
- if (settingsPref != null) {
- settingsPref.setSummary(dialog.getValueText());
- }
- }
-
- @Override
- public void onStopTrackingTouch(final SeekBarDialog dialog) {
- final float volume = dialog.getValue() / PERCENT_FLOAT;
- am.playSoundEffect(AudioManager.FX_KEYPRESS_STANDARD, volume);
- }
- };
- final SeekBarDialog.Builder builder = new SeekBarDialog.Builder(context);
- final int currentVolumeInt = getCurrentKeyPressSoundVolumePercent(sp, getResources());
- builder.setTitle(R.string.prefs_keypress_sound_volume_settings)
- .setListener(listener)
- .setMaxValue(PERCENT_INT)
- .setValue(currentVolumeInt)
- .create()
- .show();
+ // TODO: Remove this method and add proxy method to SettingsValues.
+ public SettingsValues getCurrent() {
+ return mSettingsValues;
}
}
diff --git a/java/src/com/android/inputmethod/latin/SettingsActivity.java b/java/src/com/android/inputmethod/latin/SettingsActivity.java
index 0d3c8ebb7..3aeb10113 100644
--- a/java/src/com/android/inputmethod/latin/SettingsActivity.java
+++ b/java/src/com/android/inputmethod/latin/SettingsActivity.java
@@ -20,7 +20,7 @@ import android.content.Intent;
import android.preference.PreferenceActivity;
public final class SettingsActivity extends PreferenceActivity {
- private static final String DEFAULT_FRAGMENT = Settings.class.getName();
+ private static final String DEFAULT_FRAGMENT = SettingsFragment.class.getName();
@Override
public Intent getIntent() {
diff --git a/java/src/com/android/inputmethod/latin/SettingsFragment.java b/java/src/com/android/inputmethod/latin/SettingsFragment.java
new file mode 100644
index 000000000..a2980bfa2
--- /dev/null
+++ b/java/src/com/android/inputmethod/latin/SettingsFragment.java
@@ -0,0 +1,375 @@
+/*
+ * Copyright (C) 2008 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.app.backup.BackupManager;
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.content.res.Resources;
+import android.media.AudioManager;
+import android.os.Bundle;
+import android.preference.CheckBoxPreference;
+import android.preference.ListPreference;
+import android.preference.Preference;
+import android.preference.Preference.OnPreferenceClickListener;
+import android.preference.PreferenceGroup;
+import android.preference.PreferenceScreen;
+import android.view.inputmethod.InputMethodSubtype;
+
+import com.android.inputmethod.latin.define.ProductionFlag;
+import com.android.inputmethodcommon.InputMethodSettingsFragment;
+
+public final class SettingsFragment extends InputMethodSettingsFragment
+ implements SharedPreferences.OnSharedPreferenceChangeListener {
+ private PreferenceScreen mKeypressVibrationDurationSettingsPref;
+ private PreferenceScreen mKeypressSoundVolumeSettingsPref;
+ private ListPreference mVoicePreference;
+ private ListPreference mShowCorrectionSuggestionsPreference;
+ private ListPreference mAutoCorrectionThresholdPreference;
+ private ListPreference mKeyPreviewPopupDismissDelay;
+ // Use bigrams to predict the next word when there is no input for it yet
+ private CheckBoxPreference mBigramPrediction;
+ private Preference mDebugSettingsPreference;
+
+ private void setPreferenceEnabled(final String preferenceKey, final boolean enabled) {
+ final Preference preference = findPreference(preferenceKey);
+ if (preference != null) {
+ preference.setEnabled(enabled);
+ }
+ }
+
+ private void ensureConsistencyOfAutoCorrectionSettings() {
+ final String autoCorrectionOff = getResources().getString(
+ R.string.auto_correction_threshold_mode_index_off);
+ final String currentSetting = mAutoCorrectionThresholdPreference.getValue();
+ mBigramPrediction.setEnabled(!currentSetting.equals(autoCorrectionOff));
+ }
+
+ @Override
+ public void onCreate(final Bundle icicle) {
+ super.onCreate(icicle);
+ setInputMethodSettingsCategoryTitle(R.string.language_selection_title);
+ setSubtypeEnablerTitle(R.string.select_language);
+ addPreferencesFromResource(R.xml.prefs);
+
+ final Resources res = getResources();
+ final Context context = getActivity();
+
+ // When we are called from the Settings application but we are not already running, the
+ // {@link SubtypeLocale} class may not have been initialized. It is safe to call
+ // {@link SubtypeLocale#init(Context)} multiple times.
+ SubtypeLocale.init(context);
+ mVoicePreference = (ListPreference) findPreference(Settings.PREF_VOICE_MODE);
+ mShowCorrectionSuggestionsPreference =
+ (ListPreference) findPreference(Settings.PREF_SHOW_SUGGESTIONS_SETTING);
+ final SharedPreferences prefs = getPreferenceManager().getSharedPreferences();
+ prefs.registerOnSharedPreferenceChangeListener(this);
+
+ mAutoCorrectionThresholdPreference =
+ (ListPreference) findPreference(Settings.PREF_AUTO_CORRECTION_THRESHOLD);
+ mBigramPrediction = (CheckBoxPreference) findPreference(Settings.PREF_BIGRAM_PREDICTIONS);
+ ensureConsistencyOfAutoCorrectionSettings();
+
+ final PreferenceGroup generalSettings =
+ (PreferenceGroup) findPreference(Settings.PREF_GENERAL_SETTINGS);
+ final PreferenceGroup textCorrectionGroup =
+ (PreferenceGroup) findPreference(Settings.PREF_CORRECTION_SETTINGS);
+ final PreferenceGroup gestureTypingSettings =
+ (PreferenceGroup) findPreference(Settings.PREF_GESTURE_SETTINGS);
+ final PreferenceGroup miscSettings =
+ (PreferenceGroup) findPreference(Settings.PREF_MISC_SETTINGS);
+
+ mDebugSettingsPreference = findPreference(Settings.PREF_DEBUG_SETTINGS);
+ if (mDebugSettingsPreference != null) {
+ if (ProductionFlag.IS_INTERNAL) {
+ final Intent debugSettingsIntent = new Intent(Intent.ACTION_MAIN);
+ debugSettingsIntent.setClassName(
+ context.getPackageName(), DebugSettingsActivity.class.getName());
+ mDebugSettingsPreference.setIntent(debugSettingsIntent);
+ } else {
+ miscSettings.removePreference(mDebugSettingsPreference);
+ }
+ }
+
+ final boolean showVoiceKeyOption = res.getBoolean(
+ R.bool.config_enable_show_voice_key_option);
+ if (!showVoiceKeyOption) {
+ generalSettings.removePreference(mVoicePreference);
+ }
+
+ final PreferenceGroup advancedSettings =
+ (PreferenceGroup) findPreference(Settings.PREF_ADVANCED_SETTINGS);
+ if (!AudioAndHapticFeedbackManager.getInstance().hasVibrator()) {
+ generalSettings.removePreference(findPreference(Settings.PREF_VIBRATE_ON));
+ if (null != advancedSettings) { // Theoretically advancedSettings cannot be null
+ advancedSettings.removePreference(
+ findPreference(Settings.PREF_VIBRATION_DURATION_SETTINGS));
+ }
+ }
+
+ final boolean showKeyPreviewPopupOption = res.getBoolean(
+ R.bool.config_enable_show_popup_on_keypress_option);
+ mKeyPreviewPopupDismissDelay =
+ (ListPreference) findPreference(Settings.PREF_KEY_PREVIEW_POPUP_DISMISS_DELAY);
+ if (!showKeyPreviewPopupOption) {
+ generalSettings.removePreference(findPreference(Settings.PREF_POPUP_ON));
+ if (null != advancedSettings) { // Theoretically advancedSettings cannot be null
+ advancedSettings.removePreference(mKeyPreviewPopupDismissDelay);
+ }
+ } else {
+ final String[] entries = new String[] {
+ res.getString(R.string.key_preview_popup_dismiss_no_delay),
+ res.getString(R.string.key_preview_popup_dismiss_default_delay),
+ };
+ final String popupDismissDelayDefaultValue = Integer.toString(res.getInteger(
+ R.integer.config_key_preview_linger_timeout));
+ mKeyPreviewPopupDismissDelay.setEntries(entries);
+ mKeyPreviewPopupDismissDelay.setEntryValues(
+ new String[] { "0", popupDismissDelayDefaultValue });
+ if (null == mKeyPreviewPopupDismissDelay.getValue()) {
+ mKeyPreviewPopupDismissDelay.setValue(popupDismissDelayDefaultValue);
+ }
+ mKeyPreviewPopupDismissDelay.setEnabled(
+ SettingsValues.isKeyPreviewPopupEnabled(prefs, res));
+ }
+
+ setPreferenceEnabled(Settings.PREF_INCLUDE_OTHER_IMES_IN_LANGUAGE_SWITCH_LIST,
+ SettingsValues.showsLanguageSwitchKey(prefs));
+
+ final PreferenceScreen dictionaryLink =
+ (PreferenceScreen) findPreference(Settings.PREF_CONFIGURE_DICTIONARIES_KEY);
+ final Intent intent = dictionaryLink.getIntent();
+
+ final int number = context.getPackageManager().queryIntentActivities(intent, 0).size();
+ // TODO: The experimental version is not supported by the Dictionary Pack Service yet
+ if (ProductionFlag.IS_EXPERIMENTAL || 0 >= number) {
+ textCorrectionGroup.removePreference(dictionaryLink);
+ }
+
+ final boolean gestureInputEnabledByBuildConfig = res.getBoolean(
+ R.bool.config_gesture_input_enabled_by_build_config);
+ if (!gestureInputEnabledByBuildConfig) {
+ getPreferenceScreen().removePreference(gestureTypingSettings);
+ }
+
+ mKeypressVibrationDurationSettingsPref =
+ (PreferenceScreen) findPreference(Settings.PREF_VIBRATION_DURATION_SETTINGS);
+ if (mKeypressVibrationDurationSettingsPref != null) {
+ mKeypressVibrationDurationSettingsPref.setOnPreferenceClickListener(
+ new OnPreferenceClickListener() {
+ @Override
+ public boolean onPreferenceClick(Preference arg0) {
+ showKeypressVibrationDurationSettingsDialog();
+ return true;
+ }
+ });
+ mKeypressVibrationDurationSettingsPref.setSummary(
+ res.getString(R.string.settings_keypress_vibration_duration,
+ SettingsValues.getCurrentVibrationDuration(prefs, res)));
+ }
+
+ mKeypressSoundVolumeSettingsPref =
+ (PreferenceScreen) findPreference(Settings.PREF_KEYPRESS_SOUND_VOLUME);
+ if (mKeypressSoundVolumeSettingsPref != null) {
+ mKeypressSoundVolumeSettingsPref.setOnPreferenceClickListener(
+ new OnPreferenceClickListener() {
+ @Override
+ public boolean onPreferenceClick(Preference arg0) {
+ showKeypressSoundVolumeSettingDialog();
+ return true;
+ }
+ });
+ mKeypressSoundVolumeSettingsPref.setSummary(String.valueOf(
+ getCurrentKeyPressSoundVolumePercent(prefs, res)));
+ }
+ refreshEnablingsOfKeypressSoundAndVibrationSettings(prefs, res);
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ final boolean isShortcutImeEnabled = SubtypeSwitcher.getInstance().isShortcutImeEnabled();
+ if (isShortcutImeEnabled) {
+ updateVoiceModeSummary();
+ } else {
+ getPreferenceScreen().removePreference(mVoicePreference);
+ }
+ updateShowCorrectionSuggestionsSummary();
+ updateKeyPreviewPopupDelaySummary();
+ updateCustomInputStylesSummary();
+ }
+
+ @Override
+ public void onDestroy() {
+ getPreferenceManager().getSharedPreferences().unregisterOnSharedPreferenceChangeListener(
+ this);
+ super.onDestroy();
+ }
+
+ @Override
+ public void onSharedPreferenceChanged(final SharedPreferences prefs, final String key) {
+ (new BackupManager(getActivity())).dataChanged();
+ if (key.equals(Settings.PREF_POPUP_ON)) {
+ setPreferenceEnabled(Settings.PREF_KEY_PREVIEW_POPUP_DISMISS_DELAY,
+ prefs.getBoolean(Settings.PREF_POPUP_ON, true));
+ } else if (key.equals(Settings.PREF_SHOW_LANGUAGE_SWITCH_KEY)) {
+ setPreferenceEnabled(Settings.PREF_INCLUDE_OTHER_IMES_IN_LANGUAGE_SWITCH_LIST,
+ SettingsValues.showsLanguageSwitchKey(prefs));
+ } else if (key.equals(Settings.PREF_GESTURE_INPUT)) {
+ final boolean gestureInputEnabledByConfig = getResources().getBoolean(
+ R.bool.config_gesture_input_enabled_by_build_config);
+ if (gestureInputEnabledByConfig) {
+ final boolean gestureInputEnabledByUser = prefs.getBoolean(
+ Settings.PREF_GESTURE_INPUT, true);
+ setPreferenceEnabled(Settings.PREF_GESTURE_PREVIEW_TRAIL,
+ gestureInputEnabledByUser);
+ setPreferenceEnabled(Settings.PREF_GESTURE_FLOATING_PREVIEW_TEXT,
+ gestureInputEnabledByUser);
+ }
+ }
+ ensureConsistencyOfAutoCorrectionSettings();
+ updateVoiceModeSummary();
+ updateShowCorrectionSuggestionsSummary();
+ updateKeyPreviewPopupDelaySummary();
+ refreshEnablingsOfKeypressSoundAndVibrationSettings(prefs, getResources());
+ }
+
+ private void updateShowCorrectionSuggestionsSummary() {
+ mShowCorrectionSuggestionsPreference.setSummary(
+ getResources().getStringArray(R.array.prefs_suggestion_visibilities)
+ [mShowCorrectionSuggestionsPreference.findIndexOfValue(
+ mShowCorrectionSuggestionsPreference.getValue())]);
+ }
+
+ private void updateCustomInputStylesSummary() {
+ final PreferenceScreen customInputStyles =
+ (PreferenceScreen)findPreference(Settings.PREF_CUSTOM_INPUT_STYLES);
+ final SharedPreferences prefs = getPreferenceManager().getSharedPreferences();
+ final Resources res = getResources();
+ final String prefSubtype = SettingsValues.getPrefAdditionalSubtypes(prefs, res);
+ final InputMethodSubtype[] subtypes =
+ AdditionalSubtype.createAdditionalSubtypesArray(prefSubtype);
+ final StringBuilder styles = new StringBuilder();
+ for (final InputMethodSubtype subtype : subtypes) {
+ if (styles.length() > 0) styles.append(", ");
+ styles.append(SubtypeLocale.getSubtypeDisplayName(subtype, res));
+ }
+ customInputStyles.setSummary(styles);
+ }
+
+ private void updateKeyPreviewPopupDelaySummary() {
+ final ListPreference lp = mKeyPreviewPopupDismissDelay;
+ final CharSequence[] entries = lp.getEntries();
+ if (entries == null || entries.length <= 0) return;
+ lp.setSummary(entries[lp.findIndexOfValue(lp.getValue())]);
+ }
+
+ private void updateVoiceModeSummary() {
+ mVoicePreference.setSummary(
+ getResources().getStringArray(R.array.voice_input_modes_summary)
+ [mVoicePreference.findIndexOfValue(mVoicePreference.getValue())]);
+ }
+
+ private void refreshEnablingsOfKeypressSoundAndVibrationSettings(
+ final SharedPreferences sp, final Resources res) {
+ if (mKeypressVibrationDurationSettingsPref != null) {
+ final boolean hasVibratorHardware =
+ AudioAndHapticFeedbackManager.getInstance().hasVibrator();
+ final boolean vibrateOnByUser = sp.getBoolean(Settings.PREF_VIBRATE_ON,
+ res.getBoolean(R.bool.config_default_vibration_enabled));
+ mKeypressVibrationDurationSettingsPref.setEnabled(
+ hasVibratorHardware && vibrateOnByUser);
+ }
+
+ if (mKeypressSoundVolumeSettingsPref != null) {
+ final boolean soundOn = sp.getBoolean(Settings.PREF_SOUND_ON,
+ res.getBoolean(R.bool.config_default_sound_enabled));
+ mKeypressSoundVolumeSettingsPref.setEnabled(soundOn);
+ }
+ }
+
+ private void showKeypressVibrationDurationSettingsDialog() {
+ final SharedPreferences sp = getPreferenceManager().getSharedPreferences();
+ final Context context = getActivity();
+ final PreferenceScreen settingsPref = mKeypressVibrationDurationSettingsPref;
+ final SeekBarDialog.Listener listener = new SeekBarDialog.Adapter() {
+ @Override
+ public void onPositiveButtonClick(final SeekBarDialog dialog) {
+ final int ms = dialog.getValue();
+ sp.edit().putInt(Settings.PREF_VIBRATION_DURATION_SETTINGS, ms).apply();
+ if (settingsPref != null) {
+ settingsPref.setSummary(dialog.getValueText());
+ }
+ }
+
+ @Override
+ public void onStopTrackingTouch(final SeekBarDialog dialog) {
+ final int ms = dialog.getValue();
+ AudioAndHapticFeedbackManager.getInstance().vibrate(ms);
+ }
+ };
+ final int currentMs = SettingsValues.getCurrentVibrationDuration(sp, getResources());
+ final SeekBarDialog.Builder builder = new SeekBarDialog.Builder(context);
+ builder.setTitle(R.string.prefs_keypress_vibration_duration_settings)
+ .setListener(listener)
+ .setMaxValue(AudioAndHapticFeedbackManager.MAX_KEYPRESS_VIBRATION_DURATION)
+ .setValueFromat(R.string.settings_keypress_vibration_duration)
+ .setValue(currentMs)
+ .create()
+ .show();
+ }
+
+ private static final int PERCENT_INT = 100;
+ private static final float PERCENT_FLOAT = 100.0f;
+
+ private static int getCurrentKeyPressSoundVolumePercent(final SharedPreferences sp,
+ final Resources res) {
+ return (int)(SettingsValues.getCurrentKeypressSoundVolume(sp, res) * PERCENT_FLOAT);
+ }
+
+ private void showKeypressSoundVolumeSettingDialog() {
+ final SharedPreferences sp = getPreferenceManager().getSharedPreferences();
+ final Context context = getActivity();
+ final AudioManager am = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
+ final PreferenceScreen settingsPref = mKeypressSoundVolumeSettingsPref;
+ final SeekBarDialog.Listener listener = new SeekBarDialog.Adapter() {
+ @Override
+ public void onPositiveButtonClick(final SeekBarDialog dialog) {
+ final float volume = dialog.getValue() / PERCENT_FLOAT;
+ sp.edit().putFloat(Settings.PREF_KEYPRESS_SOUND_VOLUME, volume).apply();
+ if (settingsPref != null) {
+ settingsPref.setSummary(dialog.getValueText());
+ }
+ }
+
+ @Override
+ public void onStopTrackingTouch(final SeekBarDialog dialog) {
+ final float volume = dialog.getValue() / PERCENT_FLOAT;
+ am.playSoundEffect(AudioManager.FX_KEYPRESS_STANDARD, volume);
+ }
+ };
+ final SeekBarDialog.Builder builder = new SeekBarDialog.Builder(context);
+ final int currentVolumeInt = getCurrentKeyPressSoundVolumePercent(sp, getResources());
+ builder.setTitle(R.string.prefs_keypress_sound_volume_settings)
+ .setListener(listener)
+ .setMaxValue(PERCENT_INT)
+ .setValue(currentVolumeInt)
+ .create()
+ .show();
+ }
+}
diff --git a/java/src/com/android/inputmethod/latin/SettingsValues.java b/java/src/com/android/inputmethod/latin/SettingsValues.java
index 157684437..39406621c 100644
--- a/java/src/com/android/inputmethod/latin/SettingsValues.java
+++ b/java/src/com/android/inputmethod/latin/SettingsValues.java
@@ -16,7 +16,6 @@
package com.android.inputmethod.latin;
-import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.content.res.Resources;
@@ -83,7 +82,7 @@ public final class SettingsValues {
public final boolean mGestureFloatingPreviewTextEnabled;
// From the input box
- private final InputAttributes mInputAttributes;
+ public final InputAttributes mInputAttributes;
// Deduced settings
public final int mKeypressVibrationDuration;
@@ -96,10 +95,8 @@ public final class SettingsValues {
private final boolean mVoiceKeyEnabled;
private final boolean mVoiceKeyOnMain;
- public SettingsValues(final SharedPreferences prefs, final InputAttributes inputAttributes,
- final Context context) {
- final Resources res = context.getResources();
-
+ public SettingsValues(final SharedPreferences prefs, final Resources res,
+ final InputAttributes inputAttributes) {
// Get the resources
mDelayUpdateOldSuggestions = res.getInteger(R.integer.config_delay_update_old_suggestions);
mWeakSpaceStrippers = res.getString(R.string.weak_space_stripping_symbols);
@@ -121,7 +118,7 @@ public final class SettingsValues {
res.getString(R.string.symbols_excluded_from_word_separators);
mWordSeparators = createWordSeparators(mWeakSpaceStrippers, mWeakSpaceSwappers,
mSymbolsExcludedFromWordSeparators, res);
- mHintToSaveText = context.getText(R.string.hint_add_to_dictionary);
+ mHintToSaveText = res.getText(R.string.hint_add_to_dictionary);
// Store the input attributes
if (null == inputAttributes) {
@@ -132,7 +129,7 @@ public final class SettingsValues {
// Get the settings preferences
mAutoCap = prefs.getBoolean(Settings.PREF_AUTO_CAP, true);
- mVibrateOn = isVibrateOn(context, prefs, res);
+ mVibrateOn = isVibrateOn(prefs, res);
mSoundOn = prefs.getBoolean(Settings.PREF_SOUND_ON,
res.getBoolean(R.bool.config_default_sound_enabled));
mKeyPreviewPopupOn = isKeyPreviewPopupEnabled(prefs, res);
@@ -214,9 +211,8 @@ public final class SettingsValues {
throw new RuntimeException("Bug: visibility string is not configured correctly");
}
- private static boolean isVibrateOn(final Context context, final SharedPreferences prefs,
- final Resources res) {
- final boolean hasVibrator = VibratorUtils.getInstance(context).hasVibrator();
+ private static boolean isVibrateOn(final SharedPreferences prefs, final Resources res) {
+ final boolean hasVibrator = AudioAndHapticFeedbackManager.getInstance().hasVibrator();
return hasVibrator && prefs.getBoolean(Settings.PREF_VIBRATE_ON,
res.getBoolean(R.bool.config_default_vibration_enabled));
}
@@ -273,6 +269,7 @@ public final class SettingsValues {
return !currentAutoCorrectionSetting.equals(autoCorrectionOff);
}
+ // TODO: Clean up and move public helper methods to Settings class.
// Public to access from KeyboardSwitcher. Should it have access to some
// process-global instance instead?
public static boolean isKeyPreviewPopupEnabled(final SharedPreferences prefs,
@@ -423,9 +420,4 @@ public final class SettingsValues {
public boolean isSameInputType(final EditorInfo editorInfo) {
return mInputAttributes.isSameInputType(editorInfo);
}
-
- // For debug.
- public String getInputAttributesDebugString() {
- return mInputAttributes.toString();
- }
}
diff --git a/java/src/com/android/inputmethod/latin/UserBinaryDictionary.java b/java/src/com/android/inputmethod/latin/UserBinaryDictionary.java
index 6cb39426d..a16784985 100644
--- a/java/src/com/android/inputmethod/latin/UserBinaryDictionary.java
+++ b/java/src/com/android/inputmethod/latin/UserBinaryDictionary.java
@@ -31,14 +31,15 @@ import android.text.TextUtils;
import java.util.Arrays;
/**
- * An expandable dictionary that stores the words in the user unigram dictionary.
- *
- * Largely a copy of UserDictionary, will replace that class in the future.
+ * An expandable dictionary that stores the words in the user dictionary provider into a binary
+ * dictionary file to use it from native code.
*/
public class UserBinaryDictionary extends ExpandableBinaryDictionary {
// The user dictionary provider uses an empty string to mean "all languages".
private static final String USER_DICTIONARY_ALL_LANGUAGES = "";
+ private static final int HISTORICAL_DEFAULT_USER_DICTIONARY_FREQUENCY = 250;
+ private static final int LATINIME_DEFAULT_USER_DICTIONARY_FREQUENCY = 160;
// TODO: use Words.SHORTCUT when we target JellyBean or above
final static String SHORTCUT = "shortcut";
@@ -233,6 +234,19 @@ public class UserBinaryDictionary extends ExpandableBinaryDictionary {
mContext.startActivity(intent);
}
+ private int scaleFrequencyFromDefaultToLatinIme(final int defaultFrequency) {
+ // The default frequency for the user dictionary is 250 for historical reasons.
+ // Latin IME considers a good value for the default user dictionary frequency
+ // is about 160 considering the scale we use. So we are scaling down the values.
+ if (defaultFrequency > Integer.MAX_VALUE / LATINIME_DEFAULT_USER_DICTIONARY_FREQUENCY) {
+ return (defaultFrequency / HISTORICAL_DEFAULT_USER_DICTIONARY_FREQUENCY)
+ * LATINIME_DEFAULT_USER_DICTIONARY_FREQUENCY;
+ } else {
+ return (defaultFrequency * LATINIME_DEFAULT_USER_DICTIONARY_FREQUENCY)
+ / HISTORICAL_DEFAULT_USER_DICTIONARY_FREQUENCY;
+ }
+ }
+
private void addWords(final Cursor cursor) {
final boolean hasShortcutColumn = Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN;
clearFusionDictionary();
@@ -245,12 +259,13 @@ public class UserBinaryDictionary extends ExpandableBinaryDictionary {
final String word = cursor.getString(indexWord);
final String shortcut = hasShortcutColumn ? cursor.getString(indexShortcut) : null;
final int frequency = cursor.getInt(indexFrequency);
+ final int adjustedFrequency = scaleFrequencyFromDefaultToLatinIme(frequency);
// Safeguard against adding really long words.
if (word.length() < MAX_WORD_LENGTH) {
- super.addWord(word, null, frequency);
+ super.addWord(word, null, adjustedFrequency);
}
if (null != shortcut && shortcut.length() < MAX_WORD_LENGTH) {
- super.addWord(shortcut, word, frequency);
+ super.addWord(shortcut, word, adjustedFrequency);
}
cursor.moveToNext();
}
diff --git a/java/src/com/android/inputmethod/latin/VibratorUtils.java b/java/src/com/android/inputmethod/latin/VibratorUtils.java
deleted file mode 100644
index b6696cec0..000000000
--- a/java/src/com/android/inputmethod/latin/VibratorUtils.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.inputmethod.latin;
-
-import android.content.Context;
-import android.os.Vibrator;
-
-public final class VibratorUtils {
- private static final VibratorUtils sInstance = new VibratorUtils();
- private Vibrator mVibrator;
-
- private VibratorUtils() {
- // This utility class is not publicly instantiable.
- }
-
- public static VibratorUtils getInstance(Context context) {
- if (sInstance.mVibrator == null) {
- sInstance.mVibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
- }
- return sInstance;
- }
-
- public boolean hasVibrator() {
- if (mVibrator == null) {
- return false;
- }
- return mVibrator.hasVibrator();
- }
-
- public void vibrate(long milliseconds) {
- if (mVibrator == null) {
- return;
- }
- mVibrator.vibrate(milliseconds);
- }
-}
diff --git a/java/src/com/android/inputmethod/research/FixedLogBuffer.java b/java/src/com/android/inputmethod/research/FixedLogBuffer.java
new file mode 100644
index 000000000..f3302d856
--- /dev/null
+++ b/java/src/com/android/inputmethod/research/FixedLogBuffer.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.android.inputmethod.research;
+
+import java.util.LinkedList;
+
+/**
+ * A buffer that holds a fixed number of LogUnits.
+ *
+ * LogUnits are added in and shifted out in temporal order. Only a subset of the LogUnits are
+ * actual words; the other LogUnits do not count toward the word limit. Once the buffer reaches
+ * capacity, adding another LogUnit that is a word evicts the oldest LogUnits out one at a time to
+ * stay under the capacity limit.
+ *
+ * This variant of a LogBuffer has a limited memory footprint because of its limited size. This
+ * makes it useful, for example, for recording a window of the user's most recent actions in case
+ * they want to report an observed error that they do not know how to reproduce.
+ */
+public class FixedLogBuffer extends LogBuffer {
+ /* package for test */ int mWordCapacity;
+ // The number of members of mLogUnits that are actual words.
+ private int mNumActualWords;
+
+ /**
+ * Create a new LogBuffer that can hold a fixed number of LogUnits that are words (and
+ * unlimited number of non-word LogUnits), and that outputs its result to a researchLog.
+ *
+ * @param wordCapacity maximum number of words
+ */
+ public FixedLogBuffer(final int wordCapacity) {
+ super();
+ if (wordCapacity <= 0) {
+ throw new IllegalArgumentException("wordCapacity must be 1 or greater.");
+ }
+ mWordCapacity = wordCapacity;
+ mNumActualWords = 0;
+ }
+
+ protected int getNumActualWords() {
+ return mNumActualWords;
+ }
+
+ /**
+ * Adds a new LogUnit to the front of the LIFO queue, evicting existing LogUnit's
+ * (oldest first) if word capacity is reached.
+ */
+ @Override
+ public void shiftIn(final LogUnit newLogUnit) {
+ if (newLogUnit.getWord() == null) {
+ // This LogUnit isn't a word, so it doesn't count toward the word-limit.
+ super.shiftIn(newLogUnit);
+ return;
+ }
+ if (mNumActualWords == mWordCapacity) {
+ shiftOutThroughFirstWord();
+ }
+ super.shiftIn(newLogUnit);
+ mNumActualWords++; // Must be a word, or we wouldn't be here.
+ }
+
+ private void shiftOutThroughFirstWord() {
+ final LinkedList<LogUnit> logUnits = getLogUnits();
+ while (!logUnits.isEmpty()) {
+ final LogUnit logUnit = logUnits.removeFirst();
+ onShiftOut(logUnit);
+ if (logUnit.hasWord()) {
+ // Successfully shifted out a word-containing LogUnit and made space for the new
+ // LogUnit.
+ mNumActualWords--;
+ break;
+ }
+ }
+ }
+
+ /**
+ * Removes all LogUnits from the buffer without calling onShiftOut().
+ */
+ @Override
+ public void clear() {
+ super.clear();
+ mNumActualWords = 0;
+ }
+
+ /**
+ * Called when a LogUnit is removed from the LogBuffer as a result of a shiftIn. LogUnits are
+ * removed in the order entered. This method is not called when shiftOut is called directly.
+ *
+ * Base class does nothing; subclasses may override if they want to record non-privacy sensitive
+ * events that fall off the end.
+ */
+ protected void onShiftOut(final LogUnit logUnit) {
+ }
+
+ /**
+ * Called to deliberately remove the oldest LogUnit. Usually called when draining the
+ * LogBuffer.
+ */
+ @Override
+ public LogUnit shiftOut() {
+ if (isEmpty()) {
+ return null;
+ }
+ final LogUnit logUnit = super.shiftOut();
+ if (logUnit.hasWord()) {
+ mNumActualWords--;
+ }
+ return logUnit;
+ }
+}
diff --git a/java/src/com/android/inputmethod/research/JsonUtils.java b/java/src/com/android/inputmethod/research/JsonUtils.java
index cb331d7f9..1dfd01c69 100644
--- a/java/src/com/android/inputmethod/research/JsonUtils.java
+++ b/java/src/com/android/inputmethod/research/JsonUtils.java
@@ -18,6 +18,7 @@ package com.android.inputmethod.research;
import android.content.SharedPreferences;
import android.util.JsonWriter;
+import android.view.MotionEvent;
import android.view.inputmethod.CompletionInfo;
import com.android.inputmethod.keyboard.Key;
@@ -27,6 +28,9 @@ import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
import java.io.IOException;
import java.util.Map;
+/**
+ * Routines for mapping classes and variables to JSON representations for logging.
+ */
/* package */ class JsonUtils {
private JsonUtils() {
// This utility class is not publicly instantiable.
@@ -100,4 +104,54 @@ import java.util.Map;
jsonWriter.endArray();
jsonWriter.endObject();
}
+
+ /* package */ static void writeJson(final MotionEvent me, final JsonWriter jsonWriter)
+ throws IOException {
+ jsonWriter.beginObject();
+ jsonWriter.name("pointerIds");
+ jsonWriter.beginArray();
+ final int pointerCount = me.getPointerCount();
+ for (int index = 0; index < pointerCount; index++) {
+ jsonWriter.value(me.getPointerId(index));
+ }
+ jsonWriter.endArray();
+
+ jsonWriter.name("xyt");
+ jsonWriter.beginArray();
+ final int historicalSize = me.getHistorySize();
+ for (int index = 0; index < historicalSize; index++) {
+ jsonWriter.beginObject();
+ jsonWriter.name("t");
+ jsonWriter.value(me.getHistoricalEventTime(index));
+ jsonWriter.name("d");
+ jsonWriter.beginArray();
+ for (int pointerIndex = 0; pointerIndex < pointerCount; pointerIndex++) {
+ jsonWriter.beginObject();
+ jsonWriter.name("x");
+ jsonWriter.value(me.getHistoricalX(pointerIndex, index));
+ jsonWriter.name("y");
+ jsonWriter.value(me.getHistoricalY(pointerIndex, index));
+ jsonWriter.endObject();
+ }
+ jsonWriter.endArray();
+ jsonWriter.endObject();
+ }
+ jsonWriter.beginObject();
+ jsonWriter.name("t");
+ jsonWriter.value(me.getEventTime());
+ jsonWriter.name("d");
+ jsonWriter.beginArray();
+ for (int pointerIndex = 0; pointerIndex < pointerCount; pointerIndex++) {
+ jsonWriter.beginObject();
+ jsonWriter.name("x");
+ jsonWriter.value(me.getX(pointerIndex));
+ jsonWriter.name("y");
+ jsonWriter.value(me.getY(pointerIndex));
+ jsonWriter.endObject();
+ }
+ jsonWriter.endArray();
+ jsonWriter.endObject();
+ jsonWriter.endArray();
+ jsonWriter.endObject();
+ }
}
diff --git a/java/src/com/android/inputmethod/research/LogBuffer.java b/java/src/com/android/inputmethod/research/LogBuffer.java
index a3c3e89de..14e8d08a2 100644
--- a/java/src/com/android/inputmethod/research/LogBuffer.java
+++ b/java/src/com/android/inputmethod/research/LogBuffer.java
@@ -16,102 +16,44 @@
package com.android.inputmethod.research;
-import com.android.inputmethod.latin.CollectionUtils;
-
import java.util.LinkedList;
/**
- * A buffer that holds a fixed number of LogUnits.
+ * Maintain a FIFO queue of LogUnits.
*
- * LogUnits are added in and shifted out in temporal order. Only a subset of the LogUnits are
- * actual words; the other LogUnits do not count toward the word limit. Once the buffer reaches
- * capacity, adding another LogUnit that is a word evicts the oldest LogUnits out one at a time to
- * stay under the capacity limit.
+ * This class provides an unbounded queue. This is useful when the user is aware that their actions
+ * are being recorded, such as when they are trying to reproduce a bug. In this case, there should
+ * not be artificial restrictions on how many events that can be saved.
*/
public class LogBuffer {
- protected final LinkedList<LogUnit> mLogUnits;
- /* package for test */ int mWordCapacity;
- // The number of members of mLogUnits that are actual words.
- protected int mNumActualWords;
-
- /**
- * Create a new LogBuffer that can hold a fixed number of LogUnits that are words (and
- * unlimited number of non-word LogUnits), and that outputs its result to a researchLog.
- *
- * @param wordCapacity maximum number of words
- */
- LogBuffer(final int wordCapacity) {
- if (wordCapacity <= 0) {
- throw new IllegalArgumentException("wordCapacity must be 1 or greater.");
- }
- mLogUnits = CollectionUtils.newLinkedList();
- mWordCapacity = wordCapacity;
- mNumActualWords = 0;
- }
+ // TODO: Gracefully handle situations in which this LogBuffer is consuming too much memory.
+ // This may happen, for example, if the user has forgotten that data is being logged.
+ private final LinkedList<LogUnit> mLogUnits;
- /**
- * Adds a new LogUnit to the front of the LIFO queue, evicting existing LogUnit's
- * (oldest first) if word capacity is reached.
- */
- public void shiftIn(LogUnit newLogUnit) {
- if (newLogUnit.getWord() == null) {
- // This LogUnit isn't a word, so it doesn't count toward the word-limit.
- mLogUnits.add(newLogUnit);
- return;
- }
- if (mNumActualWords == mWordCapacity) {
- shiftOutThroughFirstWord();
- }
- mLogUnits.add(newLogUnit);
- mNumActualWords++; // Must be a word, or we wouldn't be here.
+ public LogBuffer() {
+ mLogUnits = new LinkedList<LogUnit>();
}
- private void shiftOutThroughFirstWord() {
- while (!mLogUnits.isEmpty()) {
- final LogUnit logUnit = mLogUnits.removeFirst();
- onShiftOut(logUnit);
- if (logUnit.hasWord()) {
- // Successfully shifted out a word-containing LogUnit and made space for the new
- // LogUnit.
- mNumActualWords--;
- break;
- }
- }
+ protected LinkedList<LogUnit> getLogUnits() {
+ return mLogUnits;
}
- /**
- * Removes all LogUnits from the buffer without calling onShiftOut().
- */
public void clear() {
mLogUnits.clear();
- mNumActualWords = 0;
}
- /**
- * Called when a LogUnit is removed from the LogBuffer as a result of a shiftIn. LogUnits are
- * removed in the order entered. This method is not called when shiftOut is called directly.
- *
- * Base class does nothing; subclasses may override.
- */
- protected void onShiftOut(LogUnit logUnit) {
+ public void shiftIn(final LogUnit logUnit) {
+ mLogUnits.add(logUnit);
+ }
+
+ public boolean isEmpty() {
+ return mLogUnits.isEmpty();
}
- /**
- * Called to deliberately remove the oldest LogUnit. Usually called when draining the
- * LogBuffer.
- */
public LogUnit shiftOut() {
- if (mLogUnits.isEmpty()) {
+ if (isEmpty()) {
return null;
}
- final LogUnit logUnit = mLogUnits.removeFirst();
- if (logUnit.hasWord()) {
- mNumActualWords--;
- }
- return logUnit;
- }
-
- public boolean isEmpty() {
- return mLogUnits.isEmpty();
+ return mLogUnits.removeFirst();
}
}
diff --git a/java/src/com/android/inputmethod/research/LogUnit.java b/java/src/com/android/inputmethod/research/LogUnit.java
index 27c4027de..bcb144f5f 100644
--- a/java/src/com/android/inputmethod/research/LogUnit.java
+++ b/java/src/com/android/inputmethod/research/LogUnit.java
@@ -19,6 +19,7 @@ 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;
@@ -189,6 +190,8 @@ import java.util.Map;
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 {
diff --git a/java/src/com/android/inputmethod/research/MainLogBuffer.java b/java/src/com/android/inputmethod/research/MainLogBuffer.java
index 0185e5fc0..bec21d7e0 100644
--- a/java/src/com/android/inputmethod/research/MainLogBuffer.java
+++ b/java/src/com/android/inputmethod/research/MainLogBuffer.java
@@ -22,15 +22,24 @@ import com.android.inputmethod.latin.Dictionary;
import com.android.inputmethod.latin.Suggest;
import com.android.inputmethod.latin.define.ProductionFlag;
+import java.util.LinkedList;
import java.util.Random;
-public class MainLogBuffer extends LogBuffer {
+/**
+ * Provide a log buffer of fixed length that enforces privacy restrictions.
+ *
+ * The privacy restrictions include making sure that no numbers are logged, that all logged words
+ * are in the dictionary, and that words are recorded infrequently enough that the user's meaning
+ * cannot be easily determined.
+ */
+public class MainLogBuffer extends FixedLogBuffer {
private static final String TAG = MainLogBuffer.class.getSimpleName();
private static final boolean DEBUG = false && ProductionFlag.IS_EXPERIMENTAL_DEBUG;
// The size of the n-grams logged. E.g. N_GRAM_SIZE = 2 means to sample bigrams.
private static final int N_GRAM_SIZE = 2;
- // The number of words between n-grams to omit from the log.
+ // The number of words between n-grams to omit from the log. If debugging, record 50% of all
+ // words. Otherwise, only record 10%.
private static final int DEFAULT_NUMBER_OF_WORDS_BETWEEN_SAMPLES =
ProductionFlag.IS_EXPERIMENTAL_DEBUG ? 2 : 18;
@@ -56,7 +65,7 @@ public class MainLogBuffer extends LogBuffer {
mWordsUntilSafeToSample = random.nextInt(mMinWordPeriod);
}
- public void setSuggest(Suggest suggest) {
+ public void setSuggest(final Suggest suggest) {
mSuggest = suggest;
}
@@ -108,9 +117,10 @@ public class MainLogBuffer extends LogBuffer {
}
// Check each word in the buffer. If any word poses a privacy threat, we cannot upload the
// complete buffer contents in detail.
- final int length = mLogUnits.size();
+ final LinkedList<LogUnit> logUnits = getLogUnits();
+ final int length = logUnits.size();
for (int i = 0; i < length; i++) {
- final LogUnit logUnit = mLogUnits.get(i);
+ final LogUnit logUnit = logUnits.get(i);
final String word = logUnit.getWord();
if (word == null) {
// Digits outside words are a privacy threat.
@@ -133,7 +143,7 @@ public class MainLogBuffer extends LogBuffer {
}
@Override
- protected void onShiftOut(LogUnit logUnit) {
+ protected void onShiftOut(final LogUnit logUnit) {
if (mResearchLog != null) {
mResearchLog.publish(logUnit, false /* isIncludingPrivateData */);
}
diff --git a/java/src/com/android/inputmethod/research/ResearchLogger.java b/java/src/com/android/inputmethod/research/ResearchLogger.java
index 709746ee3..b1484e696 100644
--- a/java/src/com/android/inputmethod/research/ResearchLogger.java
+++ b/java/src/com/android/inputmethod/research/ResearchLogger.java
@@ -154,6 +154,11 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
private LogUnit mCurrentLogUnit = new LogUnit();
+ // Gestured or tapped words may be committed after the gesture of the next word has started.
+ // To ensure that the gesture data of the next word is not associated with the previous word,
+ // thereby leaking private data, we store the time of the down event that started the second
+ // gesture, and when committing the earlier word, split the LogUnit.
+ private long mSavedDownEventTime;
private ResearchLogger() {
mStatistics = Statistics.getInstance();
}
@@ -377,7 +382,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
mFeedbackLog = new ResearchLog(createLogFile(mFilesDir));
// LogBuffer is one more than FEEDBACK_WORD_BUFFER_SIZE, because it must also hold
// the feedback LogUnit itself.
- mFeedbackLogBuffer = new LogBuffer(FEEDBACK_WORD_BUFFER_SIZE + 1);
+ mFeedbackLogBuffer = new FixedLogBuffer(FEEDBACK_WORD_BUFFER_SIZE + 1);
}
}
@@ -638,7 +643,6 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
mMainKeyboardView.invalidateAllKeys();
}
-
public void paintIndicator(KeyboardView view, Paint paint, Canvas canvas, int width,
int height) {
// TODO: Reimplement using a keyboard background image specific to the ResearchLogger
@@ -741,9 +745,15 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
return false;
}
+ /**
+ * Commit the portion of mCurrentLogUnit before maxTime as a worded logUnit.
+ *
+ * After this operation completes, mCurrentLogUnit will hold any logStatements that happened
+ * after maxTime.
+ */
private static final LogStatement LOGSTATEMENT_COMMIT_RECORD_SPLIT_WORDS =
new LogStatement("recordSplitWords", true, false);
- public void onWordComplete(final String word, final long maxTime) {
+ /* package for test */ void commitCurrentLogUnitAsWord(final String word, final long maxTime) {
final Dictionary dictionary = getDictionary();
if (word != null && word.length() > 0 && hasLetters(word)) {
mCurrentLogUnit.setWord(word);
@@ -757,6 +767,11 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
mCurrentLogUnit = newLogUnit;
}
+ public void onWordFinished(final String word) {
+ commitCurrentLogUnitAsWord(word, mSavedDownEventTime);
+ mSavedDownEventTime = Long.MAX_VALUE;
+ }
+
private static int scrubDigitFromCodePoint(int codePoint) {
return Character.isDigit(codePoint) ? DIGIT_REPLACEMENT_CODEPOINT : codePoint;
}
@@ -880,8 +895,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
*
*/
private static final LogStatement LOGSTATEMENT_MAIN_KEYBOARD_VIEW_PROCESS_MOTION_EVENT =
- new LogStatement("MainKeyboardViewProcessMotionEvent", true, false, "action",
- "eventTime", "id", "x", "y", "size", "pressure");
+ new LogStatement("MotionEvent", true, false, "action", "MotionEvent");
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) {
@@ -896,10 +910,14 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
case MotionEvent.ACTION_OUTSIDE: actionString = "OUTSIDE"; break;
default: actionString = "ACTION_" + action; break;
}
- final float size = me.getSize(index);
- final float pressure = me.getPressure(index);
- getInstance().enqueueEvent(LOGSTATEMENT_MAIN_KEYBOARD_VIEW_PROCESS_MOTION_EVENT,
- actionString, eventTime, id, x, y, size, pressure);
+ final ResearchLogger researchLogger = getInstance();
+ researchLogger.enqueueEvent(LOGSTATEMENT_MAIN_KEYBOARD_VIEW_PROCESS_MOTION_EVENT,
+ actionString, MotionEvent.obtain(me));
+ if (action == MotionEvent.ACTION_DOWN) {
+ // Subtract 1 from eventTime so the down event is included in the later
+ // LogUnit, not the earlier (the test is for inequality).
+ researchLogger.mSavedDownEventTime = eventTime - 1;
+ }
}
}
@@ -1038,6 +1056,16 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
}
/**
+ * Log a call to LatinIME.onTextInput().
+ *
+ * SystemResponse: Raw text is added to the TextView.
+ */
+ public static void latinIME_onTextInput(final String text) {
+ final ResearchLogger researchLogger = getInstance();
+ researchLogger.commitCurrentLogUnitAsWord(text, Long.MAX_VALUE);
+ }
+
+ /**
* Log a call to LatinIME.pickSuggestionManually().
*
* UserAction: The user has chosen a specific word from the suggestion strip.
@@ -1053,7 +1081,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
scrubDigitsFromString(replacedWord), index,
suggestion == null ? null : scrubbedWord, Constants.SUGGESTION_STRIP_COORDINATE,
Constants.SUGGESTION_STRIP_COORDINATE);
- researchLogger.onWordComplete(scrubbedWord, Long.MAX_VALUE);
+ researchLogger.commitCurrentLogUnitAsWord(scrubbedWord, Long.MAX_VALUE);
researchLogger.mStatistics.recordManualSuggestion();
}
@@ -1069,7 +1097,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
final ResearchLogger researchLogger = getInstance();
researchLogger.enqueueEvent(LOGSTATEMENT_LATINIME_PUNCTUATIONSUGGESTION, index, suggestion,
Constants.SUGGESTION_STRIP_COORDINATE, Constants.SUGGESTION_STRIP_COORDINATE);
- researchLogger.onWordComplete(suggestion, Long.MAX_VALUE);
+ researchLogger.commitCurrentLogUnitAsWord(suggestion, Long.MAX_VALUE);
}
/**
@@ -1098,8 +1126,20 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
*/
private static final LogStatement LOGSTATEMENT_LATINIME_SWAPSWAPPERANDSPACE =
new LogStatement("LatinIMESwapSwapperAndSpace", false, false);
- public static void latinIME_swapSwapperAndSpace() {
- getInstance().enqueueEvent(LOGSTATEMENT_LATINIME_SWAPSWAPPERANDSPACE);
+ public static void latinIME_swapSwapperAndSpace(final String text) {
+ final ResearchLogger researchLogger = getInstance();
+ researchLogger.commitCurrentLogUnitAsWord(text, Long.MAX_VALUE);
+ researchLogger.enqueueEvent(LOGSTATEMENT_LATINIME_SWAPSWAPPERANDSPACE);
+ }
+
+ /**
+ * Log a call to LatinIME.maybeDoubleSpacePeriod().
+ *
+ * SystemResponse: Two spaces have been replaced by period space.
+ */
+ public static void latinIME_maybeDoubleSpacePeriod(final String text) {
+ final ResearchLogger researchLogger = getInstance();
+ researchLogger.commitCurrentLogUnitAsWord(text, Long.MAX_VALUE);
}
/**
@@ -1156,6 +1196,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
researchLogger.enqueueEvent(LOGSTATEMENT_LATINIME_REVERTCOMMIT, committedWord,
originallyTypedWord);
researchLogger.mStatistics.recordRevertCommit();
+ researchLogger.commitCurrentLogUnitAsWord(originallyTypedWord, Long.MAX_VALUE);
}
/**
@@ -1250,6 +1291,26 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
}
/**
+ * Log a call to RichInputConnection.revertDoubleSpacePeriod().
+ *
+ * SystemResponse: The IME has reverted ". ", which had previously replaced two typed spaces.
+ */
+ public static void richInputConnection_revertDoubleSpacePeriod(final String doubleSpace) {
+ final ResearchLogger researchLogger = getInstance();
+ researchLogger.commitCurrentLogUnitAsWord(doubleSpace, Long.MAX_VALUE);
+ }
+
+ /**
+ * Log a call to RichInputConnection.revertSwapPunctuation().
+ *
+ * SystemResponse: The IME has reverted a punctuation swap.
+ */
+ public static void richInputConnection_revertSwapPunctuation(final String text) {
+ final ResearchLogger researchLogger = getInstance();
+ researchLogger.commitCurrentLogUnitAsWord(text, Long.MAX_VALUE);
+ }
+
+ /**
* Log a call to LatinIME.commitCurrentAutoCorrection().
*
* SystemResponse: The IME has committed an auto-correction. An auto-correction changes the raw
@@ -1265,7 +1326,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
final ResearchLogger researchLogger = getInstance();
researchLogger.enqueueEvent(LOGSTATEMENT_LATINIME_COMMITCURRENTAUTOCORRECTION,
scrubbedTypedWord, scrubbedAutoCorrection, separatorString);
- researchLogger.onWordComplete(scrubbedAutoCorrection, Long.MAX_VALUE);
+ researchLogger.commitCurrentLogUnitAsWord(scrubbedAutoCorrection, Long.MAX_VALUE);
}
private boolean isExpectingCommitText = false;
@@ -1284,7 +1345,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
final ResearchLogger researchLogger = getInstance();
final String scrubbedWord = scrubDigitsFromString(committedWord.toString());
researchLogger.enqueueEvent(LOGSTATEMENT_LATINIME_COMMIT_PARTIAL_TEXT);
- researchLogger.onWordComplete(scrubbedWord, lastTimestampOfWordData);
+ researchLogger.commitCurrentLogUnitAsWord(scrubbedWord, lastTimestampOfWordData);
researchLogger.mStatistics.recordSplitWords();
}
@@ -1303,7 +1364,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
if (!researchLogger.isExpectingCommitText) {
researchLogger.enqueueEvent(LOGSTATEMENT_RICHINPUTCONNECTIONCOMMITTEXT,
newCursorPosition);
- researchLogger.onWordComplete(scrubbedWord, Long.MAX_VALUE);
+ researchLogger.commitCurrentLogUnitAsWord(scrubbedWord, Long.MAX_VALUE);
}
researchLogger.isExpectingCommitText = false;
}