Sort keys from top-left to bottom-right order

Change-Id: I228748824de62e9e46fa43db200d23f41eb6d2ce
main
Tadashi G. Takaoka 2014-04-21 14:41:57 -07:00
parent 5326dcfb7d
commit c13c1adfa7
11 changed files with 66 additions and 57 deletions

View File

@ -159,7 +159,7 @@ public final class AccessibilityEntityProvider extends AccessibilityNodeProvider
// Add the virtual children of the root View. // Add the virtual children of the root View.
final Keyboard keyboard = mKeyboardView.getKeyboard(); final Keyboard keyboard = mKeyboardView.getKeyboard();
for (final Key key : keyboard.getKeys()) { for (final Key key : keyboard.getSortedKeys()) {
final int childVirtualViewId = generateVirtualViewIdForKey(key); final int childVirtualViewId = generateVirtualViewIdForKey(key);
rootInfo.addChild(mKeyboardView, childVirtualViewId); rootInfo.addChild(mKeyboardView, childVirtualViewId);
} }
@ -307,7 +307,7 @@ public final class AccessibilityEntityProvider extends AccessibilityNodeProvider
} }
mVirtualViewIdToKey.clear(); mVirtualViewIdToKey.clear();
for (final Key key : keyboard.getKeys()) { for (final Key key : keyboard.getSortedKeys()) {
final int virtualViewId = generateVirtualViewIdForKey(key); final int virtualViewId = generateVirtualViewIdForKey(key);
mVirtualViewIdToKey.put(virtualViewId, key); mVirtualViewIdToKey.put(virtualViewId, key);
} }

View File

