Merge remote-tracking branch 'goog/master' into merge
commit
38c984cbcc
|
@ -200,8 +200,8 @@ public class Key {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Horizontal gap is divided equally to both sides of the key.
|
// Horizontal gap is divided equally to both sides of the key.
|
||||||
this.mX = x + mGap / 2;
|
mX = x + mGap / 2;
|
||||||
this.mY = y;
|
mY = y;
|
||||||
|
|
||||||
final TypedArray keyAttr = res.obtainAttributes(Xml.asAttributeSet(parser),
|
final TypedArray keyAttr = res.obtainAttributes(Xml.asAttributeSet(parser),
|
||||||
R.styleable.Keyboard_Key);
|
R.styleable.Keyboard_Key);
|
||||||
|
@ -351,12 +351,13 @@ public class Key {
|
||||||
final boolean rightEdge = (flags & Keyboard.EDGE_RIGHT) != 0;
|
final boolean rightEdge = (flags & Keyboard.EDGE_RIGHT) != 0;
|
||||||
final boolean topEdge = (flags & Keyboard.EDGE_TOP) != 0;
|
final boolean topEdge = (flags & Keyboard.EDGE_TOP) != 0;
|
||||||
final boolean bottomEdge = (flags & Keyboard.EDGE_BOTTOM) != 0;
|
final boolean bottomEdge = (flags & Keyboard.EDGE_BOTTOM) != 0;
|
||||||
final int left = this.mX;
|
final int left = mX - mGap / 2;
|
||||||
final int right = left + this.mWidth;
|
final int right = left + mWidth + mGap;
|
||||||
final int top = this.mY;
|
final int top = mY;
|
||||||
final int bottom = top + this.mHeight;
|
final int bottom = top + mHeight + mKeyboard.getVerticalGap();
|
||||||
return (x >= left || leftEdge) && (x < right || rightEdge)
|
// In order to mitigate rounding errors, we use (left <= x <= right) here.
|
||||||
&& (y >= top || topEdge) && (y < bottom || bottomEdge);
|
return (x >= left || leftEdge) && (x <= right || rightEdge)
|
||||||
|
&& (y >= top || topEdge) && (y <= bottom || bottomEdge);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -366,10 +367,10 @@ public class Key {
|
||||||
* @return the square of the distance of the point from the nearest edge of the key
|
* @return the square of the distance of the point from the nearest edge of the key
|
||||||
*/
|
*/
|
||||||
public int squaredDistanceToEdge(int x, int y) {
|
public int squaredDistanceToEdge(int x, int y) {
|
||||||
final int left = this.mX;
|
final int left = mX;
|
||||||
final int right = left + this.mWidth;
|
final int right = left + mWidth;
|
||||||
final int top = this.mY;
|
final int top = mY;
|
||||||
final int bottom = top + this.mHeight;
|
final int bottom = top + mHeight;
|
||||||
final int edgeX = x < left ? left : (x > right ? right : x);
|
final int edgeX = x < left ? left : (x > right ? right : x);
|
||||||
final int edgeY = y < top ? top : (y > bottom ? bottom : y);
|
final int edgeY = y < top ? top : (y > bottom ? bottom : y);
|
||||||
final int dx = x - edgeX;
|
final int dx = x - edgeX;
|
||||||
|
|
|
@ -91,11 +91,11 @@ public class KeyDetector {
|
||||||
*
|
*
|
||||||
* @return Allocates and returns an array that can hold all key indices returned by
|
* @return Allocates and returns an array that can hold all key indices returned by
|
||||||
* {@link #getKeyIndexAndNearbyCodes} method. All elements in the returned array are
|
* {@link #getKeyIndexAndNearbyCodes} method. All elements in the returned array are
|
||||||
* initialized by {@link #NOT_A_KEY} value.
|
* initialized by {@link #NOT_A_CODE} value.
|
||||||
*/
|
*/
|
||||||
public int[] newCodeArray() {
|
public int[] newCodeArray() {
|
||||||
int[] codes = new int[getMaxNearbyKeys()];
|
int[] codes = new int[getMaxNearbyKeys()];
|
||||||
Arrays.fill(codes, NOT_A_KEY);
|
Arrays.fill(codes, NOT_A_CODE);
|
||||||
return codes;
|
return codes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -106,16 +106,20 @@ public class KeyDetector {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Insert the key into nearby keys buffer and sort nearby keys by ascending order of distance.
|
* Insert the key into nearby keys buffer and sort nearby keys by ascending order of distance.
|
||||||
|
* If the distance of two keys are the same, the key which the point is on should be considered
|
||||||
|
* as a closer one.
|
||||||
*
|
*
|
||||||
* @param keyIndex index of the key.
|
* @param keyIndex index of the key.
|
||||||
* @param distance distance between the key's edge and user touched point.
|
* @param distance distance between the key's edge and user touched point.
|
||||||
|
* @param isOnKey true if the point is on the key.
|
||||||
* @return order of the key in the nearby buffer, 0 if it is the nearest key.
|
* @return order of the key in the nearby buffer, 0 if it is the nearest key.
|
||||||
*/
|
*/
|
||||||
private int sortNearbyKeys(int keyIndex, int distance) {
|
private int sortNearbyKeys(int keyIndex, int distance, boolean isOnKey) {
|
||||||
final int[] distances = mDistances;
|
final int[] distances = mDistances;
|
||||||
final int[] indices = mIndices;
|
final int[] indices = mIndices;
|
||||||
for (int insertPos = 0; insertPos < distances.length; insertPos++) {
|
for (int insertPos = 0; insertPos < distances.length; insertPos++) {
|
||||||
if (distance < distances[insertPos]) {
|
final int comparingDistance = distances[insertPos];
|
||||||
|
if (distance < comparingDistance || (distance == comparingDistance && isOnKey)) {
|
||||||
final int nextPos = insertPos + 1;
|
final int nextPos = insertPos + 1;
|
||||||
if (nextPos < distances.length) {
|
if (nextPos < distances.length) {
|
||||||
System.arraycopy(distances, insertPos, distances, nextPos,
|
System.arraycopy(distances, insertPos, distances, nextPos,
|
||||||
|
@ -174,11 +178,11 @@ public class KeyDetector {
|
||||||
int primaryIndex = NOT_A_KEY;
|
int primaryIndex = NOT_A_KEY;
|
||||||
for (final int index : mKeyboard.getNearestKeys(touchX, touchY)) {
|
for (final int index : mKeyboard.getNearestKeys(touchX, touchY)) {
|
||||||
final Key key = keys.get(index);
|
final Key key = keys.get(index);
|
||||||
final boolean isInside = mKeyboard.isInside(key, touchX, touchY);
|
final boolean isOnKey = key.isOnKey(touchX, touchY);
|
||||||
final int distance = key.squaredDistanceToEdge(touchX, touchY);
|
final int distance = key.squaredDistanceToEdge(touchX, touchY);
|
||||||
if (isInside || (mProximityCorrectOn && distance < mProximityThresholdSquare)) {
|
if (isOnKey || (mProximityCorrectOn && distance < mProximityThresholdSquare)) {
|
||||||
final int insertedPosition = sortNearbyKeys(index, distance);
|
final int insertedPosition = sortNearbyKeys(index, distance, isOnKey);
|
||||||
if (insertedPosition == 0 && isInside)
|
if (insertedPosition == 0 && isOnKey)
|
||||||
primaryIndex = index;
|
primaryIndex = index;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -380,10 +380,6 @@ public class Keyboard {
|
||||||
mProximityInfo.setProximityInfo(mGridNeighbors, getMinWidth(), getHeight(), mKeys);
|
mProximityInfo.setProximityInfo(mGridNeighbors, getMinWidth(), getHeight(), mKeys);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isInside(Key key, int x, int y) {
|
|
||||||
return key.isOnKey(x, y);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the indices of the keys that are closest to the given point.
|
* Returns the indices of the keys that are closest to the given point.
|
||||||
* @param x the x-coordinate of the point
|
* @param x the x-coordinate of the point
|
||||||
|
|
|
@ -28,6 +28,8 @@ import java.io.FileNotFoundException;
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -79,27 +81,32 @@ public class BinaryDictionaryFileDumper {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Queries a content provider for dictionary data for some locale and returns it as a file name.
|
* Queries a content provider for dictionary data for some locale and returns the file addresses
|
||||||
*
|
*
|
||||||
* This will query a content provider for dictionary data for a given locale, and return
|
* This will query a content provider for dictionary data for a given locale, and return
|
||||||
* the name of a file suitable to be mmap'ed. It will copy it to local storage if needed.
|
* the addresses of a file set the members of which are suitable to be mmap'ed. It will copy
|
||||||
* It should also check the dictionary version to avoid unnecessary copies but this is
|
* them to local storage if needed.
|
||||||
|
* It should also check the dictionary versions to avoid unnecessary copies but this is
|
||||||
* still in TODO state.
|
* still in TODO state.
|
||||||
* This will make the data from the content provider the cached dictionary for this locale,
|
* This will make the data from the content provider the cached dictionary for this locale,
|
||||||
* overwriting any previous cached data.
|
* overwriting any previous cached data.
|
||||||
* @returns the name of the file, or null if no data could be obtained.
|
* @returns the addresses of the files, or null if no data could be obtained.
|
||||||
* @throw FileNotFoundException if the provider returns non-existent data.
|
* @throw FileNotFoundException if the provider returns non-existent data.
|
||||||
* @throw IOException if the provider-returned data could not be read.
|
* @throw IOException if the provider-returned data could not be read.
|
||||||
*/
|
*/
|
||||||
public static String getDictionaryFileFromContentProvider(Locale locale, Context context)
|
public static List<AssetFileAddress> getDictSetFromContentProvider(Locale locale,
|
||||||
throws FileNotFoundException, IOException {
|
Context context) throws FileNotFoundException, IOException {
|
||||||
// TODO: check whether the dictionary is the same or not and if it is, return the cached
|
// TODO: check whether the dictionary is the same or not and if it is, return the cached
|
||||||
// file.
|
// file.
|
||||||
|
// TODO: This should be able to read a number of files from the dictionary pack, copy
|
||||||
|
// them all and return them.
|
||||||
final ContentResolver resolver = context.getContentResolver();
|
final ContentResolver resolver = context.getContentResolver();
|
||||||
final Uri dictionaryPackUri = getProviderUri(locale);
|
final Uri dictionaryPackUri = getProviderUri(locale);
|
||||||
final AssetFileDescriptor afd = resolver.openAssetFileDescriptor(dictionaryPackUri, "r");
|
final AssetFileDescriptor afd = resolver.openAssetFileDescriptor(dictionaryPackUri, "r");
|
||||||
if (null == afd) return null;
|
if (null == afd) return null;
|
||||||
return copyFileTo(afd.createInputStream(), getCacheFileNameForLocale(locale, context));
|
final String fileName =
|
||||||
|
copyFileTo(afd.createInputStream(), getCacheFileNameForLocale(locale, context));
|
||||||
|
return Arrays.asList(AssetFileAddress.makeFromFileName(fileName));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -22,6 +22,8 @@ import android.util.Log;
|
||||||
|
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -52,13 +54,13 @@ class BinaryDictionaryGetter {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a file address for a given locale, trying relevant methods in order.
|
* Returns a list of file addresses for a given locale, trying relevant methods in order.
|
||||||
*
|
*
|
||||||
* Tries to get a binary dictionary from various sources, in order:
|
* Tries to get binary dictionaries from various sources, in order:
|
||||||
* - Uses a private method of getting a private dictionary, as implemented by the
|
* - Uses a private method of getting a private dictionaries, as implemented by the
|
||||||
* PrivateBinaryDictionaryGetter class.
|
* PrivateBinaryDictionaryGetter class.
|
||||||
* If that fails:
|
* If that fails:
|
||||||
* - Uses a content provider to get a public dictionary, as per the protocol described
|
* - Uses a content provider to get a public dictionary set, as per the protocol described
|
||||||
* in BinaryDictionaryFileDumper.
|
* in BinaryDictionaryFileDumper.
|
||||||
* If that fails:
|
* If that fails:
|
||||||
* - Gets a file name from the fallback resource passed as an argument.
|
* - Gets a file name from the fallback resource passed as an argument.
|
||||||
|
@ -66,27 +68,25 @@ class BinaryDictionaryGetter {
|
||||||
* - Returns null.
|
* - Returns null.
|
||||||
* @return The address of a valid file, or null.
|
* @return The address of a valid file, or null.
|
||||||
*/
|
*/
|
||||||
public static AssetFileAddress getDictionaryFile(Locale locale, Context context,
|
public static List<AssetFileAddress> getDictionaryFiles(Locale locale, Context context,
|
||||||
int fallbackResId) {
|
int fallbackResId) {
|
||||||
// Try first to query a private file signed the same way.
|
// Try first to query a private package signed the same way for private files.
|
||||||
final AssetFileAddress privateFile =
|
final List<AssetFileAddress> privateFiles =
|
||||||
PrivateBinaryDictionaryGetter.getDictionaryFile(locale, context);
|
PrivateBinaryDictionaryGetter.getDictionaryFiles(locale, context);
|
||||||
if (null != privateFile) {
|
if (null != privateFiles) {
|
||||||
return privateFile;
|
return privateFiles;
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
// If that was no-go, try to find a publicly exported dictionary.
|
// If that was no-go, try to find a publicly exported dictionary.
|
||||||
final String fileName = BinaryDictionaryFileDumper.
|
return BinaryDictionaryFileDumper.getDictSetFromContentProvider(locale, context);
|
||||||
getDictionaryFileFromContentProvider(locale, context);
|
|
||||||
return AssetFileAddress.makeFromFileName(fileName);
|
|
||||||
} catch (FileNotFoundException e) {
|
} catch (FileNotFoundException e) {
|
||||||
Log.e(TAG, "Unable to create dictionary file from provider for locale "
|
Log.e(TAG, "Unable to create dictionary file from provider for locale "
|
||||||
+ locale.toString() + ": falling back to internal dictionary");
|
+ locale.toString() + ": falling back to internal dictionary");
|
||||||
return loadFallbackResource(context, fallbackResId);
|
return Arrays.asList(loadFallbackResource(context, fallbackResId));
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
Log.e(TAG, "Unable to read source data for locale "
|
Log.e(TAG, "Unable to read source data for locale "
|
||||||
+ locale.toString() + ": falling back to internal dictionary");
|
+ locale.toString() + ": falling back to internal dictionary");
|
||||||
return loadFallbackResource(context, fallbackResId);
|
return Arrays.asList(loadFallbackResource(context, fallbackResId));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
|
|
||||||
package com.android.inputmethod.latin;
|
package com.android.inputmethod.latin;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.CopyOnWriteArrayList;
|
import java.util.concurrent.CopyOnWriteArrayList;
|
||||||
|
|
||||||
|
@ -34,6 +35,10 @@ public class DictionaryCollection extends Dictionary {
|
||||||
mDictionaries = new CopyOnWriteArrayList<Dictionary>(dictionaries);
|
mDictionaries = new CopyOnWriteArrayList<Dictionary>(dictionaries);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public DictionaryCollection(Collection<Dictionary> dictionaries) {
|
||||||
|
mDictionaries = new CopyOnWriteArrayList<Dictionary>(dictionaries);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void getWords(final WordComposer composer, final WordCallback callback) {
|
public void getWords(final WordComposer composer, final WordCallback callback) {
|
||||||
for (final Dictionary dict : mDictionaries)
|
for (final Dictionary dict : mDictionaries)
|
||||||
|
|
|
@ -18,11 +18,12 @@ package com.android.inputmethod.latin;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.res.AssetFileDescriptor;
|
import android.content.res.AssetFileDescriptor;
|
||||||
import android.content.res.Configuration;
|
|
||||||
import android.content.res.Resources;
|
import android.content.res.Resources;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -50,11 +51,14 @@ public class DictionaryFactory {
|
||||||
return new DictionaryCollection(createBinaryDictionary(context, fallbackResId));
|
return new DictionaryCollection(createBinaryDictionary(context, fallbackResId));
|
||||||
}
|
}
|
||||||
|
|
||||||
final AssetFileAddress dictFile = BinaryDictionaryGetter.getDictionaryFile(locale,
|
final List<Dictionary> dictList = new LinkedList<Dictionary>();
|
||||||
context, fallbackResId);
|
for (final AssetFileAddress f : BinaryDictionaryGetter.getDictionaryFiles(locale,
|
||||||
if (null == dictFile) return null;
|
context, fallbackResId)) {
|
||||||
return new DictionaryCollection(new BinaryDictionary(context,
|
dictList.add(new BinaryDictionary(context, f.mFilename, f.mOffset, f.mLength, null));
|
||||||
dictFile.mFilename, dictFile.mOffset, dictFile.mLength, null));
|
}
|
||||||
|
|
||||||
|
if (null == dictList) return null;
|
||||||
|
return new DictionaryCollection(dictList);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -66,7 +70,6 @@ public class DictionaryFactory {
|
||||||
protected static BinaryDictionary createBinaryDictionary(Context context, int resId) {
|
protected static BinaryDictionary createBinaryDictionary(Context context, int resId) {
|
||||||
AssetFileDescriptor afd = null;
|
AssetFileDescriptor afd = null;
|
||||||
try {
|
try {
|
||||||
// TODO: IMPORTANT: Do not create a dictionary from a placeholder.
|
|
||||||
afd = context.getResources().openRawResourceFd(resId);
|
afd = context.getResources().openRawResourceFd(resId);
|
||||||
if (afd == null) {
|
if (afd == null) {
|
||||||
Log.e(TAG, "Found the resource but it is compressed. resId=" + resId);
|
Log.e(TAG, "Found the resource but it is compressed. resId=" + resId);
|
||||||
|
|
|
@ -18,11 +18,12 @@ package com.android.inputmethod.latin;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
class PrivateBinaryDictionaryGetter {
|
class PrivateBinaryDictionaryGetter {
|
||||||
private PrivateBinaryDictionaryGetter() {}
|
private PrivateBinaryDictionaryGetter() {}
|
||||||
public static AssetFileAddress getDictionaryFile(Locale locale, Context context) {
|
public static List<AssetFileAddress> getDictionaryFiles(Locale locale, Context context) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue