Auto mini keyboard layout

Bug: 4280617
Change-Id: I34c344cbf350fe125589aa14ad69e4bd1f4e6f66
main
Tadashi G. Takaoka 2011-04-13 17:57:29 +09:00
parent 72a82d7ee8
commit 5d542c2492
7 changed files with 1390 additions and 250 deletions

View File

@ -63,7 +63,7 @@
<!-- This configuration is the index of the array {@link KeyboardSwitcher.KEYBOARD_THEMES}. -->
<string name="config_default_keyboard_theme_id" translatable="false">4</string>
<string name="config_text_size_of_language_on_spacebar" translatable="false">small</string>
<integer name="config_max_popup_keyboard_column">10</integer>
<integer name="config_max_popup_keyboard_column">5</integer>
<!-- Whether or not auto-correction should be enabled by default -->
<bool name="enable_autocorrect">true</bool>
<string-array name="auto_correction_threshold_values" translatable="false">

View File

@ -17,7 +17,6 @@
package com.android.inputmethod.keyboard;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
public abstract class KeyDetector {
@ -110,31 +109,4 @@ public abstract class KeyDetector {
* @return The nearest key index
*/
abstract public int getKeyIndexAndNearbyCodes(int x, int y, final int[] allCodes);
/**
* Compute the most common key width in order to use it as proximity key detection threshold.
*
* @param keyboard The keyboard to compute the most common key width
* @return The most common key width in the keyboard
*/
public static int getMostCommonKeyWidth(final Keyboard keyboard) {
if (keyboard == null) return 0;
final List<Key> keys = keyboard.getKeys();
if (keys == null || keys.size() == 0) return 0;
final HashMap<Integer, Integer> histogram = new HashMap<Integer, Integer>();
int maxCount = 0;
int mostCommonWidth = 0;
for (final Key key : keys) {
final Integer width = key.mWidth + key.mGap;
Integer count = histogram.get(width);
if (count == null)
count = 0;
histogram.put(width, ++count);
if (count > maxCount) {
maxCount = count;
mostCommonWidth = width;
}
}
return mostCommonWidth + keyboard.getHorizontalGap();
}
}

View File

@ -405,6 +405,29 @@ public class Keyboard {
return EMPTY_INT_ARRAY;
}
/**
* Compute the most common key width in order to use it as proximity key detection threshold.
*
* @return The most common key width in the keyboard
*/
public int getMostCommonKeyWidth() {
final HashMap<Integer, Integer> histogram = new HashMap<Integer, Integer>();
int maxCount = 0;
int mostCommonWidth = 0;
for (final Key key : mKeys) {
final Integer width = key.mWidth + key.mGap;
Integer count = histogram.get(width);
if (count == null)
count = 0;
histogram.put(width, ++count);
if (count > maxCount) {
maxCount = count;
mostCommonWidth = width;
}
}
return mostCommonWidth;
}
private void loadKeyboard(Context context, int xmlLayoutResId) {
try {
KeyboardParser parser = new KeyboardParser(this, context.getResources());

View File

@ -501,7 +501,7 @@ public class KeyboardView extends View implements PointerTracker.UIProxy {
requestLayout();
mKeyboardChanged = true;
invalidateAllKeys();
mKeyDetector.setProximityThreshold(KeyDetector.getMostCommonKeyWidth(keyboard));
mKeyDetector.setProximityThreshold(keyboard.getMostCommonKeyWidth());
mMiniKeyboardCache.clear();
}

View File

@ -34,7 +34,7 @@ public class MiniKeyboardBuilder {
/* package */ static class MiniKeyboardLayoutParams {
public final int mKeyWidth;
public final int mRowHeight;
/* package */ final boolean mTopRowNeedsCentering;
/* package */ final int mTopRowAdjustment;
public final int mNumRows;
public final int mNumColumns;
public final int mLeftKeys;
@ -55,29 +55,52 @@ public class MiniKeyboardBuilder {
if (parentKeyboardWidth / keyWidth < maxColumns)
throw new IllegalArgumentException("Keyboard is too small to hold mini keyboard: "
+ parentKeyboardWidth + " " + keyWidth + " " + maxColumns);
final int numRows = (numKeys + maxColumns - 1) / maxColumns;
mKeyWidth = keyWidth;
mRowHeight = rowHeight;
mNumRows = numRows;
final int numColumns = Math.min(numKeys, maxColumns);
final int topRowKeys = numKeys % numColumns;
final int numRows = (numKeys + maxColumns - 1) / maxColumns;
mNumRows = numRows;
final int numColumns = getOptimizedColumns(numKeys, maxColumns);
mNumColumns = numColumns;
mTopRowNeedsCentering = topRowKeys != 0 && (numColumns - topRowKeys) % 2 != 0;
final int numLeftKeys = (numColumns - 1) / 2;
final int numRightKeys = numColumns - numLeftKeys; // including default key.
final int maxLeftKeys = coordXInParent / keyWidth;
final int maxRightKeys = Math.max(1, (parentKeyboardWidth - coordXInParent) / keyWidth);
int leftKeys, rightKeys;
if (numLeftKeys > maxLeftKeys) {
mLeftKeys = maxLeftKeys;
mRightKeys = numColumns - maxLeftKeys;
leftKeys = maxLeftKeys;
rightKeys = numColumns - maxLeftKeys;
} else if (numRightKeys > maxRightKeys) {
mLeftKeys = numColumns - maxRightKeys;
mRightKeys = maxRightKeys;
leftKeys = numColumns - maxRightKeys;
rightKeys = maxRightKeys;
} else {
mLeftKeys = numLeftKeys;
mRightKeys = numRightKeys;
leftKeys = numLeftKeys;
rightKeys = numRightKeys;
}
// Shift right if the left edge of mini keyboard is on the edge of parent keyboard
// unless the parent key is on the left edge.
if (leftKeys * keyWidth >= coordXInParent && leftKeys > 0) {
leftKeys--;
rightKeys++;
}
// Shift left if the right edge of mini keyboard is on the edge of parent keyboard
// unless the parent key is on the right edge.
if (rightKeys * keyWidth + coordXInParent >= parentKeyboardWidth && rightKeys > 1) {
leftKeys++;
rightKeys--;
}
mLeftKeys = leftKeys;
mRightKeys = rightKeys;
// Centering of the top row.
final boolean onEdge = (leftKeys == 0 || rightKeys == 1);
if (numRows < 2 || onEdge || getTopRowEmptySlots(numKeys, numColumns) % 2 == 0) {
mTopRowAdjustment = 0;
} else if (mLeftKeys < mRightKeys - 1) {
mTopRowAdjustment = 1;
} else {
mTopRowAdjustment = -1;
}
}
@ -113,14 +136,32 @@ public class MiniKeyboardBuilder {
return pos;
}
private static int getTopRowEmptySlots(int numKeys, int numColumns) {
final int remainingKeys = numKeys % numColumns;
if (remainingKeys == 0) {
return 0;
} else {
return numColumns - remainingKeys;
}
}
private int getOptimizedColumns(int numKeys, int maxColumns) {
int numColumns = Math.min(numKeys, maxColumns);
while (getTopRowEmptySlots(numKeys, numColumns) >= mNumRows) {
numColumns--;
}
return numColumns;
}
public int getDefaultKeyCoordX() {
return mLeftKeys * mKeyWidth;
}
public int getX(int n, int row) {
final int x = getColumnPos(n) * mKeyWidth + getDefaultKeyCoordX();
if (isLastRow(row) && mTopRowNeedsCentering)
return x - mKeyWidth / 2;
if (isTopRow(row)) {
return x + mTopRowAdjustment * (mKeyWidth / 2);
}
return x;
}
@ -131,27 +172,27 @@ public class MiniKeyboardBuilder {
public int getRowFlags(int row) {
int rowFlags = 0;
if (row == 0) rowFlags |= Keyboard.EDGE_TOP;
if (isLastRow(row)) rowFlags |= Keyboard.EDGE_BOTTOM;
if (isTopRow(row)) rowFlags |= Keyboard.EDGE_BOTTOM;
return rowFlags;
}
private boolean isLastRow(int rowCount) {
private boolean isTopRow(int rowCount) {
return rowCount == mNumRows - 1;
}
}
public MiniKeyboardBuilder(KeyboardView view, int layoutTemplateResId, Key popupKey) {
public MiniKeyboardBuilder(KeyboardView view, int layoutTemplateResId, Key parentKey) {
final Context context = view.getContext();
mRes = context.getResources();
final MiniKeyboard keyboard = new MiniKeyboard(context, layoutTemplateResId, null);
mKeyboard = keyboard;
mPopupCharacters = popupKey.mPopupCharacters;
mPopupCharacters = parentKey.mPopupCharacters;
final int keyWidth = getMaxKeyWidth(view, mPopupCharacters, keyboard.getKeyWidth());
final MiniKeyboardLayoutParams params = new MiniKeyboardLayoutParams(
mPopupCharacters.length, popupKey.mMaxPopupColumn,
mPopupCharacters.length, parentKey.mMaxPopupColumn,
keyWidth, keyboard.getRowHeight(),
popupKey.mX + (popupKey.mWidth + popupKey.mGap) / 2 - keyWidth / 2,
parentKey.mX + (parentKey.mWidth + parentKey.mGap) / 2 - keyWidth / 2,
view.getMeasuredWidth());
mParams = params;

View File

@ -55,7 +55,7 @@ public class SuggestHelper {
mSuggest.setCorrectionMode(Suggest.CORRECTION_FULL);
mKeyDetector.setKeyboard(mKeyboard, 0, 0);
mKeyDetector.setProximityCorrectionEnabled(true);
mKeyDetector.setProximityThreshold(KeyDetector.getMostCommonKeyWidth(mKeyboard));
mKeyDetector.setProximityThreshold(mKeyboard.getMostCommonKeyWidth());
}
public void setCorrectionMode(int correctionMode) {