@ -298,7 +298,7 @@ public final class EmojiPalettesView extends LinearLayout implements OnTabChange
private int getCategoryPageCount(final int categoryId) { private int getCategoryPageCount(final int categoryId) {
final Keyboard keyboard = mLayoutSet.getKeyboard(sCategoryElementId[categoryId]); final Keyboard keyboard = mLayoutSet.getKeyboard(sCategoryElementId[categoryId]);
return (keyboard.getKeys().size() - 1) / mMaxPageKeyCount + 1; return (keyboard.getSortedKeys().size() - 1) / mMaxPageKeyCount + 1;
} }
// Returns a pair of the category id and the category page id from the view pager's page // Returns a pair of the category id and the category page id from the view pager's page
@ -347,7 +347,8 @@ public final class EmojiPalettesView extends LinearLayout implements OnTabChange
} }
final Keyboard keyboard = mLayoutSet.getKeyboard(sCategoryElementId[categoryId]); final Keyboard keyboard = mLayoutSet.getKeyboard(sCategoryElementId[categoryId]);
final Key[][] sortedKeys = sortKeysIntoPages(keyboard.getKeys(), mMaxPageKeyCount); final Key[][] sortedKeys = sortKeysIntoPages(
keyboard.getSortedKeys(), mMaxPageKeyCount);
for (int pageId = 0; pageId < sortedKeys.length; ++pageId) { for (int pageId = 0; pageId < sortedKeys.length; ++pageId) {
final DynamicGridKeyboard tempKeyboard = new DynamicGridKeyboard(mPrefs, final DynamicGridKeyboard tempKeyboard = new DynamicGridKeyboard(mPrefs,
mLayoutSet.getKeyboard(KeyboardId.ELEMENT_EMOJI_RECENTS), mLayoutSet.getKeyboard(KeyboardId.ELEMENT_EMOJI_RECENTS),

View File

@ -78,7 +78,7 @@ public class Keyboard {
public final int mMaxMoreKeysKeyboardColumn; public final int mMaxMoreKeysKeyboardColumn;
/** List of keys in this keyboard */ /** List of keys in this keyboard */
private final List<Key> mKeys; private final List<Key> mSortedKeys;
public final List<Key> mShiftKeys; public final List<Key> mShiftKeys;
public final List<Key> mAltCodeKeysWhileTyping; public final List<Key> mAltCodeKeysWhileTyping;
public final KeyboardIconsSet mIconsSet; public final KeyboardIconsSet mIconsSet;
@ -103,14 +103,16 @@ public class Keyboard {
mTopPadding = params.mTopPadding; mTopPadding = params.mTopPadding;
mVerticalGap = params.mVerticalGap; mVerticalGap = params.mVerticalGap;
mKeys = Collections.unmodifiableList(CollectionUtils.newArrayList(params.mKeys)); mSortedKeys = Collections.unmodifiableList(
CollectionUtils.newArrayList(params.mSortedKeys));
mShiftKeys = Collections.unmodifiableList(params.mShiftKeys); mShiftKeys = Collections.unmodifiableList(params.mShiftKeys);
mAltCodeKeysWhileTyping = Collections.unmodifiableList(params.mAltCodeKeysWhileTyping); mAltCodeKeysWhileTyping = Collections.unmodifiableList(params.mAltCodeKeysWhileTyping);
mIconsSet = params.mIconsSet; mIconsSet = params.mIconsSet;
mProximityInfo = new ProximityInfo(params.mId.mLocale.toString(), mProximityInfo = new ProximityInfo(params.mId.mLocale.toString(),
params.GRID_WIDTH, params.GRID_HEIGHT, mOccupiedWidth, mOccupiedHeight, params.GRID_WIDTH, params.GRID_HEIGHT, mOccupiedWidth, mOccupiedHeight,
mMostCommonKeyWidth, mMostCommonKeyHeight, mKeys, params.mTouchPositionCorrection); mMostCommonKeyWidth, mMostCommonKeyHeight, mSortedKeys,
params.mTouchPositionCorrection);
mProximityCharsCorrectionEnabled = params.mProximityCharsCorrectionEnabled; mProximityCharsCorrectionEnabled = params.mProximityCharsCorrectionEnabled;
} }
@ -129,7 +131,7 @@ public class Keyboard {
mTopPadding = keyboard.mTopPadding; mTopPadding = keyboard.mTopPadding;
mVerticalGap = keyboard.mVerticalGap; mVerticalGap = keyboard.mVerticalGap;
mKeys = keyboard.mKeys; mSortedKeys = keyboard.mSortedKeys;
mShiftKeys = keyboard.mShiftKeys; mShiftKeys = keyboard.mShiftKeys;
mAltCodeKeysWhileTyping = keyboard.mAltCodeKeysWhileTyping; mAltCodeKeysWhileTyping = keyboard.mAltCodeKeysWhileTyping;
mIconsSet = keyboard.mIconsSet; mIconsSet = keyboard.mIconsSet;
@ -154,12 +156,18 @@ public class Keyboard {
return mProximityInfo; return mProximityInfo;
} }
public List<Key> getKeys() { /**
return mKeys; * Return the sorted list of keys of this keyboard.
* The keys are sorted from top-left to bottom-right order.
* The list may contain {@link Spacer} object as well.
* @return the sorted unmodifiable list of {@link Key}s of this keyboard.
*/
public List<Key> getSortedKeys() {
return mSortedKeys;
} }
public Key getKeyFromOutputText(final String outputText) { public Key getKeyFromOutputText(final String outputText) {
for (final Key key : getKeys()) { for (final Key key : getSortedKeys()) {
if (outputText.equals(key.getOutputText())) { if (outputText.equals(key.getOutputText())) {
return key; return key;
} }
@ -177,7 +185,7 @@ public class Keyboard {
return mKeyCache.valueAt(index); return mKeyCache.valueAt(index);
} }
for (final Key key : getKeys()) { for (final Key key : getSortedKeys()) {
if (key.getCode() == code) { if (key.getCode() == code) {
mKeyCache.put(code, key); mKeyCache.put(code, key);
return key; return key;
@ -193,7 +201,7 @@ public class Keyboard {
return true; return true;
} }
for (final Key key : getKeys()) { for (final Key key : getSortedKeys()) {
if (key == aKey) { if (key == aKey) {
mKeyCache.put(key.getCode(), key); mKeyCache.put(key.getCode(), key);
return true; return true;

View File

@ -289,7 +289,7 @@ public class KeyboardView extends View {
// TODO: Confirm if it's really required to draw all keys when hardware acceleration is on. // TODO: Confirm if it's really required to draw all keys when hardware acceleration is on.
if (drawAllKeys || isHardwareAccelerated) { if (drawAllKeys || isHardwareAccelerated) {
// Draw all keys. // Draw all keys.
for (final Key key : mKeyboard.getKeys()) { for (final Key key : mKeyboard.getSortedKeys()) {
onDrawKey(key, canvas, paint); onDrawKey(key, canvas, paint);
} }
} else { } else {

View File

@ -43,7 +43,7 @@ public final class MoreKeysDetector extends KeyDetector {
Key nearestKey = null; Key nearestKey = null;
int nearestDist = (y < 0) ? mSlideAllowanceSquareTop : mSlideAllowanceSquare; int nearestDist = (y < 0) ? mSlideAllowanceSquareTop : mSlideAllowanceSquare;
for (final Key key : keyboard.getKeys()) { for (final Key key : keyboard.getSortedKeys()) {
final int dist = key.squaredDistanceToEdge(touchX, touchY); final int dist = key.squaredDistanceToEdge(touchX, touchY);
if (dist < nearestDist) { if (dist < nearestDist) {
nearestKey = key; nearestKey = key;

View File

@ -51,13 +51,13 @@ public class ProximityInfo {
private final int mKeyboardHeight; private final int mKeyboardHeight;
private final int mMostCommonKeyWidth; private final int mMostCommonKeyWidth;
private final int mMostCommonKeyHeight; private final int mMostCommonKeyHeight;
private final List<Key> mKeys; private final List<Key> mSortedKeys;
private final List<Key>[] mGridNeighbors; private final List<Key>[] mGridNeighbors;
private final String mLocaleStr; private final String mLocaleStr;
ProximityInfo(final String localeStr, final int gridWidth, final int gridHeight, ProximityInfo(final String localeStr, final int gridWidth, final int gridHeight,
final int minWidth, final int height, final int mostCommonKeyWidth, final int minWidth, final int height, final int mostCommonKeyWidth,
final int mostCommonKeyHeight, final List<Key> keys, final int mostCommonKeyHeight, final List<Key> sortedKeys,
final TouchPositionCorrection touchPositionCorrection) { final TouchPositionCorrection touchPositionCorrection) {
if (TextUtils.isEmpty(localeStr)) { if (TextUtils.isEmpty(localeStr)) {
mLocaleStr = ""; mLocaleStr = "";
@ -73,7 +73,7 @@ public class ProximityInfo {
mKeyboardHeight = height; mKeyboardHeight = height;
mMostCommonKeyHeight = mostCommonKeyHeight; mMostCommonKeyHeight = mostCommonKeyHeight;
mMostCommonKeyWidth = mostCommonKeyWidth; mMostCommonKeyWidth = mostCommonKeyWidth;
mKeys = keys; mSortedKeys = sortedKeys;
mGridNeighbors = new List[mGridSize]; mGridNeighbors = new List[mGridSize];
if (minWidth == 0 || height == 0) { if (minWidth == 0 || height == 0) {
// No proximity required. Keyboard might be more keys keyboard. // No proximity required. Keyboard might be more keys keyboard.
@ -146,8 +146,8 @@ public class ProximityInfo {
} }
} }
final List<Key> keys = mKeys; final List<Key> sortedKeys = mSortedKeys;
final int keyCount = getProximityInfoKeysCount(keys); final int keyCount = getProximityInfoKeysCount(sortedKeys);
final int[] keyXCoordinates = new int[keyCount]; final int[] keyXCoordinates = new int[keyCount];
final int[] keyYCoordinates = new int[keyCount]; final int[] keyYCoordinates = new int[keyCount];
final int[] keyWidths = new int[keyCount]; final int[] keyWidths = new int[keyCount];
@ -157,8 +157,8 @@ public class ProximityInfo {
final float[] sweetSpotCenterYs; final float[] sweetSpotCenterYs;
final float[] sweetSpotRadii; final float[] sweetSpotRadii;
for (int infoIndex = 0, keyIndex = 0; keyIndex < keys.size(); keyIndex++) { for (int infoIndex = 0, keyIndex = 0; keyIndex < sortedKeys.size(); keyIndex++) {
final Key key = keys.get(keyIndex); final Key key = sortedKeys.get(keyIndex);
// Excluding from key coordinate arrays // Excluding from key coordinate arrays
if (!needsProximityInfo(key)) { if (!needsProximityInfo(key)) {
continue; continue;
@ -181,8 +181,8 @@ public class ProximityInfo {
final int rows = touchPositionCorrection.getRows(); final int rows = touchPositionCorrection.getRows();
final float defaultRadius = DEFAULT_TOUCH_POSITION_CORRECTION_RADIUS final float defaultRadius = DEFAULT_TOUCH_POSITION_CORRECTION_RADIUS
* (float)Math.hypot(mMostCommonKeyWidth, mMostCommonKeyHeight); * (float)Math.hypot(mMostCommonKeyWidth, mMostCommonKeyHeight);
for (int infoIndex = 0, keyIndex = 0; keyIndex < keys.size(); keyIndex++) { for (int infoIndex = 0, keyIndex = 0; keyIndex < sortedKeys.size(); keyIndex++) {
final Key key = keys.get(keyIndex); final Key key = sortedKeys.get(keyIndex);
// Excluding from touch position correction arrays // Excluding from touch position correction arrays
if (!needsProximityInfo(key)) { if (!needsProximityInfo(key)) {
continue; continue;
@ -244,7 +244,7 @@ public class ProximityInfo {
private void computeNearestNeighbors() { private void computeNearestNeighbors() {
final int defaultWidth = mMostCommonKeyWidth; final int defaultWidth = mMostCommonKeyWidth;
final int keyCount = mKeys.size(); final int keyCount = mSortedKeys.size();
final int gridSize = mGridNeighbors.length; final int gridSize = mGridNeighbors.length;
final int threshold = (int) (defaultWidth * SEARCH_DISTANCE); final int threshold = (int) (defaultWidth * SEARCH_DISTANCE);
final int thresholdSquared = threshold * threshold; final int thresholdSquared = threshold * threshold;
@ -263,7 +263,7 @@ public class ProximityInfo {
final int[] neighborCountPerCell = new int[gridSize]; final int[] neighborCountPerCell = new int[gridSize];
final int halfCellWidth = mCellWidth / 2; final int halfCellWidth = mCellWidth / 2;
final int halfCellHeight = mCellHeight / 2; final int halfCellHeight = mCellHeight / 2;
for (final Key key : mKeys) { for (final Key key : mSortedKeys) {
if (key.isSpacer()) continue; if (key.isSpacer()) continue;
/* HOW WE PRE-SELECT THE CELLS (iterate over only the relevant cells, instead of all of them) /* HOW WE PRE-SELECT THE CELLS (iterate over only the relevant cells, instead of all of them)

View File

@ -68,7 +68,7 @@ public class DynamicGridKeyboard extends Keyboard {
} }
private Key getTemplateKey(final int code) { private Key getTemplateKey(final int code) {
for (final Key key : super.getKeys()) { for (final Key key : super.getSortedKeys()) {
if (key.getCode() == code) { if (key.getCode() == code) {
return key; return key;
} }
@ -207,7 +207,7 @@ public class DynamicGridKeyboard extends Keyboard {
} }
@Override @Override
public List<Key> getKeys() { public List<Key> getSortedKeys() {
synchronized (mLock) { synchronized (mLock) {
if (mCachedGridKeys != null) { if (mCachedGridKeys != null) {
return mCachedGridKeys; return mCachedGridKeys;
@ -222,7 +222,7 @@ public class DynamicGridKeyboard extends Keyboard {
@Override @Override
public List<Key> getNearestKeys(final int x, final int y) { public List<Key> getNearestKeys(final int x, final int y) {
// TODO: Calculate the nearest key index in mGridKeys from x and y. // TODO: Calculate the nearest key index in mGridKeys from x and y.
return getKeys(); return getSortedKeys();
} }
static final class GridKey extends Key { static final class GridKey extends Key {

View File

@ -24,6 +24,8 @@ import com.android.inputmethod.latin.Constants;
import com.android.inputmethod.latin.utils.CollectionUtils; import com.android.inputmethod.latin.utils.CollectionUtils;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Comparator;
import java.util.SortedSet;
import java.util.TreeSet; import java.util.TreeSet;
public class KeyboardParams { public class KeyboardParams {
@ -58,7 +60,8 @@ public class KeyboardParams {
public int GRID_WIDTH; public int GRID_WIDTH;
public int GRID_HEIGHT; public int GRID_HEIGHT;
public final TreeSet<Key> mKeys = CollectionUtils.newTreeSet(); // ordered set // Keys are sorted from top-left to bottom-right order.
public final SortedSet<Key> mSortedKeys = new TreeSet<Key>(ROW_COLUMN_COMPARATOR);
public final ArrayList<Key> mShiftKeys = CollectionUtils.newArrayList(); public final ArrayList<Key> mShiftKeys = CollectionUtils.newArrayList();
public final ArrayList<Key> mAltCodeKeysWhileTyping = CollectionUtils.newArrayList(); public final ArrayList<Key> mAltCodeKeysWhileTyping = CollectionUtils.newArrayList();
public final KeyboardIconsSet mIconsSet = new KeyboardIconsSet(); public final KeyboardIconsSet mIconsSet = new KeyboardIconsSet();
@ -75,8 +78,20 @@ public class KeyboardParams {
public final TouchPositionCorrection mTouchPositionCorrection = public final TouchPositionCorrection mTouchPositionCorrection =
new TouchPositionCorrection(); new TouchPositionCorrection();
// Comparator to sort {@link Key}s from top-left to bottom-right order.
private static final Comparator<Key> ROW_COLUMN_COMPARATOR = new Comparator<Key>() {
@Override
public int compare(final Key lhs, final Key rhs) {
if (lhs.getY() < rhs.getY()) return -1;
if (lhs.getY() > rhs.getY()) return 1;
if (lhs.getX() < rhs.getX()) return -1;
if (lhs.getX() > rhs.getX()) return 1;
return 0;
}
};
protected void clearKeys() { protected void clearKeys() {
mKeys.clear(); mSortedKeys.clear();
mShiftKeys.clear(); mShiftKeys.clear();
clearHistogram(); clearHistogram();
} }
@ -88,7 +103,7 @@ public class KeyboardParams {
// Ignore zero width {@link Spacer}. // Ignore zero width {@link Spacer}.
return; return;
} }
mKeys.add(key); mSortedKeys.add(key);
if (isSpacer) { if (isSpacer) {
return; return;
} }

View File

@ -1362,7 +1362,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
kid.navigateNext(), kid.navigatePrevious(), kid.mClobberSettingsKey, kid.navigateNext(), kid.navigatePrevious(), kid.mClobberSettingsKey,
isPasswordView, kid.mSupportsSwitchingToShortcutIme, kid.mHasShortcutKey, isPasswordView, kid.mSupportsSwitchingToShortcutIme, kid.mHasShortcutKey,
kid.mLanguageSwitchKeyEnabled, kid.isMultiLine(), keyboard.mOccupiedWidth, kid.mLanguageSwitchKeyEnabled, kid.isMultiLine(), keyboard.mOccupiedWidth,
keyboard.mOccupiedHeight, keyboard.getKeys()); keyboard.mOccupiedHeight, keyboard.getSortedKeys());
} }
/** /**

View File

@ -24,27 +24,13 @@ import com.android.inputmethod.latin.utils.CollectionUtils;
import com.android.inputmethod.latin.utils.StringUtils; import com.android.inputmethod.latin.utils.StringUtils;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List; import java.util.List;
/** /**
* This class builds an actual keyboard for unit test. * This class builds an actual keyboard for unit test.
*/ */
public final class ActualKeyboardBuilder extends AbstractKeyboardBuilder<Key> { public final class ActualKeyboardBuilder extends AbstractKeyboardBuilder<Key> {
// Comparator to sort {@link Key}s from top-left to bottom-right order. private static ArrayList<Key> filterOutSpacer(final List<Key> keys) {
private static final Comparator<Key> ROW_COLUMN_COMPARATOR = new Comparator<Key>() {
@Override
public int compare(final Key lhs, final Key rhs) {
if (lhs.getY() < rhs.getY()) return -1;
if (lhs.getY() > rhs.getY()) return 1;
if (lhs.getX() < rhs.getX()) return -1;
if (lhs.getX() > rhs.getX()) return 1;
return 0;
}
};
private static ArrayList<Key> filterOutSpacerAndSortKeys(final List<Key> keys) {
final ArrayList<Key> filteredKeys = CollectionUtils.newArrayList(); final ArrayList<Key> filteredKeys = CollectionUtils.newArrayList();
for (final Key key : keys) { for (final Key key : keys) {
if (key.isSpacer()) { if (key.isSpacer()) {
@ -52,25 +38,23 @@ public final class ActualKeyboardBuilder extends AbstractKeyboardBuilder<Key> {
} }
filteredKeys.add(key); filteredKeys.add(key);
} }
Collections.sort(filteredKeys, ROW_COLUMN_COMPARATOR);
return filteredKeys; return filteredKeys;
} }
/** /**
* Create the keyboard that consists of the array of rows of the actual keyboard's keys. * Create the keyboard that consists of the array of rows of the actual keyboard's keys.
* @param keys the list of keys of the actual keyboard. * @param sortedKeys the sorted list of keys of the actual keyboard.
* @return the actual keyboard grouped with rows. * @return the actual keyboard grouped with rows.
*/ */
public static Key[][] buildKeyboard(final List<Key> keys) { public static Key[][] buildKeyboard(final List<Key> sortedKeys) {
// Filter out spacer and sort keys from top-left to bottom-right order to prepare to // Filter out spacer to prepare to create rows.
// create rows. final ArrayList<Key> filteredSortedKeys = filterOutSpacer(sortedKeys);
final ArrayList<Key> sortedKeys = filterOutSpacerAndSortKeys(keys);
// Grouping keys into rows. // Grouping keys into rows.
final ArrayList<ArrayList<Key>> rows = CollectionUtils.newArrayList(); final ArrayList<ArrayList<Key>> rows = CollectionUtils.newArrayList();
ArrayList<Key> elements = CollectionUtils.newArrayList(); ArrayList<Key> elements = CollectionUtils.newArrayList();
int lastY = sortedKeys.get(0).getY(); int lastY = filteredSortedKeys.get(0).getY();
for (final Key key : sortedKeys) { for (final Key key : filteredSortedKeys) {
if (lastY != key.getY()) { if (lastY != key.getY()) {
// A new row is starting. // A new row is starting.
lastY = key.getY(); lastY = key.getY();

View File

@ -150,7 +150,8 @@ abstract class LayoutTestsBase extends KeyboardLayoutSetTestsBase {
// Create actual keyboard object. // Create actual keyboard object.
final Keyboard keyboard = mKeyboardLayoutSet.getKeyboard(elementId); final Keyboard keyboard = mKeyboardLayoutSet.getKeyboard(elementId);
// Create actual keyboard to be compared with the expected keyboard. // Create actual keyboard to be compared with the expected keyboard.
final Key[][] actualKeyboard = ActualKeyboardBuilder.buildKeyboard(keyboard.getKeys()); final Key[][] actualKeyboard = ActualKeyboardBuilder.buildKeyboard(
keyboard.getSortedKeys());
// Dump human readable definition of expected/actual keyboards. // Dump human readable definition of expected/actual keyboards.
Log.d(tag, "expected=\n" + ExpectedKeyboardBuilder.toString(expectedKeyboard)); Log.d(tag, "expected=\n" + ExpectedKeyboardBuilder.toString(expectedKeyboard));