Auto mini keyboard layout
Bug: 4280617 Change-Id: I34c344cbf350fe125589aa14ad69e4bd1f4e6f66main
parent
72a82d7ee8
commit
5d542c2492
|
@ -63,7 +63,7 @@
|
||||||
<!-- This configuration is the index of the array {@link KeyboardSwitcher.KEYBOARD_THEMES}. -->
|
<!-- 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_default_keyboard_theme_id" translatable="false">4</string>
|
||||||
<string name="config_text_size_of_language_on_spacebar" translatable="false">small</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 -->
|
<!-- Whether or not auto-correction should be enabled by default -->
|
||||||
<bool name="enable_autocorrect">true</bool>
|
<bool name="enable_autocorrect">true</bool>
|
||||||
<string-array name="auto_correction_threshold_values" translatable="false">
|
<string-array name="auto_correction_threshold_values" translatable="false">
|
||||||
|
|
|
@ -17,7 +17,6 @@
|
||||||
package com.android.inputmethod.keyboard;
|
package com.android.inputmethod.keyboard;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public abstract class KeyDetector {
|
public abstract class KeyDetector {
|
||||||
|
@ -110,31 +109,4 @@ public abstract class KeyDetector {
|
||||||
* @return The nearest key index
|
* @return The nearest key index
|
||||||
*/
|
*/
|
||||||
abstract public int getKeyIndexAndNearbyCodes(int x, int y, final int[] allCodes);
|
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();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -405,6 +405,29 @@ public class Keyboard {
|
||||||
return EMPTY_INT_ARRAY;
|
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) {
|
private void loadKeyboard(Context context, int xmlLayoutResId) {
|
||||||
try {
|
try {
|
||||||
KeyboardParser parser = new KeyboardParser(this, context.getResources());
|
KeyboardParser parser = new KeyboardParser(this, context.getResources());
|
||||||
|
|
|
@ -501,7 +501,7 @@ public class KeyboardView extends View implements PointerTracker.UIProxy {
|
||||||
requestLayout();
|
requestLayout();
|
||||||
mKeyboardChanged = true;
|
mKeyboardChanged = true;
|
||||||
invalidateAllKeys();
|
invalidateAllKeys();
|
||||||
mKeyDetector.setProximityThreshold(KeyDetector.getMostCommonKeyWidth(keyboard));
|
mKeyDetector.setProximityThreshold(keyboard.getMostCommonKeyWidth());
|
||||||
mMiniKeyboardCache.clear();
|
mMiniKeyboardCache.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -34,7 +34,7 @@ public class MiniKeyboardBuilder {
|
||||||
/* package */ static class MiniKeyboardLayoutParams {
|
/* package */ static class MiniKeyboardLayoutParams {
|
||||||
public final int mKeyWidth;
|
public final int mKeyWidth;
|
||||||
public final int mRowHeight;
|
public final int mRowHeight;
|
||||||
/* package */ final boolean mTopRowNeedsCentering;
|
/* package */ final int mTopRowAdjustment;
|
||||||
public final int mNumRows;
|
public final int mNumRows;
|
||||||
public final int mNumColumns;
|
public final int mNumColumns;
|
||||||
public final int mLeftKeys;
|
public final int mLeftKeys;
|
||||||
|
@ -55,29 +55,52 @@ public class MiniKeyboardBuilder {
|
||||||
if (parentKeyboardWidth / keyWidth < maxColumns)
|
if (parentKeyboardWidth / keyWidth < maxColumns)
|
||||||
throw new IllegalArgumentException("Keyboard is too small to hold mini keyboard: "
|
throw new IllegalArgumentException("Keyboard is too small to hold mini keyboard: "
|
||||||
+ parentKeyboardWidth + " " + keyWidth + " " + maxColumns);
|
+ parentKeyboardWidth + " " + keyWidth + " " + maxColumns);
|
||||||
final int numRows = (numKeys + maxColumns - 1) / maxColumns;
|
|
||||||
mKeyWidth = keyWidth;
|
mKeyWidth = keyWidth;
|
||||||
mRowHeight = rowHeight;
|
mRowHeight = rowHeight;
|
||||||
mNumRows = numRows;
|
|
||||||
|
|
||||||
final int numColumns = Math.min(numKeys, maxColumns);
|
final int numRows = (numKeys + maxColumns - 1) / maxColumns;
|
||||||
final int topRowKeys = numKeys % numColumns;
|
mNumRows = numRows;
|
||||||
|
final int numColumns = getOptimizedColumns(numKeys, maxColumns);
|
||||||
mNumColumns = numColumns;
|
mNumColumns = numColumns;
|
||||||
mTopRowNeedsCentering = topRowKeys != 0 && (numColumns - topRowKeys) % 2 != 0;
|
|
||||||
|
|
||||||
final int numLeftKeys = (numColumns - 1) / 2;
|
final int numLeftKeys = (numColumns - 1) / 2;
|
||||||
final int numRightKeys = numColumns - numLeftKeys; // including default key.
|
final int numRightKeys = numColumns - numLeftKeys; // including default key.
|
||||||
final int maxLeftKeys = coordXInParent / keyWidth;
|
final int maxLeftKeys = coordXInParent / keyWidth;
|
||||||
final int maxRightKeys = Math.max(1, (parentKeyboardWidth - coordXInParent) / keyWidth);
|
final int maxRightKeys = Math.max(1, (parentKeyboardWidth - coordXInParent) / keyWidth);
|
||||||
|
int leftKeys, rightKeys;
|
||||||
if (numLeftKeys > maxLeftKeys) {
|
if (numLeftKeys > maxLeftKeys) {
|
||||||
mLeftKeys = maxLeftKeys;
|
leftKeys = maxLeftKeys;
|
||||||
mRightKeys = numColumns - maxLeftKeys;
|
rightKeys = numColumns - maxLeftKeys;
|
||||||
} else if (numRightKeys > maxRightKeys) {
|
} else if (numRightKeys > maxRightKeys) {
|
||||||
mLeftKeys = numColumns - maxRightKeys;
|
leftKeys = numColumns - maxRightKeys;
|
||||||
mRightKeys = maxRightKeys;
|
rightKeys = maxRightKeys;
|
||||||
} else {
|
} else {
|
||||||
mLeftKeys = numLeftKeys;
|
leftKeys = numLeftKeys;
|
||||||
mRightKeys = numRightKeys;
|
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;
|
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() {
|
public int getDefaultKeyCoordX() {
|
||||||
return mLeftKeys * mKeyWidth;
|
return mLeftKeys * mKeyWidth;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getX(int n, int row) {
|
public int getX(int n, int row) {
|
||||||
final int x = getColumnPos(n) * mKeyWidth + getDefaultKeyCoordX();
|
final int x = getColumnPos(n) * mKeyWidth + getDefaultKeyCoordX();
|
||||||
if (isLastRow(row) && mTopRowNeedsCentering)
|
if (isTopRow(row)) {
|
||||||
return x - mKeyWidth / 2;
|
return x + mTopRowAdjustment * (mKeyWidth / 2);
|
||||||
|
}
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -131,27 +172,27 @@ public class MiniKeyboardBuilder {
|
||||||
public int getRowFlags(int row) {
|
public int getRowFlags(int row) {
|
||||||
int rowFlags = 0;
|
int rowFlags = 0;
|
||||||
if (row == 0) rowFlags |= Keyboard.EDGE_TOP;
|
if (row == 0) rowFlags |= Keyboard.EDGE_TOP;
|
||||||
if (isLastRow(row)) rowFlags |= Keyboard.EDGE_BOTTOM;
|
if (isTopRow(row)) rowFlags |= Keyboard.EDGE_BOTTOM;
|
||||||
return rowFlags;
|
return rowFlags;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isLastRow(int rowCount) {
|
private boolean isTopRow(int rowCount) {
|
||||||
return rowCount == mNumRows - 1;
|
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();
|
final Context context = view.getContext();
|
||||||
mRes = context.getResources();
|
mRes = context.getResources();
|
||||||
final MiniKeyboard keyboard = new MiniKeyboard(context, layoutTemplateResId, null);
|
final MiniKeyboard keyboard = new MiniKeyboard(context, layoutTemplateResId, null);
|
||||||
mKeyboard = keyboard;
|
mKeyboard = keyboard;
|
||||||
mPopupCharacters = popupKey.mPopupCharacters;
|
mPopupCharacters = parentKey.mPopupCharacters;
|
||||||
|
|
||||||
final int keyWidth = getMaxKeyWidth(view, mPopupCharacters, keyboard.getKeyWidth());
|
final int keyWidth = getMaxKeyWidth(view, mPopupCharacters, keyboard.getKeyWidth());
|
||||||
final MiniKeyboardLayoutParams params = new MiniKeyboardLayoutParams(
|
final MiniKeyboardLayoutParams params = new MiniKeyboardLayoutParams(
|
||||||
mPopupCharacters.length, popupKey.mMaxPopupColumn,
|
mPopupCharacters.length, parentKey.mMaxPopupColumn,
|
||||||
keyWidth, keyboard.getRowHeight(),
|
keyWidth, keyboard.getRowHeight(),
|
||||||
popupKey.mX + (popupKey.mWidth + popupKey.mGap) / 2 - keyWidth / 2,
|
parentKey.mX + (parentKey.mWidth + parentKey.mGap) / 2 - keyWidth / 2,
|
||||||
view.getMeasuredWidth());
|
view.getMeasuredWidth());
|
||||||
mParams = params;
|
mParams = params;
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -55,7 +55,7 @@ public class SuggestHelper {
|
||||||
mSuggest.setCorrectionMode(Suggest.CORRECTION_FULL);
|
mSuggest.setCorrectionMode(Suggest.CORRECTION_FULL);
|
||||||
mKeyDetector.setKeyboard(mKeyboard, 0, 0);
|
mKeyDetector.setKeyboard(mKeyboard, 0, 0);
|
||||||
mKeyDetector.setProximityCorrectionEnabled(true);
|
mKeyDetector.setProximityCorrectionEnabled(true);
|
||||||
mKeyDetector.setProximityThreshold(KeyDetector.getMostCommonKeyWidth(mKeyboard));
|
mKeyDetector.setProximityThreshold(mKeyboard.getMostCommonKeyWidth());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setCorrectionMode(int correctionMode) {
|
public void setCorrectionMode(int correctionMode) {
|
||||||
|
|
Loading…
Reference in New Issue