aboutsummaryrefslogtreecommitdiffstats
path: root/java/src
diff options
context:
space:
mode:
Diffstat (limited to 'java/src')
-rw-r--r--java/src/com/android/inputmethod/dictionarypack/DictionarySettingsFragment.java31
-rw-r--r--java/src/com/android/inputmethod/dictionarypack/WordListPreference.java4
-rw-r--r--java/src/com/android/inputmethod/keyboard/KeyboardLayoutSet.java51
-rw-r--r--java/src/com/android/inputmethod/keyboard/PointerTracker.java6
-rw-r--r--java/src/com/android/inputmethod/keyboard/ProximityInfo.java17
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/GesturePreviewTrail.java29
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/GestureStroke.java2
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/GestureStrokeWithPreviewPoints.java100
-rw-r--r--java/src/com/android/inputmethod/latin/ContactsBinaryDictionary.java36
-rw-r--r--java/src/com/android/inputmethod/latin/LatinIME.java12
-rw-r--r--java/src/com/android/inputmethod/latin/ResourceUtils.java14
-rw-r--r--java/src/com/android/inputmethod/latin/RichInputConnection.java5
-rw-r--r--java/src/com/android/inputmethod/latin/RichInputMethodManager.java17
-rw-r--r--java/src/com/android/inputmethod/latin/StringUtils.java21
-rw-r--r--java/src/com/android/inputmethod/latin/SubtypeSwitcher.java2
-rw-r--r--java/src/com/android/inputmethod/latin/WordComposer.java4
-rw-r--r--java/src/com/android/inputmethod/latin/personalization/AccountUtils.java47
-rw-r--r--java/src/com/android/inputmethod/latin/setup/SetupActivity.java417
-rw-r--r--java/src/com/android/inputmethod/latin/setup/SetupWizardActivity.java466
-rw-r--r--java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java25
-rw-r--r--java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java17
-rw-r--r--java/src/com/android/inputmethod/latin/spellcheck/DictAndKeyboard.java56
-rw-r--r--java/src/com/android/inputmethod/latin/spellcheck/DictAndProximity.java32
-rw-r--r--java/src/com/android/inputmethod/latin/spellcheck/DictionaryPool.java22
-rw-r--r--java/src/com/android/inputmethod/latin/spellcheck/SpellCheckerProximityInfo.java462
-rw-r--r--java/src/com/android/inputmethod/latin/userdictionary/UserDictionaryAddWordFragment.java8
-rw-r--r--java/src/com/android/inputmethod/latin/userdictionary/UserDictionarySettings.java1
-rw-r--r--java/src/com/android/inputmethod/research/FixedLogBuffer.java23
-rw-r--r--java/src/com/android/inputmethod/research/MainLogBuffer.java31
29 files changed, 903 insertions, 1055 deletions
diff --git a/java/src/com/android/inputmethod/dictionarypack/DictionarySettingsFragment.java b/java/src/com/android/inputmethod/dictionarypack/DictionarySettingsFragment.java
index fb75d6dc0..618322357 100644
--- a/java/src/com/android/inputmethod/dictionarypack/DictionarySettingsFragment.java
+++ b/java/src/com/android/inputmethod/dictionarypack/DictionarySettingsFragment.java
@@ -66,6 +66,8 @@ public final class DictionarySettingsFragment extends PreferenceFragment
private boolean mChangedSettings;
private DictionaryListInterfaceState mDictionaryListInterfaceState =
new DictionaryListInterfaceState();
+ private TreeMap<String, WordListPreference> mCurrentPreferenceMap =
+ new TreeMap<String, WordListPreference>(); // never null
private final BroadcastReceiver mConnectivityChangedReceiver = new BroadcastReceiver() {
@Override
@@ -278,7 +280,7 @@ public final class DictionarySettingsFragment extends PreferenceFragment
return result;
} else {
final String systemLocaleString = Locale.getDefault().toString();
- final TreeMap<String, WordListPreference> prefList =
+ final TreeMap<String, WordListPreference> prefMap =
new TreeMap<String, WordListPreference>();
final int idIndex = cursor.getColumnIndex(MetadataDbHelper.WORDLISTID_COLUMN);
final int versionIndex = cursor.getColumnIndex(MetadataDbHelper.VERSION_COLUMN);
@@ -299,16 +301,31 @@ public final class DictionarySettingsFragment extends PreferenceFragment
// The key is sorted in lexicographic order, according to the match level, then
// the description.
final String key = matchLevelString + "." + description + "." + wordlistId;
- final WordListPreference existingPref = prefList.get(key);
+ final WordListPreference existingPref = prefMap.get(key);
if (null == existingPref || hasPriority(status, existingPref.mStatus)) {
- final WordListPreference pref = new WordListPreference(activity,
- mDictionaryListInterfaceState, mClientId, wordlistId, version, locale,
- description, status, filesize);
- prefList.put(key, pref);
+ final WordListPreference oldPreference = mCurrentPreferenceMap.get(key);
+ final WordListPreference pref;
+ if (null != oldPreference
+ && oldPreference.mVersion == version
+ && oldPreference.mLocale.equals(locale)) {
+ // If the old preference has all the new attributes, reuse it. We test
+ // for version and locale because although attributes other than status
+ // need to be the same, others have been tested through the key of the
+ // map. Also, status may differ so we don't want to use #equals() here.
+ pref = oldPreference;
+ pref.mStatus = status;
+ } else {
+ // Otherwise, discard it and create a new one instead.
+ pref = new WordListPreference(activity, mDictionaryListInterfaceState,
+ mClientId, wordlistId, version, locale, description, status,
+ filesize);
+ }
+ prefMap.put(key, pref);
}
} while (cursor.moveToNext());
cursor.close();
- return prefList.values();
+ mCurrentPreferenceMap = prefMap;
+ return prefMap.values();
}
}
diff --git a/java/src/com/android/inputmethod/dictionarypack/WordListPreference.java b/java/src/com/android/inputmethod/dictionarypack/WordListPreference.java
index 29015d61b..451a0fb82 100644
--- a/java/src/com/android/inputmethod/dictionarypack/WordListPreference.java
+++ b/java/src/com/android/inputmethod/dictionarypack/WordListPreference.java
@@ -58,6 +58,8 @@ public final class WordListPreference extends Preference {
// The metadata word list id and version of this word list.
public final String mWordlistId;
public final int mVersion;
+ public final Locale mLocale;
+ public final String mDescription;
// The status
public int mStatus;
// The size of the dictionary file
@@ -80,6 +82,8 @@ public final class WordListPreference extends Preference {
mVersion = version;
mWordlistId = wordlistId;
mFilesize = filesize;
+ mLocale = locale;
+ mDescription = description;
setLayoutResource(R.layout.dictionary_line);
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardLayoutSet.java b/java/src/com/android/inputmethod/keyboard/KeyboardLayoutSet.java
index bc9e8cdd4..1fe23a330 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardLayoutSet.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardLayoutSet.java
@@ -29,17 +29,18 @@ import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
import android.text.InputType;
import android.text.TextUtils;
+import android.util.DisplayMetrics;
import android.util.Log;
import android.util.SparseArray;
import android.util.Xml;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodSubtype;
-import com.android.inputmethod.annotations.UsedForTesting;
import com.android.inputmethod.compat.EditorInfoCompatUtils;
import com.android.inputmethod.keyboard.internal.KeyboardBuilder;
import com.android.inputmethod.keyboard.internal.KeyboardParams;
import com.android.inputmethod.keyboard.internal.KeysCache;
+import com.android.inputmethod.latin.AdditionalSubtype;
import com.android.inputmethod.latin.CollectionUtils;
import com.android.inputmethod.latin.InputAttributes;
import com.android.inputmethod.latin.InputTypeUtils;
@@ -72,6 +73,8 @@ public final class KeyboardLayoutSet {
private static final String TAG_ELEMENT = "Element";
private static final String KEYBOARD_LAYOUT_SET_RESOURCE_PREFIX = "keyboard_layout_set_";
+ private static final int SPELLCHECKER_DUMMY_KEYBOARD_WIDTH = 480;
+ private static final int SPELLCHECKER_DUMMY_KEYBOARD_HEIGHT = 800;
private final Context mContext;
private final Params mParams;
@@ -282,8 +285,7 @@ public final class KeyboardLayoutSet {
return this;
}
- @UsedForTesting
- public void disableTouchPositionCorrectionDataForTest() {
+ public void disableTouchPositionCorrectionData() {
mParams.mDisableTouchPositionCorrectionDataForTest = true;
}
@@ -413,4 +415,47 @@ public final class KeyboardLayoutSet {
}
}
}
+
+ public static KeyboardLayoutSet createKeyboardSetForSpellChecker(final Context context,
+ final String locale, final String layout) {
+ final InputMethodSubtype subtype =
+ AdditionalSubtype.createAdditionalSubtype(locale, layout, null);
+ return createKeyboardSet(context, subtype, SPELLCHECKER_DUMMY_KEYBOARD_WIDTH,
+ SPELLCHECKER_DUMMY_KEYBOARD_HEIGHT, false);
+ }
+
+ public static KeyboardLayoutSet createKeyboardSetForTest(final Context context,
+ final InputMethodSubtype subtype, final int orientation,
+ final boolean testCasesHaveTouchCoordinates) {
+ final DisplayMetrics dm = context.getResources().getDisplayMetrics();
+ final int width;
+ final int height;
+ if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
+ width = Math.max(dm.widthPixels, dm.heightPixels);
+ height = Math.min(dm.widthPixels, dm.heightPixels);
+ } else if (orientation == Configuration.ORIENTATION_PORTRAIT) {
+ width = Math.min(dm.widthPixels, dm.heightPixels);
+ height = Math.max(dm.widthPixels, dm.heightPixels);
+ } else {
+ throw new RuntimeException("Orientation should be ORIENTATION_LANDSCAPE or "
+ + "ORIENTATION_PORTRAIT: orientation=" + orientation);
+ }
+ return createKeyboardSet(context, subtype, width, height, testCasesHaveTouchCoordinates);
+ }
+
+ private static KeyboardLayoutSet createKeyboardSet(final Context context,
+ final InputMethodSubtype subtype, final int width, final int height,
+ final boolean testCasesHaveTouchCoordinates) {
+ final EditorInfo editorInfo = new EditorInfo();
+ editorInfo.inputType = InputType.TYPE_CLASS_TEXT;
+ final KeyboardLayoutSet.Builder builder = new KeyboardLayoutSet.Builder(
+ context, editorInfo);
+ builder.setScreenGeometry(width, height);
+ builder.setSubtype(subtype);
+ if (!testCasesHaveTouchCoordinates) {
+ // For spell checker and tests
+ builder.disableTouchPositionCorrectionData();
+ }
+ return builder.build();
+ }
}
diff --git a/java/src/com/android/inputmethod/keyboard/PointerTracker.java b/java/src/com/android/inputmethod/keyboard/PointerTracker.java
index 0556fddd3..2d791648e 100644
--- a/java/src/com/android/inputmethod/keyboard/PointerTracker.java
+++ b/java/src/com/android/inputmethod/keyboard/PointerTracker.java
@@ -25,6 +25,7 @@ import com.android.inputmethod.accessibility.AccessibilityUtils;
import com.android.inputmethod.keyboard.internal.GestureStroke;
import com.android.inputmethod.keyboard.internal.GestureStroke.GestureStrokeParams;
import com.android.inputmethod.keyboard.internal.GestureStrokeWithPreviewPoints;
+import com.android.inputmethod.keyboard.internal.GestureStrokeWithPreviewPoints.GestureStrokePreviewParams;
import com.android.inputmethod.keyboard.internal.PointerTrackerQueue;
import com.android.inputmethod.latin.CollectionUtils;
import com.android.inputmethod.latin.Constants;
@@ -161,6 +162,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
// Parameters for pointer handling.
private static PointerTrackerParams sParams;
private static GestureStrokeParams sGestureStrokeParams;
+ private static GestureStrokePreviewParams sGesturePreviewParams;
private static boolean sNeedsPhantomSuddenMoveEventHack;
// Move this threshold to resource.
// TODO: Device specific parameter would be better for device specific hack?
@@ -339,12 +341,14 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
sNeedsPhantomSuddenMoveEventHack = needsPhantomSuddenMoveEventHack;
sParams = PointerTrackerParams.DEFAULT;
sGestureStrokeParams = GestureStrokeParams.DEFAULT;
+ sGesturePreviewParams = GestureStrokePreviewParams.DEFAULT;
sTimeRecorder = new TimeRecorder(sParams, sGestureStrokeParams);
}
public static void setParameters(final TypedArray mainKeyboardViewAttr) {
sParams = new PointerTrackerParams(mainKeyboardViewAttr);
sGestureStrokeParams = new GestureStrokeParams(mainKeyboardViewAttr);
+ sGesturePreviewParams = new GestureStrokePreviewParams(mainKeyboardViewAttr);
sTimeRecorder = new TimeRecorder(sParams, sGestureStrokeParams);
}
@@ -428,7 +432,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
}
mPointerId = id;
mGestureStrokeWithPreviewPoints = new GestureStrokeWithPreviewPoints(
- id, sGestureStrokeParams);
+ id, sGestureStrokeParams, sGesturePreviewParams);
setKeyDetectorInner(handler.getKeyDetector());
mListener = handler.getKeyboardActionListener();
mDrawingProxy = handler.getDrawingProxy();
diff --git a/java/src/com/android/inputmethod/keyboard/ProximityInfo.java b/java/src/com/android/inputmethod/keyboard/ProximityInfo.java
index b77e378bf..57d3fede4 100644
--- a/java/src/com/android/inputmethod/keyboard/ProximityInfo.java
+++ b/java/src/com/android/inputmethod/keyboard/ProximityInfo.java
@@ -79,23 +79,6 @@ public class ProximityInfo {
mNativeProximityInfo = createNativeProximityInfo(touchPositionCorrection);
}
- /**
- * Constructor for subclasses such as
- * {@link com.android.inputmethod.latin.spellcheck.SpellCheckerProximityInfo}.
- */
- protected ProximityInfo(final int[] proximityCharsArray, final int gridWidth,
- final int gridHeight) {
- this("", 1, 1, 1, 1, 1, 1, EMPTY_KEY_ARRAY, null);
- mNativeProximityInfo = setProximityInfoNative("" /* locale */,
- gridWidth /* displayWidth */, gridHeight /* displayHeight */,
- gridWidth, gridHeight, 1 /* mostCommonKeyWidth */,
- 1 /* mostCommonKeyHeight */, proximityCharsArray, 0 /* keyCount */,
- null /*keyXCoordinates */, null /* keyYCoordinates */,
- null /* keyWidths */, null /* keyHeights */, null /* keyCharCodes */,
- null /* sweetSpotCenterXs */, null /* sweetSpotCenterYs */,
- null /* sweetSpotRadii */);
- }
-
private long mNativeProximityInfo;
static {
JniUtils.loadNativeLibrary();
diff --git a/java/src/com/android/inputmethod/keyboard/internal/GesturePreviewTrail.java b/java/src/com/android/inputmethod/keyboard/internal/GesturePreviewTrail.java
index 7fd1bedcb..761d9dcd6 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/GesturePreviewTrail.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/GesturePreviewTrail.java
@@ -18,6 +18,7 @@ package com.android.inputmethod.keyboard.internal;
import android.content.res.TypedArray;
import android.graphics.Canvas;
+import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Rect;
@@ -35,12 +36,19 @@ import com.android.inputmethod.latin.ResizableIntArray;
* @attr ref R.styleable#MainKeyboardView_gesturePreviewTrailWidth
*/
final class GesturePreviewTrail {
+ public static final boolean DBG_SHOW_POINTS = false;
+ public static final int POINT_TYPE_SAMPLED = 0;
+ public static final int POINT_TYPE_INTERPOLATED = 1;
+ public static final int POINT_TYPE_COMPROMISED = 2;
+
private static final int DEFAULT_CAPACITY = GestureStrokeWithPreviewPoints.PREVIEW_CAPACITY;
// These three {@link ResizableIntArray}s should be synchronized by {@link #mEventTimes}.
private final ResizableIntArray mXCoordinates = new ResizableIntArray(DEFAULT_CAPACITY);
private final ResizableIntArray mYCoordinates = new ResizableIntArray(DEFAULT_CAPACITY);
private final ResizableIntArray mEventTimes = new ResizableIntArray(DEFAULT_CAPACITY);
+ private final ResizableIntArray mPointTypes = new ResizableIntArray(
+ DBG_SHOW_POINTS ? DEFAULT_CAPACITY : 0);
private int mCurrentStrokeId = -1;
// The wall time of the zero value in {@link #mEventTimes}
private long mCurrentTimeBase;
@@ -75,9 +83,9 @@ final class GesturePreviewTrail {
R.styleable.MainKeyboardView_gesturePreviewTrailShadowRatio, 0);
mTrailShadowEnabled = (trailShadowRatioInt > 0);
mTrailShadowRatio = (float)trailShadowRatioInt / (float)PERCENTAGE_INT;
- mFadeoutStartDelay = mainKeyboardViewAttr.getInt(
+ mFadeoutStartDelay = DBG_SHOW_POINTS ? 2000 : mainKeyboardViewAttr.getInt(
R.styleable.MainKeyboardView_gesturePreviewTrailFadeoutStartDelay, 0);
- mFadeoutDuration = mainKeyboardViewAttr.getInt(
+ mFadeoutDuration = DBG_SHOW_POINTS ? 200 : mainKeyboardViewAttr.getInt(
R.styleable.MainKeyboardView_gesturePreviewTrailFadeoutDuration, 0);
mTrailLingerDuration = mFadeoutStartDelay + mFadeoutDuration;
mUpdateInterval = mainKeyboardViewAttr.getInt(
@@ -125,7 +133,7 @@ final class GesturePreviewTrail {
final int lastInterpolatedIndex = (strokeId == mCurrentStrokeId)
? mLastInterpolatedDrawIndex : trailSize;
mLastInterpolatedDrawIndex = stroke.interpolateStrokeAndReturnStartIndexOfLastSegment(
- lastInterpolatedIndex, mEventTimes, mXCoordinates, mYCoordinates);
+ lastInterpolatedIndex, mEventTimes, mXCoordinates, mYCoordinates, mPointTypes);
if (strokeId != mCurrentStrokeId) {
final int elapsedTime = (int)(downTime - mCurrentTimeBase);
for (int i = mTrailStartIndex; i < trailSize; i++) {
@@ -204,6 +212,7 @@ final class GesturePreviewTrail {
final int[] eventTimes = mEventTimes.getPrimitiveArray();
final int[] xCoords = mXCoordinates.getPrimitiveArray();
final int[] yCoords = mYCoordinates.getPrimitiveArray();
+ final int[] pointTypes = mPointTypes.getPrimitiveArray();
final int sinceDown = (int)(SystemClock.uptimeMillis() - mCurrentTimeBase);
int startIndex;
for (startIndex = mTrailStartIndex; startIndex < trailSize; startIndex++) {
@@ -246,6 +255,17 @@ final class GesturePreviewTrail {
final int alpha = getAlpha(elapsedTime, params);
paint.setAlpha(alpha);
canvas.drawPath(path, paint);
+ if (DBG_SHOW_POINTS) {
+ if (pointTypes[i] == POINT_TYPE_INTERPOLATED) {
+ paint.setColor(Color.RED);
+ } else if (pointTypes[i] == POINT_TYPE_SAMPLED) {
+ paint.setColor(0xFFA000FF);
+ } else {
+ paint.setColor(Color.GREEN);
+ }
+ canvas.drawCircle(p1x - 1, p1y - 1, 2, paint);
+ paint.setColor(params.mTrailColor);
+ }
}
}
p1x = p2x;
@@ -265,6 +285,9 @@ final class GesturePreviewTrail {
mEventTimes.setLength(newSize);
mXCoordinates.setLength(newSize);
mYCoordinates.setLength(newSize);
+ if (DBG_SHOW_POINTS) {
+ mPointTypes.setLength(newSize);
+ }
// The start index of the last segment of the stroke
// {@link mLastInterpolatedDrawIndex} should also be updated because all array
// elements have just been shifted for compaction or been zeroed.
diff --git a/java/src/com/android/inputmethod/keyboard/internal/GestureStroke.java b/java/src/com/android/inputmethod/keyboard/internal/GestureStroke.java
index 93ff26466..70363e602 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/GestureStroke.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/GestureStroke.java
@@ -145,7 +145,7 @@ public class GestureStroke {
public void setKeyboardGeometry(final int keyWidth, final int keyboardHeight) {
mKeyWidth = keyWidth;
mMinYCoordinate = -(int)(keyboardHeight * EXTRA_GESTURE_TRAIL_AREA_ABOVE_KEYBOARD_RATIO);
- mMaxYCoordinate = keyboardHeight - 1;
+ mMaxYCoordinate = keyboardHeight;
// TODO: Find an appropriate base metric for these length. Maybe diagonal length of the key?
mDetectFastMoveSpeedThreshold = (int)(keyWidth * mParams.mDetectFastMoveSpeedThreshold);
mGestureDynamicDistanceThresholdFrom =
diff --git a/java/src/com/android/inputmethod/keyboard/internal/GestureStrokeWithPreviewPoints.java b/java/src/com/android/inputmethod/keyboard/internal/GestureStrokeWithPreviewPoints.java
index 7a51e2568..ccb8802c6 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/GestureStrokeWithPreviewPoints.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/GestureStrokeWithPreviewPoints.java
@@ -16,6 +16,9 @@
package com.android.inputmethod.keyboard.internal;
+import android.content.res.TypedArray;
+
+import com.android.inputmethod.latin.R;
import com.android.inputmethod.latin.ResizableIntArray;
public final class GestureStrokeWithPreviewPoints extends GestureStroke {
@@ -25,6 +28,8 @@ public final class GestureStrokeWithPreviewPoints extends GestureStroke {
private final ResizableIntArray mPreviewXCoordinates = new ResizableIntArray(PREVIEW_CAPACITY);
private final ResizableIntArray mPreviewYCoordinates = new ResizableIntArray(PREVIEW_CAPACITY);
+ private final GestureStrokePreviewParams mPreviewParams;
+
private int mStrokeId;
private int mLastPreviewSize;
private final HermiteInterpolator mInterpolator = new HermiteInterpolator();
@@ -32,23 +37,53 @@ public final class GestureStrokeWithPreviewPoints extends GestureStroke {
private int mLastX;
private int mLastY;
- private double mMinPreviewSamplingDistance;
private double mDistanceFromLastSample;
- private double mInterpolationDistanceThreshold;
-
- // TODO: Move these constants to resource.
- // TODO: Use "dp" instead of ratio to the keyWidth because table has rather large keys.
- // The minimum trail distance between sample points for preview in keyWidth unit when using
- // interpolation.
- private static final float MIN_PREVIEW_SAMPLING_RATIO_TO_KEY_WIDTH = 0.2f;
- // The angular threshold to use interpolation in radian. PI/12 is 15 degree.
- private static final double INTERPOLATION_ANGULAR_THRESHOLD = Math.PI / 12.0d;
- // The distance threshold to use interpolation in keyWidth unit.
- private static final float INTERPOLATION_DISTANCE_THRESHOLD_TO_KEY_WIDTH = 0.5f;
- private static final int MAX_INTERPOLATION_PARTITIONS = 6;
-
- public GestureStrokeWithPreviewPoints(final int pointerId, final GestureStrokeParams params) {
- super(pointerId, params);
+
+ public static final class GestureStrokePreviewParams {
+ public final double mMinSamplingDistance; // in pixel
+ public final double mMaxInterpolationAngularThreshold; // in radian
+ public final double mMaxInterpolationDistanceThreshold; // in pixel
+ public final int mMaxInterpolationSegments;
+
+ public static final GestureStrokePreviewParams DEFAULT = new GestureStrokePreviewParams();
+
+ private static final int DEFAULT_MAX_INTERPOLATION_ANGULAR_THRESHOLD = 15; // in degree
+
+ private GestureStrokePreviewParams() {
+ mMinSamplingDistance = 0.0d;
+ mMaxInterpolationAngularThreshold =
+ degreeToRadian(DEFAULT_MAX_INTERPOLATION_ANGULAR_THRESHOLD);
+ mMaxInterpolationDistanceThreshold = mMinSamplingDistance;
+ mMaxInterpolationSegments = 4;
+ }
+
+ private static double degreeToRadian(final int degree) {
+ return (double)degree / 180.0d * Math.PI;
+ }
+
+ public GestureStrokePreviewParams(final TypedArray mainKeyboardViewAttr) {
+ mMinSamplingDistance = mainKeyboardViewAttr.getDimension(
+ R.styleable.MainKeyboardView_gesturePreviewTrailMinSamplingDistance,
+ (float)DEFAULT.mMinSamplingDistance);
+ final int interpolationAngularDegree = mainKeyboardViewAttr.getInteger(R.styleable
+ .MainKeyboardView_gesturePreviewTrailMaxInterpolationAngularThreshold, 0);
+ mMaxInterpolationAngularThreshold = (interpolationAngularDegree <= 0)
+ ? DEFAULT.mMaxInterpolationAngularThreshold
+ : degreeToRadian(interpolationAngularDegree);
+ mMaxInterpolationDistanceThreshold = mainKeyboardViewAttr.getDimension(R.styleable
+ .MainKeyboardView_gesturePreviewTrailMaxInterpolationDistanceThreshold,
+ (float)DEFAULT.mMaxInterpolationDistanceThreshold);
+ mMaxInterpolationSegments = mainKeyboardViewAttr.getInteger(
+ R.styleable.MainKeyboardView_gesturePreviewTrailMaxInterpolationSegments,
+ DEFAULT.mMaxInterpolationSegments);
+ }
+ }
+
+ public GestureStrokeWithPreviewPoints(final int pointerId,
+ final GestureStrokeParams strokeParams,
+ final GestureStrokePreviewParams previewParams) {
+ super(pointerId, strokeParams);
+ mPreviewParams = previewParams;
}
@Override
@@ -66,19 +101,12 @@ public final class GestureStrokeWithPreviewPoints extends GestureStroke {
return mStrokeId;
}
- @Override
- public void setKeyboardGeometry(final int keyWidth, final int keyboardHeight) {
- super.setKeyboardGeometry(keyWidth, keyboardHeight);
- mMinPreviewSamplingDistance = keyWidth * MIN_PREVIEW_SAMPLING_RATIO_TO_KEY_WIDTH;
- mInterpolationDistanceThreshold = keyWidth * INTERPOLATION_DISTANCE_THRESHOLD_TO_KEY_WIDTH;
- }
-
private boolean needsSampling(final int x, final int y) {
mDistanceFromLastSample += Math.hypot(x - mLastX, y - mLastY);
mLastX = x;
mLastY = y;
final boolean isDownEvent = (mPreviewEventTimes.getLength() == 0);
- if (mDistanceFromLastSample >= mMinPreviewSamplingDistance || isDownEvent) {
+ if (mDistanceFromLastSample >= mPreviewParams.mMinSamplingDistance || isDownEvent) {
mDistanceFromLastSample = 0.0d;
return true;
}
@@ -124,7 +152,7 @@ public final class GestureStrokeWithPreviewPoints extends GestureStroke {
*/
public int interpolateStrokeAndReturnStartIndexOfLastSegment(final int lastInterpolatedIndex,
final ResizableIntArray eventTimes, final ResizableIntArray xCoords,
- final ResizableIntArray yCoords) {
+ final ResizableIntArray yCoords, final ResizableIntArray types) {
final int size = mPreviewEventTimes.getLength();
final int[] pt = mPreviewEventTimes.getPrimitiveArray();
final int[] px = mPreviewXCoordinates.getPrimitiveArray();
@@ -144,28 +172,34 @@ public final class GestureStrokeWithPreviewPoints extends GestureStroke {
final double m1 = Math.atan2(mInterpolator.mSlope1Y, mInterpolator.mSlope1X);
final double m2 = Math.atan2(mInterpolator.mSlope2Y, mInterpolator.mSlope2X);
final double deltaAngle = Math.abs(angularDiff(m2, m1));
- final int partitionsByAngle = (int)Math.ceil(
- deltaAngle / INTERPOLATION_ANGULAR_THRESHOLD);
+ final int segmentsByAngle = (int)Math.ceil(
+ deltaAngle / mPreviewParams.mMaxInterpolationAngularThreshold);
final double deltaDistance = Math.hypot(mInterpolator.mP1X - mInterpolator.mP2X,
mInterpolator.mP1Y - mInterpolator.mP2Y);
- final int partitionsByDistance = (int)Math.ceil(deltaDistance
- / mInterpolationDistanceThreshold);
- final int partitions = Math.min(MAX_INTERPOLATION_PARTITIONS,
- Math.max(partitionsByAngle, partitionsByDistance));
+ final int segmentsByDistance = (int)Math.ceil(deltaDistance
+ / mPreviewParams.mMaxInterpolationDistanceThreshold);
+ final int segments = Math.min(mPreviewParams.mMaxInterpolationSegments,
+ Math.max(segmentsByAngle, segmentsByDistance));
final int t1 = eventTimes.get(d1);
final int dt = pt[p2] - pt[p1];
d1++;
- for (int i = 1; i < partitions; i++) {
- final float t = i / (float)partitions;
+ for (int i = 1; i < segments; i++) {
+ final float t = i / (float)segments;
mInterpolator.interpolate(t);
eventTimes.add(d1, (int)(dt * t) + t1);
xCoords.add(d1, (int)mInterpolator.mInterpolatedX);
yCoords.add(d1, (int)mInterpolator.mInterpolatedY);
+ if (GesturePreviewTrail.DBG_SHOW_POINTS) {
+ types.add(d1, GesturePreviewTrail.POINT_TYPE_INTERPOLATED);
+ }
d1++;
}
eventTimes.add(d1, pt[p2]);
xCoords.add(d1, px[p2]);
yCoords.add(d1, py[p2]);
+ if (GesturePreviewTrail.DBG_SHOW_POINTS) {
+ types.add(d1, GesturePreviewTrail.POINT_TYPE_SAMPLED);
+ }
}
return lastInterpolatedDrawIndex;
}
diff --git a/java/src/com/android/inputmethod/latin/ContactsBinaryDictionary.java b/java/src/com/android/inputmethod/latin/ContactsBinaryDictionary.java
index 75c2cf2c8..b9db9a092 100644
--- a/java/src/com/android/inputmethod/latin/ContactsBinaryDictionary.java
+++ b/java/src/com/android/inputmethod/latin/ContactsBinaryDictionary.java
@@ -16,21 +16,26 @@
package com.android.inputmethod.latin;
+import com.android.inputmethod.latin.personalization.AccountUtils;
+
import android.content.ContentResolver;
import android.content.Context;
import android.database.ContentObserver;
import android.database.Cursor;
+import android.net.Uri;
import android.os.SystemClock;
import android.provider.BaseColumns;
+import android.provider.ContactsContract;
import android.provider.ContactsContract.Contacts;
import android.text.TextUtils;
import android.util.Log;
+import java.util.List;
import java.util.Locale;
public class ContactsBinaryDictionary extends ExpandableBinaryDictionary {
- private static final String[] PROJECTION = {BaseColumns._ID, Contacts.DISPLAY_NAME,};
+ private static final String[] PROJECTION = {BaseColumns._ID, Contacts.DISPLAY_NAME};
private static final String[] PROJECTION_ID_ONLY = {BaseColumns._ID};
private static final String TAG = ContactsBinaryDictionary.class.getSimpleName();
@@ -102,9 +107,32 @@ public class ContactsBinaryDictionary extends ExpandableBinaryDictionary {
@Override
public void loadDictionaryAsync() {
+ clearFusionDictionary();
+ loadDeviceAccountsEmailAddresses();
+ loadDictionaryAsyncForUri(ContactsContract.Profile.CONTENT_URI);
+ // TODO: Switch this URL to the newer ContactsContract too
+ loadDictionaryAsyncForUri(Contacts.CONTENT_URI);
+ }
+
+ private void loadDeviceAccountsEmailAddresses() {
+ final List<String> accountVocabulary =
+ AccountUtils.getDeviceAccountsEmailAddresses(mContext);
+ if (accountVocabulary == null || accountVocabulary.isEmpty()) {
+ return;
+ }
+ for (String word : accountVocabulary) {
+ if (DEBUG) {
+ Log.d(TAG, "loadAccountVocabulary: " + word);
+ }
+ super.addWord(word, null /* shortcut */, FREQUENCY_FOR_CONTACTS,
+ false /* isNotAWord */);
+ }
+ }
+
+ private void loadDictionaryAsyncForUri(final Uri uri) {
try {
Cursor cursor = mContext.getContentResolver()
- .query(Contacts.CONTENT_URI, PROJECTION, null, null, null);
+ .query(uri, PROJECTION, null, null, null);
if (cursor != null) {
try {
if (cursor.moveToFirst()) {
@@ -129,7 +157,6 @@ public class ContactsBinaryDictionary extends ExpandableBinaryDictionary {
}
private void addWords(final Cursor cursor) {
- clearFusionDictionary();
int count = 0;
while (!cursor.isAfterLast() && count < MAX_CONTACT_COUNT) {
String name = cursor.getString(INDEX_NAME);
@@ -173,6 +200,9 @@ public class ContactsBinaryDictionary extends ExpandableBinaryDictionary {
// capitalization of i.
final int wordLen = StringUtils.codePointCount(word);
if (wordLen < MAX_WORD_LENGTH && wordLen > 1) {
+ if (DEBUG) {
+ Log.d(TAG, "addName " + name + ", " + word + ", " + prevWord);
+ }
super.addWord(word, null /* shortcut */, FREQUENCY_FOR_CONTACTS,
false /* isNotAWord */);
if (!TextUtils.isEmpty(prevWord)) {
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index 84c752934..fdd470cf1 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -250,6 +250,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
}
public void postResumeSuggestions() {
+ removeMessages(MSG_RESUME_SUGGESTIONS);
sendMessageDelayed(obtainMessage(MSG_RESUME_SUGGESTIONS), mDelayUpdateSuggestions);
}
@@ -759,7 +760,8 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
}
mSuggestedWords = SuggestedWords.EMPTY;
- mConnection.resetCachesUponCursorMove(editorInfo.initialSelStart);
+ mConnection.resetCachesUponCursorMove(editorInfo.initialSelStart,
+ false /* shouldFinishComposition */);
if (isDifferentTextField) {
mainKeyboardView.closing();
@@ -1148,13 +1150,14 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
// This will reset the whole input state to the starting state. It will clear
// the composing word, reset the last composed word, tell the inputconnection about it.
private void resetEntireInputState(final int newCursorPosition) {
+ final boolean shouldFinishComposition = mWordComposer.isComposingWord();
resetComposingState(true /* alsoResetLastComposedWord */);
if (mSettings.getCurrent().mBigramPredictionEnabled) {
clearSuggestionStrip();
} else {
setSuggestedWords(mSettings.getCurrent().mSuggestPuncList, false);
}
- mConnection.resetCachesUponCursorMove(newCursorPosition);
+ mConnection.resetCachesUponCursorMove(newCursorPosition, shouldFinishComposition);
}
private void resetComposingState(final boolean alsoResetLastComposedWord) {
@@ -2436,10 +2439,15 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
private void restartSuggestionsOnWordTouchedByCursor() {
// If the cursor is not touching a word, or if there is a selection, return right away.
if (mLastSelectionStart != mLastSelectionEnd) return;
+ // If we don't know the cursor location, return.
+ if (mLastSelectionStart < 0) return;
if (!mConnection.isCursorTouchingWord(mSettings.getCurrent())) return;
final Range range = mConnection.getWordRangeAtCursor(mSettings.getWordSeparators(),
0 /* additionalPrecedingWordsCount */);
if (null == range) return; // Happens if we don't have an input connection at all
+ // If for some strange reason (editor bug or so) we measure the text before the cursor as
+ // longer than what the entire text is supposed to be, the safe thing to do is bail out.
+ if (range.mCharsBefore > mLastSelectionStart) return;
final ArrayList<SuggestedWordInfo> suggestions = CollectionUtils.newArrayList();
final String typedWord = range.mWord.toString();
if (range.mWord instanceof SpannableString) {
diff --git a/java/src/com/android/inputmethod/latin/ResourceUtils.java b/java/src/com/android/inputmethod/latin/ResourceUtils.java
index b74b979b5..f0bfe75fe 100644
--- a/java/src/com/android/inputmethod/latin/ResourceUtils.java
+++ b/java/src/com/android/inputmethod/latin/ResourceUtils.java
@@ -35,8 +35,7 @@ public final class ResourceUtils {
// This utility class is not publicly instantiable.
}
- private static final String DEFAULT_PREFIX = "DEFAULT,";
- private static final String HARDWARE_PREFIX = Build.HARDWARE + ",";
+ private static final String DEFAULT_KEY = "DEFAULT";
private static final HashMap<String, String> sDeviceOverrideValueMap =
CollectionUtils.newHashMap();
@@ -48,28 +47,29 @@ public final class ResourceUtils {
}
final String[] overrideArray = res.getStringArray(overrideResId);
- final String overrideValue = StringUtils.findPrefixedString(HARDWARE_PREFIX, overrideArray);
+ final String hardwareKey = "HARDWARE=" + Build.HARDWARE;
+ final String overrideValue = StringUtils.findValueOfKey(hardwareKey, overrideArray);
// The overrideValue might be an empty string.
if (overrideValue != null) {
if (DEBUG) {
Log.d(TAG, "Find override value:"
+ " resource="+ res.getResourceEntryName(overrideResId)
- + " Build.HARDWARE=" + Build.HARDWARE + " override=" + overrideValue);
+ + " " + hardwareKey + " override=" + overrideValue);
}
sDeviceOverrideValueMap.put(key, overrideValue);
return overrideValue;
}
- final String defaultValue = StringUtils.findPrefixedString(DEFAULT_PREFIX, overrideArray);
+ final String defaultValue = StringUtils.findValueOfKey(DEFAULT_KEY, overrideArray);
// The defaultValue might be an empty string.
if (defaultValue == null) {
Log.w(TAG, "Couldn't find override value nor default value:"
+ " resource="+ res.getResourceEntryName(overrideResId)
- + " Build.HARDWARE=" + Build.HARDWARE);
+ + " " + hardwareKey);
} else if (DEBUG) {
Log.d(TAG, "Found default value:"
+ " resource="+ res.getResourceEntryName(overrideResId)
- + " Build.HARDWARE=" + Build.HARDWARE + " default=" + defaultValue);
+ + " " + hardwareKey + " " + DEFAULT_KEY + "=" + defaultValue);
}
sDeviceOverrideValueMap.put(key, defaultValue);
return defaultValue;
diff --git a/java/src/com/android/inputmethod/latin/RichInputConnection.java b/java/src/com/android/inputmethod/latin/RichInputConnection.java
index 8ed7ab264..980215de6 100644
--- a/java/src/com/android/inputmethod/latin/RichInputConnection.java
+++ b/java/src/com/android/inputmethod/latin/RichInputConnection.java
@@ -135,13 +135,14 @@ public final class RichInputConnection {
if (DEBUG_PREVIOUS_TEXT) checkConsistencyForDebug();
}
- public void resetCachesUponCursorMove(final int newCursorPosition) {
+ public void resetCachesUponCursorMove(final int newCursorPosition,
+ final boolean shouldFinishComposition) {
mCurrentCursorPosition = newCursorPosition;
mComposingText.setLength(0);
mCommittedTextBeforeComposingText.setLength(0);
final CharSequence textBeforeCursor = getTextBeforeCursor(DEFAULT_TEXT_CACHE_SIZE, 0);
if (null != textBeforeCursor) mCommittedTextBeforeComposingText.append(textBeforeCursor);
- if (null != mIC) {
+ if (null != mIC && shouldFinishComposition) {
mIC.finishComposingText();
if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) {
ResearchLogger.richInputConnection_finishComposingText();
diff --git a/java/src/com/android/inputmethod/latin/RichInputMethodManager.java b/java/src/com/android/inputmethod/latin/RichInputMethodManager.java
index 3f7be99e5..94513e635 100644
--- a/java/src/com/android/inputmethod/latin/RichInputMethodManager.java
+++ b/java/src/com/android/inputmethod/latin/RichInputMethodManager.java
@@ -100,6 +100,12 @@ public final class RichInputMethodManager {
throw new RuntimeException("Input method id for " + packageName + " not found.");
}
+ public List<InputMethodSubtype> getMyEnabledInputMethodSubtypeList(
+ boolean allowsImplicitlySelectedSubtypes) {
+ return mImmWrapper.mImm.getEnabledInputMethodSubtypeList(
+ mInputMethodInfoOfThisIme, allowsImplicitlySelectedSubtypes);
+ }
+
public boolean switchToNextInputMethod(final IBinder token, final boolean onlyCurrentIme) {
if (mImmWrapper.switchToNextInputMethod(token, onlyCurrentIme)) {
return true;
@@ -116,8 +122,8 @@ public final class RichInputMethodManager {
final boolean onlyCurrentIme) {
final InputMethodManager imm = mImmWrapper.mImm;
final InputMethodSubtype currentSubtype = imm.getCurrentInputMethodSubtype();
- final List<InputMethodSubtype> enabledSubtypes = imm.getEnabledInputMethodSubtypeList(
- mInputMethodInfoOfThisIme, true /* allowsImplicitlySelectedSubtypes */);
+ final List<InputMethodSubtype> enabledSubtypes = getMyEnabledInputMethodSubtypeList(
+ true /* allowsImplicitlySelectedSubtypes */);
final int currentIndex = getSubtypeIndexInList(currentSubtype, enabledSubtypes);
if (currentIndex == INDEX_NOT_FOUND) {
Log.w(TAG, "Can't find current subtype in enabled subtypes: subtype="
@@ -214,8 +220,8 @@ public final class RichInputMethodManager {
final InputMethodSubtype subtype) {
final boolean subtypeEnabled = checkIfSubtypeBelongsToThisImeAndEnabled(subtype);
final boolean subtypeExplicitlyEnabled = checkIfSubtypeBelongsToList(
- subtype, mImmWrapper.mImm.getEnabledInputMethodSubtypeList(
- mInputMethodInfoOfThisIme, false /* allowsImplicitlySelectedSubtypes */));
+ subtype, getMyEnabledInputMethodSubtypeList(
+ false /* allowsImplicitlySelectedSubtypes */));
return subtypeEnabled && !subtypeExplicitlyEnabled;
}
@@ -312,8 +318,7 @@ public final class RichInputMethodManager {
if (filteredImisCount > 1) {
return true;
}
- final List<InputMethodSubtype> subtypes =
- mImmWrapper.mImm.getEnabledInputMethodSubtypeList(null, true);
+ final List<InputMethodSubtype> subtypes = getMyEnabledInputMethodSubtypeList(true);
int keyboardCount = 0;
// imm.getEnabledInputMethodSubtypeList(null, true) will return the current IME's
// both explicitly and implicitly enabled input method subtype.
diff --git a/java/src/com/android/inputmethod/latin/StringUtils.java b/java/src/com/android/inputmethod/latin/StringUtils.java
index d5ee58a63..5ff101f7a 100644
--- a/java/src/com/android/inputmethod/latin/StringUtils.java
+++ b/java/src/com/android/inputmethod/latin/StringUtils.java
@@ -65,17 +65,24 @@ public final class StringUtils {
}
/**
- * Find a string that start with specified prefix from an array.
+ * Find a value that has a specified key from an array of key-comma-value.
*
- * @param prefix a prefix string to find.
- * @param array an string array to be searched.
- * @return the rest part of the string that starts with the prefix.
+ * @param key a key string to find.
+ * @param array an array of key-comma-value string to be searched.
+ * @return the value part of the first string that has a specified key.
* Returns null if it couldn't be found.
*/
- public static String findPrefixedString(final String prefix, final String[] array) {
+ public static String findValueOfKey(final String key, final String[] array) {
+ if (array == null) {
+ return null;
+ }
for (final String element : array) {
- if (element.startsWith(prefix)) {
- return element.substring(prefix.length());
+ final int posComma = element.indexOf(',');
+ if (posComma < 0) {
+ throw new RuntimeException("Element has no comma: " + element);
+ }
+ if (element.substring(0, posComma).equals(key)) {
+ return element.substring(posComma + 1);
}
}
return null;
diff --git a/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java b/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java
index bef8a3cf1..282b5794f 100644
--- a/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java
+++ b/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java
@@ -115,7 +115,7 @@ public final class SubtypeSwitcher {
*/
public void updateParametersOnStartInputView() {
final List<InputMethodSubtype> enabledSubtypesOfThisIme =
- mRichImm.getInputMethodManager().getEnabledInputMethodSubtypeList(null, true);
+ mRichImm.getMyEnabledInputMethodSubtypeList(true);
mNeedsToDisplayLanguage.updateEnabledSubtypeCount(enabledSubtypesOfThisIme.size());
updateShortcutIME();
}
diff --git a/java/src/com/android/inputmethod/latin/WordComposer.java b/java/src/com/android/inputmethod/latin/WordComposer.java
index 51bd901fb..e078f03f4 100644
--- a/java/src/com/android/inputmethod/latin/WordComposer.java
+++ b/java/src/com/android/inputmethod/latin/WordComposer.java
@@ -16,7 +16,6 @@
package com.android.inputmethod.latin;
-import com.android.inputmethod.annotations.UsedForTesting;
import com.android.inputmethod.keyboard.Key;
import com.android.inputmethod.keyboard.Keyboard;
@@ -211,9 +210,8 @@ public final class WordComposer {
}
/**
- * Internal method to retrieve reasonable proximity info for a character.
+ * Add a dummy key by retrieving reasonable coordinates
*/
- @UsedForTesting
public void addKeyInfo(final int codePoint, final Keyboard keyboard) {
final int x, y;
final Key key;
diff --git a/java/src/com/android/inputmethod/latin/personalization/AccountUtils.java b/java/src/com/android/inputmethod/latin/personalization/AccountUtils.java
new file mode 100644
index 000000000..93687e193
--- /dev/null
+++ b/java/src/com/android/inputmethod/latin/personalization/AccountUtils.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.inputmethod.latin.personalization;
+
+import android.accounts.Account;
+import android.accounts.AccountManager;
+import android.content.Context;
+import android.util.Patterns;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class AccountUtils {
+ private AccountUtils() {
+ // This utility class is not publicly instantiable.
+ }
+
+ private static Account[] getAccounts(final Context context) {
+ return AccountManager.get(context).getAccounts();
+ }
+
+ public static List<String> getDeviceAccountsEmailAddresses(final Context context) {
+ final ArrayList<String> retval = new ArrayList<String>();
+ for (final Account account : getAccounts(context)) {
+ final String name = account.name;
+ if (Patterns.EMAIL_ADDRESS.matcher(name).matches()) {
+ retval.add(name);
+ retval.add(name.split("@")[0]);
+ }
+ }
+ return retval;
+ }
+}
diff --git a/java/src/com/android/inputmethod/latin/setup/SetupActivity.java b/java/src/com/android/inputmethod/latin/setup/SetupActivity.java
index affe3a348..8a2de887d 100644
--- a/java/src/com/android/inputmethod/latin/setup/SetupActivity.java
+++ b/java/src/com/android/inputmethod/latin/setup/SetupActivity.java
@@ -17,270 +17,27 @@
package com.android.inputmethod.latin.setup;
import android.app.Activity;
-import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
-import android.content.res.Resources;
-import android.media.MediaPlayer;
-import android.net.Uri;
import android.os.Bundle;
-import android.os.Message;
import android.provider.Settings;
-import android.util.Log;
-import android.view.View;
import android.view.inputmethod.InputMethodInfo;
import android.view.inputmethod.InputMethodManager;
-import android.widget.ImageView;
-import android.widget.TextView;
-import android.widget.VideoView;
-import com.android.inputmethod.compat.TextViewCompatUtils;
-import com.android.inputmethod.compat.ViewCompatUtils;
-import com.android.inputmethod.latin.CollectionUtils;
-import com.android.inputmethod.latin.R;
import com.android.inputmethod.latin.RichInputMethodManager;
-import com.android.inputmethod.latin.SettingsActivity;
-import com.android.inputmethod.latin.StaticInnerHandlerWrapper;
-
-import java.util.ArrayList;
-
-// TODO: Use Fragment to implement welcome screen and setup steps.
-public final class SetupActivity extends Activity implements View.OnClickListener {
- private static final String TAG = SetupActivity.class.getSimpleName();
-
- private View mWelcomeScreen;
- private View mSetupScreen;
- private Uri mWelcomeVideoUri;
- private VideoView mWelcomeVideoView;
- private View mActionStart;
- private View mActionNext;
- private TextView mStep1Bullet;
- private TextView mActionFinish;
- private SetupStepGroup mSetupStepGroup;
- private static final String STATE_STEP = "step";
- private int mStepNumber;
- private static final int STEP_WELCOME = 0;
- private static final int STEP_1 = 1;
- private static final int STEP_2 = 2;
- private static final int STEP_3 = 3;
- private boolean mWasLanguageAndInputSettingsInvoked;
-
- private final SettingsPoolingHandler mHandler = new SettingsPoolingHandler(this);
-
- static final class SettingsPoolingHandler extends StaticInnerHandlerWrapper<SetupActivity> {
- private static final int MSG_POLLING_IME_SETTINGS = 0;
- private static final long IME_SETTINGS_POLLING_INTERVAL = 200;
-
- public SettingsPoolingHandler(final SetupActivity outerInstance) {
- super(outerInstance);
- }
-
- @Override
- public void handleMessage(final Message msg) {
- final SetupActivity setupActivity = getOuterInstance();
- if (setupActivity == null) {
- return;
- }
- switch (msg.what) {
- case MSG_POLLING_IME_SETTINGS:
- if (SetupActivity.isThisImeEnabled(setupActivity)) {
- setupActivity.invokeSetupWizardOfThisIme();
- return;
- }
- startPollingImeSettings();
- break;
- }
- }
-
- public void startPollingImeSettings() {
- sendMessageDelayed(obtainMessage(MSG_POLLING_IME_SETTINGS),
- IME_SETTINGS_POLLING_INTERVAL);
- }
-
- public void cancelPollingImeSettings() {
- removeMessages(MSG_POLLING_IME_SETTINGS);
- }
- }
+public final class SetupActivity extends Activity {
@Override
protected void onCreate(final Bundle savedInstanceState) {
- setTheme(android.R.style.Theme_DeviceDefault_Light_NoActionBar);
super.onCreate(savedInstanceState);
-
- setContentView(R.layout.setup_wizard);
-
- RichInputMethodManager.init(this);
-
- if (savedInstanceState == null) {
- mStepNumber = determineSetupStepNumber();
- if (mStepNumber == STEP_1 && !mWasLanguageAndInputSettingsInvoked) {
- mStepNumber = STEP_WELCOME;
- }
- if (mStepNumber == STEP_3) {
- // This IME already has been enabled and set as current IME.
- // TODO: Implement tutorial.
- invokeSettingsOfThisIme();
- finish();
- return;
- }
- } else {
- mStepNumber = savedInstanceState.getInt(STATE_STEP);
- }
-
- final String applicationName = getResources().getString(getApplicationInfo().labelRes);
- mWelcomeScreen = findViewById(R.id.setup_welcome_screen);
- final TextView welcomeTitle = (TextView)findViewById(R.id.setup_welcome_title);
- welcomeTitle.setText(getString(R.string.setup_welcome_title, applicationName));
-
- mSetupScreen = findViewById(R.id.setup_steps_screen);
- final TextView stepsTitle = (TextView)findViewById(R.id.setup_title);
- stepsTitle.setText(getString(R.string.setup_steps_title, applicationName));
-
- final SetupStepIndicatorView indicatorView =
- (SetupStepIndicatorView)findViewById(R.id.setup_step_indicator);
- mSetupStepGroup = new SetupStepGroup(indicatorView);
-
- mStep1Bullet = (TextView)findViewById(R.id.setup_step1_bullet);
- mStep1Bullet.setOnClickListener(this);
- final SetupStep step1 = new SetupStep(STEP_1, applicationName,
- mStep1Bullet, findViewById(R.id.setup_step1),
- R.string.setup_step1_title, R.string.setup_step1_instruction,
- R.string.setup_step1_finished_instruction, R.drawable.ic_setup_step1,
- R.string.setup_step1_action);
- step1.setAction(new Runnable() {
- @Override
- public void run() {
- invokeLanguageAndInputSettings();
- mHandler.startPollingImeSettings();
- }
- });
- mSetupStepGroup.addStep(step1);
-
- final SetupStep step2 = new SetupStep(STEP_2, applicationName,
- (TextView)findViewById(R.id.setup_step2_bullet), findViewById(R.id.setup_step2),
- R.string.setup_step2_title, R.string.setup_step2_instruction,
- 0 /* finishedInstruction */, R.drawable.ic_setup_step2,
- R.string.setup_step2_action);
- step2.setAction(new Runnable() {
- @Override
- public void run() {
- // Invoke input method picker.
- RichInputMethodManager.getInstance().getInputMethodManager()
- .showInputMethodPicker();
- }
- });
- mSetupStepGroup.addStep(step2);
-
- final SetupStep step3 = new SetupStep(STEP_3, applicationName,
- (TextView)findViewById(R.id.setup_step3_bullet), findViewById(R.id.setup_step3),
- R.string.setup_step3_title, R.string.setup_step3_instruction,
- 0 /* finishedInstruction */, R.drawable.ic_setup_step3,
- R.string.setup_step3_action);
- step3.setAction(new Runnable() {
- @Override
- public void run() {
- invokeSubtypeEnablerOfThisIme();
- }
- });
- mSetupStepGroup.addStep(step3);
-
- mWelcomeVideoUri = new Uri.Builder()
- .scheme(ContentResolver.SCHEME_ANDROID_RESOURCE)
- .authority(getPackageName())
- .path(Integer.toString(R.raw.setup_welcome_video))
- .build();
- mWelcomeVideoView = (VideoView)findViewById(R.id.setup_welcome_video);
- mWelcomeVideoView.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
- @Override
- public void onCompletion(final MediaPlayer mp) {
- mp.start();
- }
- });
- mWelcomeVideoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
- @Override
- public void onPrepared(final MediaPlayer mp) {
- // Now VideoView has been laid-out and ready to play, remove background of it to
- // reveal the video.
- mWelcomeVideoView.setBackgroundResource(0);
- }
- });
- final ImageView welcomeImageView = (ImageView)findViewById(R.id.setup_welcome_image);
- mWelcomeVideoView.setOnErrorListener(new MediaPlayer.OnErrorListener() {
- @Override
- public boolean onError(final MediaPlayer mp, final int what, final int extra) {
- Log.e(TAG, "Playing welcome video causes error: what=" + what + " extra=" + extra);
- mWelcomeVideoView.setVisibility(View.GONE);
- welcomeImageView.setImageResource(R.raw.setup_welcome_image);
- welcomeImageView.setVisibility(View.VISIBLE);
- return true;
- }
- });
-
- mActionStart = findViewById(R.id.setup_start_label);
- mActionStart.setOnClickListener(this);
- mActionNext = findViewById(R.id.setup_next);
- mActionNext.setOnClickListener(this);
- mActionFinish = (TextView)findViewById(R.id.setup_finish);
- TextViewCompatUtils.setCompoundDrawablesRelativeWithIntrinsicBounds(mActionFinish,
- getResources().getDrawable(R.drawable.ic_setup_finish), null, null, null);
- mActionFinish.setOnClickListener(this);
- }
-
- @Override
- public void onClick(final View v) {
- if (v == mActionFinish) {
- finish();
- return;
- }
- final int currentStep = determineSetupStepNumber();
- final int nextStep;
- if (v == mActionStart) {
- nextStep = STEP_1;
- } else if (v == mActionNext) {
- nextStep = mStepNumber + 1;
- } else if (v == mStep1Bullet && currentStep == STEP_2) {
- nextStep = STEP_1;
- } else {
- nextStep = mStepNumber;
- }
- if (mStepNumber != nextStep) {
- mStepNumber = nextStep;
- updateSetupStepView();
- }
- }
-
- private void invokeSetupWizardOfThisIme() {
- final Intent intent = new Intent();
- intent.setClass(this, SetupActivity.class);
- intent.setFlags(Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
- | Intent.FLAG_ACTIVITY_CLEAR_TOP);
- startActivity(intent);
- }
-
- private void invokeSettingsOfThisIme() {
- final Intent intent = new Intent();
- intent.setClass(this, SettingsActivity.class);
- intent.setFlags(Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
- | Intent.FLAG_ACTIVITY_CLEAR_TOP);
- startActivity(intent);
- }
-
- private void invokeLanguageAndInputSettings() {
final Intent intent = new Intent();
- intent.setAction(Settings.ACTION_INPUT_METHOD_SETTINGS);
- intent.addCategory(Intent.CATEGORY_DEFAULT);
- startActivity(intent);
- mWasLanguageAndInputSettingsInvoked = true;
- }
-
- private void invokeSubtypeEnablerOfThisIme() {
- final InputMethodInfo imi =
- RichInputMethodManager.getInstance().getInputMethodInfoOfThisIme();
- final Intent intent = new Intent();
- intent.setAction(Settings.ACTION_INPUT_METHOD_SUBTYPE_SETTINGS);
- intent.addCategory(Intent.CATEGORY_DEFAULT);
- intent.putExtra(Settings.EXTRA_INPUT_METHOD_ID, imi.getId());
+ intent.setClass(this, SetupWizardActivity.class);
+ intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP
+ | Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
+ if (!isFinishing()) {
+ finish();
+ }
}
/**
@@ -317,164 +74,4 @@ public final class SetupActivity extends Activity implements View.OnClickListene
context.getContentResolver(), Settings.Secure.DEFAULT_INPUT_METHOD);
return myImi.getId().equals(currentImeId);
}
-
- private int determineSetupStepNumber() {
- mHandler.cancelPollingImeSettings();
- if (!isThisImeEnabled(this)) {
- return STEP_1;
- }
- if (!isThisImeCurrent(this)) {
- return STEP_2;
- }
- return STEP_3;
- }
-
- @Override
- protected void onSaveInstanceState(final Bundle outState) {
- super.onSaveInstanceState(outState);
- outState.putInt(STATE_STEP, mStepNumber);
- }
-
- @Override
- protected void onRestoreInstanceState(final Bundle savedInstanceState) {
- super.onRestoreInstanceState(savedInstanceState);
- mStepNumber = savedInstanceState.getInt(STATE_STEP);
- }
-
- @Override
- protected void onRestart() {
- super.onRestart();
- if (mStepNumber != STEP_WELCOME) {
- mStepNumber = determineSetupStepNumber();
- }
- }
-
- @Override
- protected void onResume() {
- super.onResume();
- updateSetupStepView();
- }
-
- @Override
- public void onBackPressed() {
- if (mStepNumber == STEP_1) {
- mStepNumber = STEP_WELCOME;
- updateSetupStepView();
- return;
- }
- super.onBackPressed();
- }
-
- @Override
- protected void onPause() {
- mWelcomeVideoView.stopPlayback();
- super.onPause();
- }
-
- @Override
- public void onWindowFocusChanged(final boolean hasFocus) {
- super.onWindowFocusChanged(hasFocus);
- if (hasFocus && mStepNumber != STEP_WELCOME) {
- mStepNumber = determineSetupStepNumber();
- updateSetupStepView();
- }
- }
-
- private void updateSetupStepView() {
- final boolean welcomeScreen = (mStepNumber == STEP_WELCOME);
- mWelcomeScreen.setVisibility(welcomeScreen ? View.VISIBLE : View.GONE);
- mSetupScreen.setVisibility(welcomeScreen ? View.GONE: View.VISIBLE);
- if (welcomeScreen) {
- mWelcomeVideoView.setVideoURI(mWelcomeVideoUri);
- mWelcomeVideoView.start();
- return;
- }
- mWelcomeVideoView.stopPlayback();
- final boolean isStepActionAlreadyDone = mStepNumber < determineSetupStepNumber();
- mSetupStepGroup.enableStep(mStepNumber, isStepActionAlreadyDone);
- mActionNext.setVisibility(isStepActionAlreadyDone ? View.VISIBLE : View.GONE);
- mActionFinish.setVisibility((mStepNumber == STEP_3) ? View.VISIBLE : View.GONE);
- }
-
- static final class SetupStep implements View.OnClickListener {
- public final int mStepNo;
- private final View mStepView;
- private final TextView mBulletView;
- private final int mActivatedColor;
- private final int mDeactivatedColor;
- private final String mInstruction;
- private final String mFinishedInstruction;
- private final TextView mActionLabel;
- private Runnable mAction;
-
- public SetupStep(final int stepNo, final String applicationName, final TextView bulletView,
- final View stepView, final int title, final int instruction,
- final int finishedInstruction,final int actionIcon, final int actionLabel) {
- mStepNo = stepNo;
- mStepView = stepView;
- mBulletView = bulletView;
- final Resources res = stepView.getResources();
- mActivatedColor = res.getColor(R.color.setup_text_action);
- mDeactivatedColor = res.getColor(R.color.setup_text_dark);
-
- final TextView titleView = (TextView)mStepView.findViewById(R.id.setup_step_title);
- titleView.setText(res.getString(title, applicationName));
- mInstruction = (instruction == 0) ? null
- : res.getString(instruction, applicationName);
- mFinishedInstruction = (finishedInstruction == 0) ? null
- : res.getString(finishedInstruction, applicationName);
-
- mActionLabel = (TextView)mStepView.findViewById(R.id.setup_step_action_label);
- mActionLabel.setText(res.getString(actionLabel));
- if (actionIcon == 0) {
- final int paddingEnd = ViewCompatUtils.getPaddingEnd(mActionLabel);
- ViewCompatUtils.setPaddingRelative(mActionLabel, paddingEnd, 0, paddingEnd, 0);
- } else {
- TextViewCompatUtils.setCompoundDrawablesRelativeWithIntrinsicBounds(
- mActionLabel, res.getDrawable(actionIcon), null, null, null);
- }
- }
-
- public void setEnabled(final boolean enabled, final boolean isStepActionAlreadyDone) {
- mStepView.setVisibility(enabled ? View.VISIBLE : View.GONE);
- mBulletView.setTextColor(enabled ? mActivatedColor : mDeactivatedColor);
- final TextView instructionView = (TextView)mStepView.findViewById(
- R.id.setup_step_instruction);
- instructionView.setText(isStepActionAlreadyDone ? mFinishedInstruction : mInstruction);
- mActionLabel.setVisibility(isStepActionAlreadyDone ? View.GONE : View.VISIBLE);
- }
-
- public void setAction(final Runnable action) {
- mActionLabel.setOnClickListener(this);
- mAction = action;
- }
-
- @Override
- public void onClick(final View v) {
- if (v == mActionLabel && mAction != null) {
- mAction.run();
- return;
- }
- }
- }
-
- static final class SetupStepGroup {
- private final SetupStepIndicatorView mIndicatorView;
- private final ArrayList<SetupStep> mGroup = CollectionUtils.newArrayList();
-
- public SetupStepGroup(final SetupStepIndicatorView indicatorView) {
- mIndicatorView = indicatorView;
- }
-
- public void addStep(final SetupStep step) {
- mGroup.add(step);
- }
-
- public void enableStep(final int enableStepNo, final boolean isStepActionAlreadyDone) {
- for (final SetupStep step : mGroup) {
- step.setEnabled(step.mStepNo == enableStepNo, isStepActionAlreadyDone);
- }
- mIndicatorView.setIndicatorPosition(enableStepNo - STEP_1, mGroup.size());
- }
- }
}
diff --git a/java/src/com/android/inputmethod/latin/setup/SetupWizardActivity.java b/java/src/com/android/inputmethod/latin/setup/SetupWizardActivity.java
new file mode 100644
index 000000000..3406ecf34
--- /dev/null
+++ b/java/src/com/android/inputmethod/latin/setup/SetupWizardActivity.java
@@ -0,0 +1,466 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.inputmethod.latin.setup;
+
+import android.app.Activity;
+import android.content.ContentResolver;
+import android.content.Intent;
+import android.content.res.Resources;
+import android.media.MediaPlayer;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Message;
+import android.provider.Settings;
+import android.util.Log;
+import android.view.View;
+import android.view.inputmethod.InputMethodInfo;
+import android.widget.ImageView;
+import android.widget.TextView;
+import android.widget.VideoView;
+
+import com.android.inputmethod.compat.TextViewCompatUtils;
+import com.android.inputmethod.compat.ViewCompatUtils;
+import com.android.inputmethod.latin.CollectionUtils;
+import com.android.inputmethod.latin.R;
+import com.android.inputmethod.latin.RichInputMethodManager;
+import com.android.inputmethod.latin.SettingsActivity;
+import com.android.inputmethod.latin.StaticInnerHandlerWrapper;
+
+import java.util.ArrayList;
+
+// TODO: Use Fragment to implement welcome screen and setup steps.
+public final class SetupWizardActivity extends Activity implements View.OnClickListener {
+ static final String TAG = SetupWizardActivity.class.getSimpleName();
+
+ private View mSetupWizard;
+ private View mWelcomeScreen;
+ private View mSetupScreen;
+ private Uri mWelcomeVideoUri;
+ private VideoView mWelcomeVideoView;
+ private View mActionStart;
+ private View mActionNext;
+ private TextView mStep1Bullet;
+ private TextView mActionFinish;
+ private SetupStepGroup mSetupStepGroup;
+ private static final String STATE_STEP = "step";
+ private int mStepNumber;
+ private static final int STEP_WELCOME = 0;
+ private static final int STEP_1 = 1;
+ private static final int STEP_2 = 2;
+ private static final int STEP_3 = 3;
+ private static final int STEP_LAUNCHING_IME_SETTINGS = 4;
+ private static final int STEP_BACK_FROM_IME_SETTINGS = 5;
+
+ final SettingsPoolingHandler mHandler = new SettingsPoolingHandler(this);
+
+ static final class SettingsPoolingHandler
+ extends StaticInnerHandlerWrapper<SetupWizardActivity> {
+ private static final int MSG_POLLING_IME_SETTINGS = 0;
+ private static final long IME_SETTINGS_POLLING_INTERVAL = 200;
+
+ public SettingsPoolingHandler(final SetupWizardActivity outerInstance) {
+ super(outerInstance);
+ }
+
+ @Override
+ public void handleMessage(final Message msg) {
+ final SetupWizardActivity setupWizardActivity = getOuterInstance();
+ if (setupWizardActivity == null) {
+ return;
+ }
+ switch (msg.what) {
+ case MSG_POLLING_IME_SETTINGS:
+ if (SetupActivity.isThisImeEnabled(setupWizardActivity)) {
+ setupWizardActivity.invokeSetupWizardOfThisIme();
+ return;
+ }
+ startPollingImeSettings();
+ break;
+ }
+ }
+
+ public void startPollingImeSettings() {
+ sendMessageDelayed(obtainMessage(MSG_POLLING_IME_SETTINGS),
+ IME_SETTINGS_POLLING_INTERVAL);
+ }
+
+ public void cancelPollingImeSettings() {
+ removeMessages(MSG_POLLING_IME_SETTINGS);
+ }
+ }
+
+ @Override
+ protected void onCreate(final Bundle savedInstanceState) {
+ setTheme(android.R.style.Theme_Translucent_NoTitleBar);
+ super.onCreate(savedInstanceState);
+
+ setContentView(R.layout.setup_wizard);
+ mSetupWizard = findViewById(R.id.setup_wizard);
+
+ RichInputMethodManager.init(this);
+
+ if (savedInstanceState == null) {
+ mStepNumber = determineSetupStepNumberFromLauncher();
+ } else {
+ mStepNumber = savedInstanceState.getInt(STATE_STEP);
+ }
+
+ final String applicationName = getResources().getString(getApplicationInfo().labelRes);
+ mWelcomeScreen = findViewById(R.id.setup_welcome_screen);
+ final TextView welcomeTitle = (TextView)findViewById(R.id.setup_welcome_title);
+ welcomeTitle.setText(getString(R.string.setup_welcome_title, applicationName));
+
+ mSetupScreen = findViewById(R.id.setup_steps_screen);
+ final TextView stepsTitle = (TextView)findViewById(R.id.setup_title);
+ stepsTitle.setText(getString(R.string.setup_steps_title, applicationName));
+
+ final SetupStepIndicatorView indicatorView =
+ (SetupStepIndicatorView)findViewById(R.id.setup_step_indicator);
+ mSetupStepGroup = new SetupStepGroup(indicatorView);
+
+ mStep1Bullet = (TextView)findViewById(R.id.setup_step1_bullet);
+ mStep1Bullet.setOnClickListener(this);
+ final SetupStep step1 = new SetupStep(STEP_1, applicationName,
+ mStep1Bullet, findViewById(R.id.setup_step1),
+ R.string.setup_step1_title, R.string.setup_step1_instruction,
+ R.string.setup_step1_finished_instruction, R.drawable.ic_setup_step1,
+ R.string.setup_step1_action);
+ step1.setAction(new Runnable() {
+ @Override
+ public void run() {
+ invokeLanguageAndInputSettings();
+ mHandler.startPollingImeSettings();
+ }
+ });
+ mSetupStepGroup.addStep(step1);
+
+ final SetupStep step2 = new SetupStep(STEP_2, applicationName,
+ (TextView)findViewById(R.id.setup_step2_bullet), findViewById(R.id.setup_step2),
+ R.string.setup_step2_title, R.string.setup_step2_instruction,
+ 0 /* finishedInstruction */, R.drawable.ic_setup_step2,
+ R.string.setup_step2_action);
+ step2.setAction(new Runnable() {
+ @Override
+ public void run() {
+ // Invoke input method picker.
+ RichInputMethodManager.getInstance().getInputMethodManager()
+ .showInputMethodPicker();
+ }
+ });
+ mSetupStepGroup.addStep(step2);
+
+ final SetupStep step3 = new SetupStep(STEP_3, applicationName,
+ (TextView)findViewById(R.id.setup_step3_bullet), findViewById(R.id.setup_step3),
+ R.string.setup_step3_title, R.string.setup_step3_instruction,
+ 0 /* finishedInstruction */, R.drawable.ic_setup_step3,
+ R.string.setup_step3_action);
+ step3.setAction(new Runnable() {
+ @Override
+ public void run() {
+ invokeSubtypeEnablerOfThisIme();
+ }
+ });
+ mSetupStepGroup.addStep(step3);
+
+ mWelcomeVideoUri = new Uri.Builder()
+ .scheme(ContentResolver.SCHEME_ANDROID_RESOURCE)
+ .authority(getPackageName())
+ .path(Integer.toString(R.raw.setup_welcome_video))
+ .build();
+ final VideoView welcomeVideoView = (VideoView)findViewById(R.id.setup_welcome_video);
+ welcomeVideoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
+ @Override
+ public void onPrepared(final MediaPlayer mp) {
+ // Now VideoView has been laid-out and ready to play, remove background of it to
+ // reveal the video.
+ welcomeVideoView.setBackgroundResource(0);
+ mp.setLooping(true);
+ }
+ });
+ final ImageView welcomeImageView = (ImageView)findViewById(R.id.setup_welcome_image);
+ welcomeVideoView.setOnErrorListener(new MediaPlayer.OnErrorListener() {
+ @Override
+ public boolean onError(final MediaPlayer mp, final int what, final int extra) {
+ Log.e(TAG, "Playing welcome video causes error: what=" + what + " extra=" + extra);
+ welcomeVideoView.setVisibility(View.GONE);
+ welcomeImageView.setImageResource(R.raw.setup_welcome_image);
+ welcomeImageView.setVisibility(View.VISIBLE);
+ return true;
+ }
+ });
+ mWelcomeVideoView = welcomeVideoView;
+
+ mActionStart = findViewById(R.id.setup_start_label);
+ mActionStart.setOnClickListener(this);
+ mActionNext = findViewById(R.id.setup_next);
+ mActionNext.setOnClickListener(this);
+ mActionFinish = (TextView)findViewById(R.id.setup_finish);
+ TextViewCompatUtils.setCompoundDrawablesRelativeWithIntrinsicBounds(mActionFinish,
+ getResources().getDrawable(R.drawable.ic_setup_finish), null, null, null);
+ mActionFinish.setOnClickListener(this);
+ }
+
+ @Override
+ public void onClick(final View v) {
+ if (v == mActionFinish) {
+ finish();
+ return;
+ }
+ final int currentStep = determineSetupStepNumber();
+ final int nextStep;
+ if (v == mActionStart) {
+ nextStep = STEP_1;
+ } else if (v == mActionNext) {
+ nextStep = mStepNumber + 1;
+ } else if (v == mStep1Bullet && currentStep == STEP_2) {
+ nextStep = STEP_1;
+ } else {
+ nextStep = mStepNumber;
+ }
+ if (mStepNumber != nextStep) {
+ mStepNumber = nextStep;
+ updateSetupStepView();
+ }
+ }
+
+ void invokeSetupWizardOfThisIme() {
+ final Intent intent = new Intent();
+ intent.setClass(this, SetupWizardActivity.class);
+ intent.setFlags(Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
+ | Intent.FLAG_ACTIVITY_SINGLE_TOP
+ | Intent.FLAG_ACTIVITY_CLEAR_TOP);
+ startActivity(intent);
+ }
+
+ private void invokeSettingsOfThisIme() {
+ final Intent intent = new Intent();
+ intent.setClass(this, SettingsActivity.class);
+ intent.setFlags(Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
+ | Intent.FLAG_ACTIVITY_CLEAR_TOP);
+ startActivity(intent);
+ }
+
+ void invokeLanguageAndInputSettings() {
+ final Intent intent = new Intent();
+ intent.setAction(Settings.ACTION_INPUT_METHOD_SETTINGS);
+ intent.addCategory(Intent.CATEGORY_DEFAULT);
+ startActivity(intent);
+ }
+
+ void invokeSubtypeEnablerOfThisIme() {
+ final InputMethodInfo imi =
+ RichInputMethodManager.getInstance().getInputMethodInfoOfThisIme();
+ final Intent intent = new Intent();
+ intent.setAction(Settings.ACTION_INPUT_METHOD_SUBTYPE_SETTINGS);
+ intent.addCategory(Intent.CATEGORY_DEFAULT);
+ intent.putExtra(Settings.EXTRA_INPUT_METHOD_ID, imi.getId());
+ startActivity(intent);
+ }
+
+ private int determineSetupStepNumberFromLauncher() {
+ final int stepNumber = determineSetupStepNumber();
+ if (stepNumber == STEP_1) {
+ return STEP_WELCOME;
+ }
+ if (stepNumber == STEP_3) {
+ return STEP_LAUNCHING_IME_SETTINGS;
+ }
+ return stepNumber;
+ }
+
+ private int determineSetupStepNumber() {
+ mHandler.cancelPollingImeSettings();
+ if (!SetupActivity.isThisImeEnabled(this)) {
+ return STEP_1;
+ }
+ if (!SetupActivity.isThisImeCurrent(this)) {
+ return STEP_2;
+ }
+ return STEP_3;
+ }
+
+ @Override
+ protected void onSaveInstanceState(final Bundle outState) {
+ super.onSaveInstanceState(outState);
+ outState.putInt(STATE_STEP, mStepNumber);
+ }
+
+ @Override
+ protected void onRestoreInstanceState(final Bundle savedInstanceState) {
+ super.onRestoreInstanceState(savedInstanceState);
+ mStepNumber = savedInstanceState.getInt(STATE_STEP);
+ }
+
+ private static boolean isInSetupSteps(final int stepNumber) {
+ return stepNumber >= STEP_1 && stepNumber <= STEP_3;
+ }
+
+ @Override
+ protected void onRestart() {
+ super.onRestart();
+ if (isInSetupSteps(mStepNumber)) {
+ mStepNumber = determineSetupStepNumber();
+ }
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ if (mStepNumber == STEP_LAUNCHING_IME_SETTINGS) {
+ // Prevent white screen flashing while launching settings activity.
+ mSetupWizard.setVisibility(View.INVISIBLE);
+ invokeSettingsOfThisIme();
+ mStepNumber = STEP_BACK_FROM_IME_SETTINGS;
+ return;
+ }
+ if (mStepNumber == STEP_BACK_FROM_IME_SETTINGS) {
+ finish();
+ return;
+ }
+ updateSetupStepView();
+ }
+
+ @Override
+ public void onBackPressed() {
+ if (mStepNumber == STEP_1) {
+ mStepNumber = STEP_WELCOME;
+ updateSetupStepView();
+ return;
+ }
+ super.onBackPressed();
+ }
+
+ private static void hideAndStopVideo(final VideoView videoView) {
+ videoView.stopPlayback();
+ videoView.setVisibility(View.INVISIBLE);
+ }
+
+ @Override
+ protected void onPause() {
+ hideAndStopVideo(mWelcomeVideoView);
+ super.onPause();
+ }
+
+ @Override
+ public void onWindowFocusChanged(final boolean hasFocus) {
+ super.onWindowFocusChanged(hasFocus);
+ if (hasFocus && isInSetupSteps(mStepNumber)) {
+ mStepNumber = determineSetupStepNumber();
+ updateSetupStepView();
+ }
+ }
+
+ private void updateSetupStepView() {
+ mSetupWizard.setVisibility(View.VISIBLE);
+ final boolean welcomeScreen = (mStepNumber == STEP_WELCOME);
+ mWelcomeScreen.setVisibility(welcomeScreen ? View.VISIBLE : View.GONE);
+ mSetupScreen.setVisibility(welcomeScreen ? View.GONE : View.VISIBLE);
+ if (welcomeScreen) {
+ mWelcomeVideoView.setVisibility(View.VISIBLE);
+ mWelcomeVideoView.setVideoURI(mWelcomeVideoUri);
+ mWelcomeVideoView.start();
+ return;
+ }
+ hideAndStopVideo(mWelcomeVideoView);
+ final boolean isStepActionAlreadyDone = mStepNumber < determineSetupStepNumber();
+ mSetupStepGroup.enableStep(mStepNumber, isStepActionAlreadyDone);
+ mActionNext.setVisibility(isStepActionAlreadyDone ? View.VISIBLE : View.GONE);
+ mActionFinish.setVisibility((mStepNumber == STEP_3) ? View.VISIBLE : View.GONE);
+ }
+
+ static final class SetupStep implements View.OnClickListener {
+ public final int mStepNo;
+ private final View mStepView;
+ private final TextView mBulletView;
+ private final int mActivatedColor;
+ private final int mDeactivatedColor;
+ private final String mInstruction;
+ private final String mFinishedInstruction;
+ private final TextView mActionLabel;
+ private Runnable mAction;
+
+ public SetupStep(final int stepNo, final String applicationName, final TextView bulletView,
+ final View stepView, final int title, final int instruction,
+ final int finishedInstruction, final int actionIcon, final int actionLabel) {
+ mStepNo = stepNo;
+ mStepView = stepView;
+ mBulletView = bulletView;
+ final Resources res = stepView.getResources();
+ mActivatedColor = res.getColor(R.color.setup_text_action);
+ mDeactivatedColor = res.getColor(R.color.setup_text_dark);
+
+ final TextView titleView = (TextView)mStepView.findViewById(R.id.setup_step_title);
+ titleView.setText(res.getString(title, applicationName));
+ mInstruction = (instruction == 0) ? null
+ : res.getString(instruction, applicationName);
+ mFinishedInstruction = (finishedInstruction == 0) ? null
+ : res.getString(finishedInstruction, applicationName);
+
+ mActionLabel = (TextView)mStepView.findViewById(R.id.setup_step_action_label);
+ mActionLabel.setText(res.getString(actionLabel));
+ if (actionIcon == 0) {
+ final int paddingEnd = ViewCompatUtils.getPaddingEnd(mActionLabel);
+ ViewCompatUtils.setPaddingRelative(mActionLabel, paddingEnd, 0, paddingEnd, 0);
+ } else {
+ TextViewCompatUtils.setCompoundDrawablesRelativeWithIntrinsicBounds(
+ mActionLabel, res.getDrawable(actionIcon), null, null, null);
+ }
+ }
+
+ public void setEnabled(final boolean enabled, final boolean isStepActionAlreadyDone) {
+ mStepView.setVisibility(enabled ? View.VISIBLE : View.GONE);
+ mBulletView.setTextColor(enabled ? mActivatedColor : mDeactivatedColor);
+ final TextView instructionView = (TextView)mStepView.findViewById(
+ R.id.setup_step_instruction);
+ instructionView.setText(isStepActionAlreadyDone ? mFinishedInstruction : mInstruction);
+ mActionLabel.setVisibility(isStepActionAlreadyDone ? View.GONE : View.VISIBLE);
+ }
+
+ public void setAction(final Runnable action) {
+ mActionLabel.setOnClickListener(this);
+ mAction = action;
+ }
+
+ @Override
+ public void onClick(final View v) {
+ if (v == mActionLabel && mAction != null) {
+ mAction.run();
+ return;
+ }
+ }
+ }
+
+ static final class SetupStepGroup {
+ private final SetupStepIndicatorView mIndicatorView;
+ private final ArrayList<SetupStep> mGroup = CollectionUtils.newArrayList();
+
+ public SetupStepGroup(final SetupStepIndicatorView indicatorView) {
+ mIndicatorView = indicatorView;
+ }
+
+ public void addStep(final SetupStep step) {
+ mGroup.add(step);
+ }
+
+ public void enableStep(final int enableStepNo, final boolean isStepActionAlreadyDone) {
+ for (final SetupStep step : mGroup) {
+ step.setEnabled(step.mStepNo == enableStepNo, isStepActionAlreadyDone);
+ }
+ mIndicatorView.setIndicatorPosition(enableStepNo - STEP_1, mGroup.size());
+ }
+ }
+}
diff --git a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java
index aa60496ae..13fcaf48a 100644
--- a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java
+++ b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java
@@ -23,7 +23,7 @@ import android.service.textservice.SpellCheckerService;
import android.util.Log;
import android.view.textservice.SuggestionsInfo;
-import com.android.inputmethod.keyboard.ProximityInfo;
+import com.android.inputmethod.keyboard.KeyboardLayoutSet;
import com.android.inputmethod.latin.BinaryDictionary;
import com.android.inputmethod.latin.CollectionUtils;
import com.android.inputmethod.latin.ContactsBinaryDictionary;
@@ -126,6 +126,19 @@ public final class AndroidSpellCheckerService extends SpellCheckerService
return script;
}
+ private static String getKeyboardLayoutNameForScript(final int script) {
+ switch (script) {
+ case AndroidSpellCheckerService.SCRIPT_LATIN:
+ return "qwerty";
+ case AndroidSpellCheckerService.SCRIPT_CYRILLIC:
+ return "east_slavic";
+ case AndroidSpellCheckerService.SCRIPT_GREEK:
+ return "greek";
+ default:
+ throw new RuntimeException("Wrong script supplied: " + script);
+ }
+ }
+
@Override
public void onSharedPreferenceChanged(final SharedPreferences prefs, final String key) {
if (!PREF_USE_CONTACTS_KEY.equals(key)) return;
@@ -385,9 +398,13 @@ public final class AndroidSpellCheckerService extends SpellCheckerService
return pool;
}
- public DictAndProximity createDictAndProximity(final Locale locale) {
+ public DictAndKeyboard createDictAndKeyboard(final Locale locale) {
final int script = getScriptFromLocale(locale);
- final ProximityInfo proximityInfo = new SpellCheckerProximityInfo(script);
+ final String keyboardLayoutName = getKeyboardLayoutNameForScript(script);
+ final KeyboardLayoutSet keyboardLayoutSet =
+ KeyboardLayoutSet.createKeyboardSetForSpellChecker(this, locale.toString(),
+ keyboardLayoutName);
+
final DictionaryCollection dictionaryCollection =
DictionaryFactory.createMainDictionaryFromManager(this, locale,
true /* useFullEditDistance */);
@@ -412,6 +429,6 @@ public final class AndroidSpellCheckerService extends SpellCheckerService
mDictionaryCollectionsList.add(
new WeakReference<DictionaryCollection>(dictionaryCollection));
}
- return new DictAndProximity(dictionaryCollection, proximityInfo);
+ return new DictAndKeyboard(dictionaryCollection, keyboardLayoutSet);
}
}
diff --git a/java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java b/java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java
index 61850e42e..16e9fb77e 100644
--- a/java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java
+++ b/java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java
@@ -257,7 +257,7 @@ public abstract class AndroidWordLevelSpellCheckerSession extends Session {
}
if (shouldFilterOut(inText, mScript)) {
- DictAndProximity dictInfo = null;
+ DictAndKeyboard dictInfo = null;
try {
dictInfo = mDictionaryPool.pollWithDefaultTimeout();
if (!DictionaryPool.isAValidDictionary(dictInfo)) {
@@ -286,7 +286,7 @@ public abstract class AndroidWordLevelSpellCheckerSession extends Session {
final int capitalizeType = StringUtils.getCapitalizationType(text);
boolean isInDict = true;
- DictAndProximity dictInfo = null;
+ DictAndKeyboard dictInfo = null;
try {
dictInfo = mDictionaryPool.pollWithDefaultTimeout();
if (!DictionaryPool.isAValidDictionary(dictInfo)) {
@@ -296,20 +296,13 @@ public abstract class AndroidWordLevelSpellCheckerSession extends Session {
final int length = text.length();
for (int i = 0; i < length; i = text.offsetByCodePoints(i, 1)) {
final int codePoint = text.codePointAt(i);
- // The getXYForCodePointAndScript method returns (Y << 16) + X
- final int xy = SpellCheckerProximityInfo.getXYForCodePointAndScript(
- codePoint, mScript);
- if (SpellCheckerProximityInfo.NOT_A_COORDINATE_PAIR == xy) {
- composer.add(codePoint,
- Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE);
- } else {
- composer.add(codePoint, xy & 0xFFFF, xy >> 16);
- }
+ composer.addKeyInfo(codePoint, dictInfo.getKeyboard(codePoint));
}
// TODO: make a spell checker option to block offensive words or not
final ArrayList<SuggestedWordInfo> suggestions =
dictInfo.mDictionary.getSuggestions(composer, prevWord,
- dictInfo.mProximityInfo, true /* blockOffensiveWords */);
+ dictInfo.getProximityInfo(),
+ true /* blockOffensiveWords */);
for (final SuggestedWordInfo suggestion : suggestions) {
final String suggestionStr = suggestion.mWord;
suggestionsGatherer.addWord(suggestionStr.toCharArray(), null, 0,
diff --git a/java/src/com/android/inputmethod/latin/spellcheck/DictAndKeyboard.java b/java/src/com/android/inputmethod/latin/spellcheck/DictAndKeyboard.java
new file mode 100644
index 000000000..b77f3e2c5
--- /dev/null
+++ b/java/src/com/android/inputmethod/latin/spellcheck/DictAndKeyboard.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2011 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.spellcheck;
+
+import com.android.inputmethod.latin.Dictionary;
+import com.android.inputmethod.keyboard.Keyboard;
+import com.android.inputmethod.keyboard.KeyboardId;
+import com.android.inputmethod.keyboard.KeyboardLayoutSet;
+import com.android.inputmethod.keyboard.ProximityInfo;
+
+/**
+ * A container for a Dictionary and a Keyboard.
+ */
+public final class DictAndKeyboard {
+ public final Dictionary mDictionary;
+ private final Keyboard mKeyboard;
+ private final Keyboard mManualShiftedKeyboard;
+
+ public DictAndKeyboard(
+ final Dictionary dictionary, final KeyboardLayoutSet keyboardLayoutSet) {
+ mDictionary = dictionary;
+ if (keyboardLayoutSet == null) {
+ mKeyboard = null;
+ mManualShiftedKeyboard = null;
+ return;
+ }
+ mKeyboard = keyboardLayoutSet.getKeyboard(KeyboardId.ELEMENT_ALPHABET);
+ mManualShiftedKeyboard =
+ keyboardLayoutSet.getKeyboard(KeyboardId.ELEMENT_ALPHABET_MANUAL_SHIFTED);
+ }
+
+ public Keyboard getKeyboard(final int codePoint) {
+ if (mKeyboard == null) {
+ return null;
+ }
+ return mKeyboard.getKey(codePoint) != null ? mKeyboard : mManualShiftedKeyboard;
+ }
+
+ public ProximityInfo getProximityInfo() {
+ return mKeyboard == null ? null : mKeyboard.getProximityInfo();
+ }
+}
diff --git a/java/src/com/android/inputmethod/latin/spellcheck/DictAndProximity.java b/java/src/com/android/inputmethod/latin/spellcheck/DictAndProximity.java
deleted file mode 100644
index 017a4f555..000000000
--- a/java/src/com/android/inputmethod/latin/spellcheck/DictAndProximity.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (C) 2011 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.spellcheck;
-
-import com.android.inputmethod.latin.Dictionary;
-import com.android.inputmethod.keyboard.ProximityInfo;
-
-/**
- * A simple container for both a Dictionary and a ProximityInfo.
- */
-public final class DictAndProximity {
- public final Dictionary mDictionary;
- public final ProximityInfo mProximityInfo;
- public DictAndProximity(final Dictionary dictionary, final ProximityInfo proximityInfo) {
- mDictionary = dictionary;
- mProximityInfo = proximityInfo;
- }
-}
diff --git a/java/src/com/android/inputmethod/latin/spellcheck/DictionaryPool.java b/java/src/com/android/inputmethod/latin/spellcheck/DictionaryPool.java
index 27964b3c6..a20e09ee8 100644
--- a/java/src/com/android/inputmethod/latin/spellcheck/DictionaryPool.java
+++ b/java/src/com/android/inputmethod/latin/spellcheck/DictionaryPool.java
@@ -36,7 +36,7 @@ import java.util.concurrent.TimeUnit;
* the client code, but may help with sloppy clients.
*/
@SuppressWarnings("serial")
-public final class DictionaryPool extends LinkedBlockingQueue<DictAndProximity> {
+public final class DictionaryPool extends LinkedBlockingQueue<DictAndKeyboard> {
private final static String TAG = DictionaryPool.class.getSimpleName();
// How many seconds we wait for a dictionary to become available. Past this delay, we give up in
// fear some bug caused a deadlock, and reset the whole pool.
@@ -47,7 +47,7 @@ public final class DictionaryPool extends LinkedBlockingQueue<DictAndProximity>
private int mSize;
private volatile boolean mClosed;
final static ArrayList<SuggestedWordInfo> noSuggestions = CollectionUtils.newArrayList();
- private final static DictAndProximity dummyDict = new DictAndProximity(
+ private final static DictAndKeyboard dummyDict = new DictAndKeyboard(
new Dictionary(Dictionary.TYPE_MAIN) {
@Override
public ArrayList<SuggestedWordInfo> getSuggestions(final WordComposer composer,
@@ -64,7 +64,7 @@ public final class DictionaryPool extends LinkedBlockingQueue<DictAndProximity>
}
}, null);
- static public boolean isAValidDictionary(final DictAndProximity dictInfo) {
+ static public boolean isAValidDictionary(final DictAndKeyboard dictInfo) {
return null != dictInfo && dummyDict != dictInfo;
}
@@ -79,32 +79,32 @@ public final class DictionaryPool extends LinkedBlockingQueue<DictAndProximity>
}
@Override
- public DictAndProximity poll(final long timeout, final TimeUnit unit)
+ public DictAndKeyboard poll(final long timeout, final TimeUnit unit)
throws InterruptedException {
- final DictAndProximity dict = poll();
+ final DictAndKeyboard dict = poll();
if (null != dict) return dict;
synchronized(this) {
if (mSize >= mMaxSize) {
// Our pool is already full. Wait until some dictionary is ready, or TIMEOUT
// expires to avoid a deadlock.
- final DictAndProximity result = super.poll(timeout, unit);
+ final DictAndKeyboard result = super.poll(timeout, unit);
if (null == result) {
Log.e(TAG, "Deadlock detected ! Resetting dictionary pool");
clear();
mSize = 1;
- return mService.createDictAndProximity(mLocale);
+ return mService.createDictAndKeyboard(mLocale);
} else {
return result;
}
} else {
++mSize;
- return mService.createDictAndProximity(mLocale);
+ return mService.createDictAndKeyboard(mLocale);
}
}
}
// Convenience method
- public DictAndProximity pollWithDefaultTimeout() {
+ public DictAndKeyboard pollWithDefaultTimeout() {
try {
return poll(TIMEOUT, TimeUnit.SECONDS);
} catch (InterruptedException e) {
@@ -115,7 +115,7 @@ public final class DictionaryPool extends LinkedBlockingQueue<DictAndProximity>
public void close() {
synchronized(this) {
mClosed = true;
- for (DictAndProximity dict : this) {
+ for (DictAndKeyboard dict : this) {
dict.mDictionary.close();
}
clear();
@@ -123,7 +123,7 @@ public final class DictionaryPool extends LinkedBlockingQueue<DictAndProximity>
}
@Override
- public boolean offer(final DictAndProximity dict) {
+ public boolean offer(final DictAndKeyboard dict) {
if (mClosed) {
dict.mDictionary.close();
return super.offer(dummyDict);
diff --git a/java/src/com/android/inputmethod/latin/spellcheck/SpellCheckerProximityInfo.java b/java/src/com/android/inputmethod/latin/spellcheck/SpellCheckerProximityInfo.java
deleted file mode 100644
index 0c480eaba..000000000
--- a/java/src/com/android/inputmethod/latin/spellcheck/SpellCheckerProximityInfo.java
+++ /dev/null
@@ -1,462 +0,0 @@
-/*
- * Copyright (C) 2011 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.spellcheck;
-
-import android.util.SparseIntArray;
-
-import com.android.inputmethod.keyboard.ProximityInfo;
-import com.android.inputmethod.latin.Constants;
-
-public final class SpellCheckerProximityInfo extends ProximityInfo {
- public SpellCheckerProximityInfo(final int script) {
- super(getProximityForScript(script), PROXIMITY_GRID_WIDTH, PROXIMITY_GRID_HEIGHT);
- }
-
- private static final int NUL = Constants.NOT_A_CODE;
-
- // This must be the same as MAX_PROXIMITY_CHARS_SIZE else it will not work inside
- // native code - this value is passed at creation of the binary object and reused
- // as the size of the passed array afterwards so they can't be different.
- private static final int ROW_SIZE = ProximityInfo.MAX_PROXIMITY_CHARS_SIZE;
-
- // The number of keys in a row of the grid used by the spell checker.
- private static final int PROXIMITY_GRID_WIDTH = 11;
- // The number of rows in the grid used by the spell checker.
- private static final int PROXIMITY_GRID_HEIGHT = 3;
-
- private static final int NOT_AN_INDEX = -1;
- public static final int NOT_A_COORDINATE_PAIR = -1;
-
- // Helper methods
- static void buildProximityIndices(final int[] proximity, final int rowSize,
- final SparseIntArray indices) {
- for (int i = 0; i < proximity.length; i += rowSize) {
- if (NUL != proximity[i]) indices.put(proximity[i], i / rowSize);
- }
- }
-
- private static final class Latin {
- // The proximity here is the union of
- // - the proximity for a QWERTY keyboard.
- // - the proximity for an AZERTY keyboard.
- // - the proximity for a QWERTZ keyboard.
- // ...plus, add all characters in the ('a', 'e', 'i', 'o', 'u') set to each other.
- //
- // The reasoning behind this construction is, almost any alphabetic text we may want
- // to spell check has been entered with one of the keyboards above. Also, specifically
- // to English, many spelling errors consist of the last vowel of the word being wrong
- // because in English vowels tend to merge with each other in pronunciation.
- /*
- The Qwerty layout this represents looks like the following:
- q w e r t y u i o p
- a s d f g h j k l
- z x c v b n m
- */
- static final int[] PROXIMITY = {
- // Proximity for row 1. This must have exactly ROW_SIZE entries for each letter,
- // and exactly PROXIMITY_GRID_WIDTH letters for a row. Pad with NUL's.
- // The number of rows must be exactly PROXIMITY_GRID_HEIGHT.
- 'q', 'w', 's', 'a', 'z', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- 'w', 'q', 'a', 's', 'd', 'e', 'x', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- 'e', 'w', 's', 'd', 'f', 'r', 'a', 'i', 'o', 'u', NUL, NUL, NUL, NUL, NUL, NUL,
- 'r', 'e', 'd', 'f', 'g', 't', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- 't', 'r', 'f', 'g', 'h', 'y', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- 'y', 't', 'g', 'h', 'j', 'u', 'a', 's', 'd', 'x', NUL, NUL, NUL, NUL, NUL, NUL,
- 'u', 'y', 'h', 'j', 'k', 'i', 'a', 'e', 'o', NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- 'i', 'u', 'j', 'k', 'l', 'o', 'a', 'e', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- 'o', 'i', 'k', 'l', 'p', 'a', 'e', 'u', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- 'p', 'o', 'l', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-
- // Proximity for row 2. See comment above about size.
- 'a', 'z', 'x', 's', 'w', 'q', 'e', 'i', 'o', 'u', NUL, NUL, NUL, NUL, NUL, NUL,
- 's', 'q', 'a', 'z', 'x', 'c', 'd', 'e', 'w', NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- 'd', 'w', 's', 'x', 'c', 'v', 'f', 'r', 'e', NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- 'f', 'e', 'd', 'c', 'v', 'b', 'g', 't', 'r', NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- 'g', 'r', 'f', 'v', 'b', 'n', 'h', 'y', 't', NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- 'h', 't', 'g', 'b', 'n', 'm', 'j', 'u', 'y', NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- 'j', 'y', 'h', 'n', 'm', 'k', 'i', 'u', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- 'k', 'u', 'j', 'm', 'l', 'o', 'i', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- 'l', 'i', 'k', 'p', 'o', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-
- // Proximity for row 3. See comment above about size.
- 'z', 'a', 's', 'd', 'x', 't', 'g', 'h', 'j', 'u', 'q', 'e', NUL, NUL, NUL, NUL,
- 'x', 'z', 'a', 's', 'd', 'c', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- 'c', 'x', 's', 'd', 'f', 'v', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- 'v', 'c', 'd', 'f', 'g', 'b', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- 'b', 'v', 'f', 'g', 'h', 'n', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- 'n', 'b', 'g', 'h', 'j', 'm', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- 'm', 'n', 'h', 'j', 'k', 'l', 'o', 'p', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- };
-
- // This is a mapping array from the code point to the index in the PROXIMITY array.
- // When we check the spelling of a word, we need to pass (x,y) coordinates to the native
- // code for each letter of the word. These are most easily computed from the index in the
- // PROXIMITY array. Since we'll need to do that very often, the index lookup from the code
- // point needs to be as fast as possible, and a map is probably the best way to do this.
- // To avoid unnecessary boxing conversion to Integer, here we use SparseIntArray.
- static final SparseIntArray INDICES = new SparseIntArray(PROXIMITY.length / ROW_SIZE);
-
- static {
- buildProximityIndices(PROXIMITY, ROW_SIZE, INDICES);
- }
- }
-
- private static final class Cyrillic {
- // TODO: The following table is solely based on the keyboard layout. Consult with Russian
- // speakers on commonly misspelled words/letters.
- /*
- The Russian layout this represents looks like the following:
- й ц у к е н г ш щ з х
- ф ы в а п р о л д ж э
- я ч с м и т ь б ю
-
- This gives us the following table:
- 'й', 'ц', 'ф', 'ы', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- 'ц', 'й', 'ф', 'ы', 'в', 'у', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- 'у', 'ц', 'ы', 'в', 'а', 'к', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- 'к', 'у', 'в', 'а', 'п', 'е', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- 'е', 'к', 'а', 'п', 'р', 'н', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- 'н', 'е', 'п', 'р', 'о', 'г', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- 'г', 'н', 'р', 'о', 'л', 'ш', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- 'ш', 'г', 'о', 'л', 'д', 'щ', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- 'щ', 'ш', 'л', 'д', 'ж', 'з', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- 'з', 'щ', 'д', 'ж', 'э', 'х', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- 'х', 'з', 'ж', 'э', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-
- 'ф', 'й', 'ц', 'ы', 'я', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- 'ы', 'й', 'ц', 'у', 'ф', 'в', 'я', 'ч', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- 'в', 'ц', 'у', 'к', 'ы', 'а', 'я', 'ч', 'с', NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- 'а', 'у', 'к', 'е', 'в', 'п', 'ч', 'с', 'м', NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- 'п', 'к', 'е', 'н', 'а', 'р', 'с', 'м', 'и', NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- 'р', 'е', 'н', 'г', 'п', 'о', 'м', 'и', 'т', NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- 'о', 'н', 'г', 'ш', 'р', 'л', 'и', 'т', 'ь', NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- 'л', 'г', 'ш', 'щ', 'о', 'д', 'т', 'ь', 'б', NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- 'д', 'ш', 'щ', 'з', 'л', 'ж', 'ь', 'б', 'ю', NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- 'ж', 'щ', 'з', 'х', 'д', 'э', 'б', 'ю', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- 'э', 'з', 'х', 'ю', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-
- 'я', 'ф', 'ы', 'в', 'ч', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- 'ч', 'ы', 'в', 'а', 'я', 'с', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- 'с', 'в', 'а', 'п', 'ч', 'м', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- 'м', 'а', 'п', 'р', 'с', 'и', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- 'и', 'п', 'р', 'о', 'м', 'т', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- 'т', 'р', 'о', 'л', 'и', 'ь', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- 'ь', 'о', 'л', 'д', 'т', 'б', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- 'б', 'л', 'д', 'ж', 'ь', 'ю', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- 'ю', 'д', 'ж', 'э', 'б', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-
- Using the following characters:
- */
- private static final int CY_SHORT_I = '\u0439'; // й
- private static final int CY_TSE = '\u0446'; // ц
- private static final int CY_U = '\u0443'; // у
- private static final int CY_KA = '\u043A'; // к
- private static final int CY_IE = '\u0435'; // е
- private static final int CY_EN = '\u043D'; // н
- private static final int CY_GHE = '\u0433'; // г
- private static final int CY_SHA = '\u0448'; // ш
- private static final int CY_SHCHA = '\u0449'; // щ
- private static final int CY_ZE = '\u0437'; // з
- private static final int CY_HA = '\u0445'; // х
- private static final int CY_EF = '\u0444'; // ф
- private static final int CY_YERU = '\u044B'; // ы
- private static final int CY_VE = '\u0432'; // в
- private static final int CY_A = '\u0430'; // а
- private static final int CY_PE = '\u043F'; // п
- private static final int CY_ER = '\u0440'; // р
- private static final int CY_O = '\u043E'; // о
- private static final int CY_EL = '\u043B'; // л
- private static final int CY_DE = '\u0434'; // д
- private static final int CY_ZHE = '\u0436'; // ж
- private static final int CY_E = '\u044D'; // э
- private static final int CY_YA = '\u044F'; // я
- private static final int CY_CHE = '\u0447'; // ч
- private static final int CY_ES = '\u0441'; // с
- private static final int CY_EM = '\u043C'; // м
- private static final int CY_I = '\u0438'; // и
- private static final int CY_TE = '\u0442'; // т
- private static final int CY_SOFT_SIGN = '\u044C'; // ь
- private static final int CY_BE = '\u0431'; // б
- private static final int CY_YU = '\u044E'; // ю
- static final int[] PROXIMITY = {
- // Proximity for row 1. This must have exactly ROW_SIZE entries for each letter,
- // and exactly PROXIMITY_GRID_WIDTH letters for a row. Pad with NUL's.
- // The number of rows must be exactly PROXIMITY_GRID_HEIGHT.
- CY_SHORT_I, CY_TSE, CY_EF, CY_YERU, NUL, NUL, NUL, NUL,
- NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- CY_TSE, CY_SHORT_I, CY_EF, CY_YERU, CY_VE, CY_U, NUL, NUL,
- NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- CY_U, CY_TSE, CY_YERU, CY_VE, CY_A, CY_KA, NUL, NUL,
- NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- CY_KA, CY_U, CY_VE, CY_A, CY_PE, CY_IE, NUL, NUL,
- NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- CY_IE, CY_KA, CY_A, CY_PE, CY_ER, CY_EN, NUL, NUL,
- NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- CY_EN, CY_IE, CY_PE, CY_ER, CY_O, CY_GHE, NUL, NUL,
- NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- CY_GHE, CY_EN, CY_ER, CY_O, CY_EL, CY_SHA, NUL, NUL,
- NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- CY_SHA, CY_GHE, CY_O, CY_EL, CY_DE, CY_SHCHA, NUL, NUL,
- NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- CY_SHCHA, CY_SHA, CY_EL, CY_DE, CY_ZHE, CY_ZE, NUL, NUL,
- NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- CY_ZE, CY_SHCHA, CY_DE, CY_ZHE, CY_E, CY_HA, NUL, NUL,
- NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- CY_HA, CY_ZE, CY_ZHE, CY_E, NUL, NUL, NUL, NUL,
- NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-
- // Proximity for row 2. See comment above about size.
- CY_EF, CY_SHORT_I, CY_TSE, CY_YERU, CY_YA, NUL, NUL, NUL,
- NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- CY_YERU, CY_SHORT_I, CY_TSE, CY_U, CY_EF, CY_VE, CY_YA, CY_CHE,
- NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- CY_VE, CY_TSE, CY_U, CY_KA, CY_YERU, CY_A, CY_YA, CY_CHE,
- CY_ES, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- CY_A, CY_U, CY_KA, CY_IE, CY_VE, CY_PE, CY_CHE, CY_ES,
- CY_EM, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- CY_PE, CY_KA, CY_IE, CY_EN, CY_A, CY_ER, CY_ES, CY_EM,
- CY_I, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- CY_ER, CY_IE, CY_EN, CY_GHE, CY_PE, CY_O, CY_EM, CY_I,
- CY_TE, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- CY_O, CY_EN, CY_GHE, CY_SHA, CY_ER, CY_EL, CY_I, CY_TE,
- CY_SOFT_SIGN, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- CY_EL, CY_GHE, CY_SHA, CY_SHCHA, CY_O, CY_DE, CY_TE, CY_SOFT_SIGN,
- CY_BE, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- CY_DE, CY_SHA, CY_SHCHA, CY_ZE, CY_EL, CY_ZHE, CY_SOFT_SIGN, CY_BE,
- CY_YU, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- CY_ZHE, CY_SHCHA, CY_ZE, CY_HA, CY_DE, CY_E, CY_BE, CY_YU,
- NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- CY_E, CY_ZE, CY_HA, CY_YU, NUL, NUL, NUL, NUL,
- NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-
- // Proximity for row 3. See comment above about size.
- CY_YA, CY_EF, CY_YERU, CY_VE, CY_CHE, NUL, NUL, NUL,
- NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- CY_CHE, CY_YERU, CY_VE, CY_A, CY_YA, CY_ES, NUL, NUL,
- NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- CY_ES, CY_VE, CY_A, CY_PE, CY_CHE, CY_EM, NUL, NUL,
- NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- CY_EM, CY_A, CY_PE, CY_ER, CY_ES, CY_I, NUL, NUL,
- NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- CY_I, CY_PE, CY_ER, CY_O, CY_EM, CY_TE, NUL, NUL,
- NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- CY_TE, CY_ER, CY_O, CY_EL, CY_I, CY_SOFT_SIGN, NUL, NUL,
- NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- CY_SOFT_SIGN, CY_O, CY_EL, CY_DE, CY_TE, CY_BE, NUL, NUL,
- NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- CY_BE, CY_EL, CY_DE, CY_ZHE, CY_SOFT_SIGN, CY_YU, NUL, NUL,
- NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- CY_YU, CY_DE, CY_ZHE, CY_E, CY_BE, NUL, NUL, NUL,
- NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- };
-
- static final SparseIntArray INDICES = new SparseIntArray(PROXIMITY.length / ROW_SIZE);
-
- static {
- buildProximityIndices(PROXIMITY, ROW_SIZE, INDICES);
- }
- }
-
- private static final class Greek {
- // TODO: The following table is solely based on the keyboard layout. Consult with Greek
- // speakers on commonly misspelled words/letters.
- /*
- The Greek layout this represents looks like the following:
- ; ς ε ρ τ υ θ ι ο π
- α σ δ φ γ η ξ κ λ
- ζ χ ψ ω β ν μ
-
- This gives us the following table:
- 'ς', 'ε', 'α', 'σ', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- 'ε', 'ς', 'ρ', 'σ', 'δ', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- 'ρ', 'ε', 'τ', 'δ', 'φ', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- 'τ', 'ρ', 'υ', 'φ', 'γ', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- 'υ', 'τ', 'θ', 'γ', 'η', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- 'θ', 'υ', 'ι', 'η', 'ξ', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- 'ι', 'θ', 'ο', 'ξ', 'κ', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- 'ο', 'ι', 'π', 'κ', 'λ', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- 'π', 'ο', 'λ', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-
- 'α', 'ς', 'σ', 'ζ', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- 'σ', 'ς', 'ε', 'α', 'δ', 'ζ', 'χ', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- 'δ', 'ε', 'ρ', 'σ', 'φ', 'ζ', 'χ', 'ψ', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- 'φ', 'ρ', 'τ', 'δ', 'γ', 'χ', 'ψ', 'ω', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- 'γ', 'τ', 'υ', 'φ', 'η', 'ψ', 'ω', 'β', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- 'η', 'υ', 'θ', 'γ', 'ξ', 'ω', 'β', 'ν', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- 'ξ', 'θ', 'ι', 'η', 'κ', 'β', 'ν', 'μ', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- 'κ', 'ι', 'ο', 'ξ', 'λ', 'ν', 'μ', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- 'λ', 'ο', 'π', 'κ', 'μ', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-
- 'ζ', 'α', 'σ', 'δ', 'χ', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- 'χ', 'σ', 'δ', 'φ', 'ζ', 'ψ', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- 'ψ', 'δ', 'φ', 'γ', 'χ', 'ω', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- 'ω', 'φ', 'γ', 'η', 'ψ', 'β', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- 'β', 'γ', 'η', 'ξ', 'ω', 'ν', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- 'ν', 'η', 'ξ', 'κ', 'β', 'μ', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- 'μ', 'ξ', 'κ', 'λ', 'ν', NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-
- Using the following characters:
- */
- private static final int GR_FINAL_SIGMA = '\u03C2'; // ς
- private static final int GR_EPSILON = '\u03B5'; // ε
- private static final int GR_RHO = '\u03C1'; // ρ
- private static final int GR_TAU = '\u03C4'; // τ
- private static final int GR_UPSILON = '\u03C5'; // υ
- private static final int GR_THETA = '\u03B8'; // θ
- private static final int GR_IOTA = '\u03B9'; // ι
- private static final int GR_OMICRON = '\u03BF'; // ο
- private static final int GR_PI = '\u03C0'; // π
- private static final int GR_ALPHA = '\u03B1'; // α
- private static final int GR_SIGMA = '\u03C3'; // σ
- private static final int GR_DELTA = '\u03B4'; // δ
- private static final int GR_PHI = '\u03C6'; // φ
- private static final int GR_GAMMA = '\u03B3'; // γ
- private static final int GR_ETA = '\u03B7'; // η
- private static final int GR_XI = '\u03BE'; // ξ
- private static final int GR_KAPPA = '\u03BA'; // κ
- private static final int GR_LAMDA = '\u03BB'; // λ
- private static final int GR_ZETA = '\u03B6'; // ζ
- private static final int GR_CHI = '\u03C7'; // χ
- private static final int GR_PSI = '\u03C8'; // ψ
- private static final int GR_OMEGA = '\u03C9'; // ω
- private static final int GR_BETA = '\u03B2'; // β
- private static final int GR_NU = '\u03BD'; // ν
- private static final int GR_MU = '\u03BC'; // μ
- static final int[] PROXIMITY = {
- // Proximity for row 1. This must have exactly ROW_SIZE entries for each letter,
- // and exactly PROXIMITY_GRID_WIDTH letters for a row. Pad with NUL's.
- // The number of rows must be exactly PROXIMITY_GRID_HEIGHT.
- GR_FINAL_SIGMA, GR_EPSILON, GR_ALPHA, GR_SIGMA, NUL, NUL, NUL,
- NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- GR_EPSILON, GR_FINAL_SIGMA, GR_RHO, GR_SIGMA, GR_DELTA, NUL, NUL, NUL,
- NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- GR_RHO, GR_EPSILON, GR_TAU, GR_DELTA, GR_PHI, NUL, NUL, NUL,
- NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- GR_TAU, GR_RHO, GR_UPSILON, GR_PHI, GR_GAMMA, NUL, NUL, NUL,
- NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- GR_UPSILON, GR_TAU, GR_THETA, GR_GAMMA, GR_ETA, NUL, NUL, NUL,
- NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- GR_THETA, GR_UPSILON, GR_IOTA, GR_ETA, GR_XI, NUL, NUL, NUL,
- NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- GR_IOTA, GR_THETA, GR_OMICRON, GR_XI, GR_KAPPA, NUL, NUL, NUL,
- NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- GR_OMICRON, GR_IOTA, GR_PI, GR_KAPPA, GR_LAMDA, NUL, NUL, NUL, NUL, NUL,
- NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- GR_PI, GR_OMICRON, GR_LAMDA, NUL, NUL, NUL, NUL, NUL,
- NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-
- GR_ALPHA, GR_FINAL_SIGMA, GR_SIGMA, GR_ZETA, NUL, NUL, NUL, NUL,
- NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- GR_SIGMA, GR_FINAL_SIGMA, GR_EPSILON, GR_ALPHA, GR_DELTA, GR_ZETA, GR_CHI, NUL,
- NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- GR_DELTA, GR_EPSILON, GR_RHO, GR_SIGMA, GR_PHI, GR_ZETA, GR_CHI, GR_PSI,
- NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- GR_PHI, GR_RHO, GR_TAU, GR_DELTA, GR_GAMMA, GR_CHI, GR_PSI, GR_OMEGA,
- NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- GR_GAMMA, GR_TAU, GR_UPSILON, GR_PHI, GR_ETA, GR_PSI, GR_OMEGA, GR_BETA,
- NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- GR_ETA, GR_UPSILON, GR_THETA, GR_GAMMA, GR_XI, GR_OMEGA, GR_BETA, GR_NU,
- NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- GR_XI, GR_THETA, GR_IOTA, GR_ETA, GR_KAPPA, GR_BETA, GR_NU, GR_MU,
- NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- GR_KAPPA, GR_IOTA, GR_OMICRON, GR_XI, GR_LAMDA, GR_NU, GR_MU, NUL, NUL,
- NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- GR_LAMDA, GR_OMICRON, GR_PI, GR_KAPPA, GR_MU, NUL, NUL, NUL,
- NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
-
- GR_ZETA, GR_ALPHA, GR_SIGMA, GR_DELTA, GR_CHI, NUL, NUL, NUL,
- NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- GR_CHI, GR_SIGMA, GR_DELTA, GR_PHI, GR_ZETA, GR_PSI, NUL, NUL,
- NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- GR_PSI, GR_DELTA, GR_PHI, GR_GAMMA, GR_CHI, GR_OMEGA, NUL, NUL,
- NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- GR_OMEGA, GR_PHI, GR_GAMMA, GR_ETA, GR_PSI, GR_BETA, NUL, NUL,
- NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- GR_BETA, GR_GAMMA, GR_ETA, GR_XI, GR_OMEGA, GR_NU, NUL, NUL,
- NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- GR_NU, GR_ETA, GR_XI, GR_KAPPA, GR_BETA, GR_MU, NUL, NUL,
- NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- GR_MU, GR_XI, GR_KAPPA, GR_LAMDA, GR_NU, NUL, NUL, NUL,
- NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL,
- };
-
- static final SparseIntArray INDICES = new SparseIntArray(PROXIMITY.length / ROW_SIZE);
-
- static {
- buildProximityIndices(PROXIMITY, ROW_SIZE, INDICES);
- }
- }
-
- private static int[] getProximityForScript(final int script) {
- switch (script) {
- case AndroidSpellCheckerService.SCRIPT_LATIN:
- return Latin.PROXIMITY;
- case AndroidSpellCheckerService.SCRIPT_CYRILLIC:
- return Cyrillic.PROXIMITY;
- case AndroidSpellCheckerService.SCRIPT_GREEK:
- return Greek.PROXIMITY;
- default:
- throw new RuntimeException("Wrong script supplied: " + script);
- }
- }
-
- private static int getIndexOfCodeForScript(final int codePoint, final int script) {
- switch (script) {
- case AndroidSpellCheckerService.SCRIPT_LATIN:
- return Latin.INDICES.get(codePoint, NOT_AN_INDEX);
- case AndroidSpellCheckerService.SCRIPT_CYRILLIC:
- return Cyrillic.INDICES.get(codePoint, NOT_AN_INDEX);
- case AndroidSpellCheckerService.SCRIPT_GREEK:
- return Greek.INDICES.get(codePoint, NOT_AN_INDEX);
- default:
- throw new RuntimeException("Wrong script supplied: " + script);
- }
- }
-
- // Returns (Y << 16) + X to avoid creating a temporary object. This is okay because
- // X and Y are limited to PROXIMITY_GRID_WIDTH resp. PROXIMITY_GRID_HEIGHT which is very
- // inferior to 1 << 16
- // As an exception, this returns NOT_A_COORDINATE_PAIR if the key is not on the grid
- public static int getXYForCodePointAndScript(final int codePoint, final int script) {
- final int index = getIndexOfCodeForScript(codePoint, script);
- if (NOT_AN_INDEX == index) return NOT_A_COORDINATE_PAIR;
- final int y = index / PROXIMITY_GRID_WIDTH;
- final int x = index % PROXIMITY_GRID_WIDTH;
- if (y > PROXIMITY_GRID_HEIGHT) {
- // Safety check, should be entirely useless
- throw new RuntimeException("Wrong y coordinate in spell checker proximity");
- }
- return (y << 16) + x;
- }
-}
diff --git a/java/src/com/android/inputmethod/latin/userdictionary/UserDictionaryAddWordFragment.java b/java/src/com/android/inputmethod/latin/userdictionary/UserDictionaryAddWordFragment.java
index 5f4c44636..58c8f266c 100644
--- a/java/src/com/android/inputmethod/latin/userdictionary/UserDictionaryAddWordFragment.java
+++ b/java/src/com/android/inputmethod/latin/userdictionary/UserDictionaryAddWordFragment.java
@@ -74,14 +74,14 @@ public class UserDictionaryAddWordFragment extends Fragment
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+ final MenuItem actionItemAdd = menu.add(0, OPTIONS_MENU_ADD, 0,
+ R.string.user_dict_settings_add_menu_title).setIcon(R.drawable.ic_menu_add);
+ actionItemAdd.setShowAsAction(
+ MenuItem.SHOW_AS_ACTION_IF_ROOM | MenuItem.SHOW_AS_ACTION_WITH_TEXT);
final MenuItem actionItemDelete = menu.add(0, OPTIONS_MENU_DELETE, 0,
R.string.user_dict_settings_delete).setIcon(android.R.drawable.ic_menu_delete);
actionItemDelete.setShowAsAction(
MenuItem.SHOW_AS_ACTION_IF_ROOM | MenuItem.SHOW_AS_ACTION_WITH_TEXT);
- final MenuItem actionItemAdd = menu.add(0, OPTIONS_MENU_ADD, 0,
- R.string.user_dict_settings_delete).setIcon(R.drawable.ic_menu_add);
- actionItemAdd.setShowAsAction(
- MenuItem.SHOW_AS_ACTION_IF_ROOM | MenuItem.SHOW_AS_ACTION_WITH_TEXT);
}
/**
diff --git a/java/src/com/android/inputmethod/latin/userdictionary/UserDictionarySettings.java b/java/src/com/android/inputmethod/latin/userdictionary/UserDictionarySettings.java
index 36bc5ba49..50dda9663 100644
--- a/java/src/com/android/inputmethod/latin/userdictionary/UserDictionarySettings.java
+++ b/java/src/com/android/inputmethod/latin/userdictionary/UserDictionarySettings.java
@@ -108,6 +108,7 @@ public class UserDictionarySettings extends ListFragment {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ getActivity().getActionBar().setTitle(R.string.edit_personal_dictionary);
}
@Override
diff --git a/java/src/com/android/inputmethod/research/FixedLogBuffer.java b/java/src/com/android/inputmethod/research/FixedLogBuffer.java
index 4249af544..8b64de8ae 100644
--- a/java/src/com/android/inputmethod/research/FixedLogBuffer.java
+++ b/java/src/com/android/inputmethod/research/FixedLogBuffer.java
@@ -65,6 +65,7 @@ public class FixedLogBuffer extends LogBuffer {
final int numWordsIncoming = newLogUnit.getNumWords();
if (mNumActualWords >= mWordCapacity) {
// Give subclass a chance to handle the buffer full condition by shifting out logUnits.
+ // TODO: Tell onBufferFull() how much space it needs to make to avoid forced eviction.
onBufferFull();
// If still full, evict.
if (mNumActualWords >= mWordCapacity) {
@@ -119,21 +120,19 @@ public class FixedLogBuffer extends LogBuffer {
/**
* Remove LogUnits from the front of the LogBuffer until {@code numWords} have been removed.
*
- * If there are less than {@code numWords} word-containing {@link LogUnit}s, shifts out
- * all {@code LogUnit}s in the buffer.
+ * If there are less than {@code numWords} in the buffer, shifts out all {@code LogUnit}s.
*
- * @param numWords the minimum number of word-containing {@link LogUnit}s to shift out
- * @return the number of actual {@code LogUnit}s shifted out
+ * @param numWords the minimum number of words in {@link LogUnit}s to shift out
+ * @return the number of actual words LogUnit}s shifted out
*/
protected int shiftOutWords(final int numWords) {
- int numWordContainingLogUnitsShiftedOut = 0;
- for (LogUnit logUnit = shiftOut(); logUnit != null
- && numWordContainingLogUnitsShiftedOut < numWords; logUnit = shiftOut()) {
- if (logUnit.hasOneOrMoreWords()) {
- numWordContainingLogUnitsShiftedOut += logUnit.getNumWords();
- }
- }
- return numWordContainingLogUnitsShiftedOut;
+ int numWordsShiftedOut = 0;
+ do {
+ final LogUnit logUnit = shiftOut();
+ if (logUnit == null) break;
+ numWordsShiftedOut += logUnit.getNumWords();
+ } while (numWordsShiftedOut < numWords);
+ return numWordsShiftedOut;
}
public void shiftOutAll() {
diff --git a/java/src/com/android/inputmethod/research/MainLogBuffer.java b/java/src/com/android/inputmethod/research/MainLogBuffer.java
index 42ef5d3b6..9bdedbf6d 100644
--- a/java/src/com/android/inputmethod/research/MainLogBuffer.java
+++ b/java/src/com/android/inputmethod/research/MainLogBuffer.java
@@ -190,22 +190,30 @@ public abstract class MainLogBuffer extends FixedLogBuffer {
}
protected final void publishLogUnitsAtFrontOfBuffer() {
+ // TODO: Refactor this method to require fewer passes through the LogUnits. Should really
+ // require only one pass.
ArrayList<LogUnit> logUnits = peekAtFirstNWords(N_GRAM_SIZE);
if (isSafeNGram(logUnits, N_GRAM_SIZE)) {
// Good n-gram at the front of the buffer. Publish it, disclosing details.
publish(logUnits, true /* canIncludePrivateData */);
shiftOutWords(N_GRAM_SIZE);
mNumWordsUntilSafeToSample = mNumWordsBetweenNGrams;
- } else {
- // No good n-gram at front, and buffer is full. Shift out up through the first logUnit
- // with associated words (or if there is none, all the existing logUnits).
- logUnits.clear();
- for (LogUnit logUnit = shiftOut(); logUnit != null && !logUnit.hasOneOrMoreWords();
- logUnit = shiftOut()) {
- logUnits.add(logUnit);
+ return;
+ }
+ // No good n-gram at front, and buffer is full. Shift out up through the first logUnit
+ // with associated words (or if there is none, all the existing logUnits).
+ logUnits.clear();
+ LogUnit logUnit = shiftOut();
+ while (logUnit != null) {
+ logUnits.add(logUnit);
+ final int numWords = logUnit.getNumWords();
+ if (numWords > 0) {
+ mNumWordsUntilSafeToSample = Math.max(0, mNumWordsUntilSafeToSample - numWords);
+ break;
}
- publish(logUnits, false /* canIncludePrivateData */);
+ logUnit = shiftOut();
}
+ publish(logUnits, false /* canIncludePrivateData */);
}
/**
@@ -222,12 +230,11 @@ public abstract class MainLogBuffer extends FixedLogBuffer {
@Override
protected int shiftOutWords(final int numWords) {
- final int numWordContainingLogUnitsShiftedOut = super.shiftOutWords(numWords);
- mNumWordsUntilSafeToSample = Math.max(0, mNumWordsUntilSafeToSample
- - numWordContainingLogUnitsShiftedOut);
+ final int numWordsShiftedOut = super.shiftOutWords(numWords);
+ mNumWordsUntilSafeToSample = Math.max(0, mNumWordsUntilSafeToSample - numWordsShiftedOut);
if (DEBUG) {
Log.d(TAG, "wordsUntilSafeToSample now at " + mNumWordsUntilSafeToSample);
}
- return numWordContainingLogUnitsShiftedOut;
+ return numWordsShiftedOut;
}
}