diff options
Diffstat (limited to 'java/src')
4 files changed, 131 insertions, 33 deletions
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/internal/GestureStrokeWithPreviewPoints.java b/java/src/com/android/inputmethod/keyboard/internal/GestureStrokeWithPreviewPoints.java index 7a51e2568..312fd2160 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; } @@ -144,19 +172,19 @@ 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); diff --git a/java/src/com/android/inputmethod/latin/ContactsBinaryDictionary.java b/java/src/com/android/inputmethod/latin/ContactsBinaryDictionary.java index d660f70cc..b9db9a092 100644 --- a/java/src/com/android/inputmethod/latin/ContactsBinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/ContactsBinaryDictionary.java @@ -16,6 +16,8 @@ package com.android.inputmethod.latin; +import com.android.inputmethod.latin.personalization.AccountUtils; + import android.content.ContentResolver; import android.content.Context; import android.database.ContentObserver; @@ -28,6 +30,7 @@ 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 { @@ -105,11 +108,27 @@ 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() 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; + } +} |