am 09f8b126: Add Key preserveCase enum to keyLabelOptions attribute
* commit '09f8b126e532ca2ac6bbe00c0d78bf03e44b78a2': Add Key preserveCase enum to keyLabelOptions attributemain
commit
1b709fe947
|
@ -242,6 +242,9 @@
|
||||||
<flag name="withIconLeft" value="0x1000" />
|
<flag name="withIconLeft" value="0x1000" />
|
||||||
<flag name="withIconRight" value="0x2000" />
|
<flag name="withIconRight" value="0x2000" />
|
||||||
<flag name="autoXScale" value="0x4000" />
|
<flag name="autoXScale" value="0x4000" />
|
||||||
|
<!-- If true, character case of code, altCode, moreKeys, keyOutputText, keyLabel,
|
||||||
|
or keyHintLabel will never be subject to change. -->
|
||||||
|
<flag name="preserveCase" value="0x8000" />
|
||||||
</attr>
|
</attr>
|
||||||
<!-- The icon to display on the key instead of the label. -->
|
<!-- The icon to display on the key instead of the label. -->
|
||||||
<attr name="keyIcon" format="enum">
|
<attr name="keyIcon" format="enum">
|
||||||
|
|
|
@ -23,7 +23,8 @@
|
||||||
latin:keyboardLocale="en_GB,en_US">
|
latin:keyboardLocale="en_GB,en_US">
|
||||||
<Element
|
<Element
|
||||||
latin:elementName="alphabet"
|
latin:elementName="alphabet"
|
||||||
latin:elementKeyboard="@xml/kbd_qwerty" />
|
latin:elementKeyboard="@xml/kbd_qwerty"
|
||||||
|
latin:elementAutoGenerate="true" />
|
||||||
<Element
|
<Element
|
||||||
latin:elementName="alphabetManualShifted"
|
latin:elementName="alphabetManualShifted"
|
||||||
latin:elementKeyboard="@xml/kbd_qwerty"
|
latin:elementKeyboard="@xml/kbd_qwerty"
|
||||||
|
|
|
@ -71,6 +71,7 @@ public class Key {
|
||||||
private static final int LABEL_FLAGS_WITH_ICON_LEFT = 0x1000;
|
private static final int LABEL_FLAGS_WITH_ICON_LEFT = 0x1000;
|
||||||
private static final int LABEL_FLAGS_WITH_ICON_RIGHT = 0x2000;
|
private static final int LABEL_FLAGS_WITH_ICON_RIGHT = 0x2000;
|
||||||
private static final int LABEL_FLAGS_AUTO_X_SCALE = 0x4000;
|
private static final int LABEL_FLAGS_AUTO_X_SCALE = 0x4000;
|
||||||
|
private static final int LABEL_FLAGS_PRESERVE_CASE = 0x8000;
|
||||||
|
|
||||||
/** Icon to display instead of a label. Icon takes precedence over a label */
|
/** Icon to display instead of a label. Icon takes precedence over a label */
|
||||||
private final int mIconAttrId;
|
private final int mIconAttrId;
|
||||||
|
@ -262,19 +263,6 @@ public class Key {
|
||||||
// Update row to have current x coordinate.
|
// Update row to have current x coordinate.
|
||||||
row.setXPos(keyXPos + keyWidth);
|
row.setXPos(keyXPos + keyWidth);
|
||||||
|
|
||||||
final String[] moreKeys = style.getStringArray(keyAttr,
|
|
||||||
R.styleable.Keyboard_Key_moreKeys);
|
|
||||||
// In Arabic symbol layouts, we'd like to keep digits in more keys regardless of
|
|
||||||
// config_digit_more_keys_enabled.
|
|
||||||
if (params.mId.isAlphabetKeyboard()
|
|
||||||
&& !res.getBoolean(R.bool.config_digit_more_keys_enabled)) {
|
|
||||||
mMoreKeys = MoreKeySpecParser.filterOut(res, moreKeys, MoreKeySpecParser.DIGIT_FILTER);
|
|
||||||
} else {
|
|
||||||
mMoreKeys = moreKeys;
|
|
||||||
}
|
|
||||||
mMaxMoreKeysColumn = style.getInt(keyAttr,
|
|
||||||
R.styleable.Keyboard_Key_maxMoreKeysColumn, params.mMaxMiniKeyboardColumn);
|
|
||||||
|
|
||||||
mBackgroundType = style.getInt(keyAttr,
|
mBackgroundType = style.getInt(keyAttr,
|
||||||
R.styleable.Keyboard_Key_backgroundType, BACKGROUND_TYPE_NORMAL);
|
R.styleable.Keyboard_Key_backgroundType, BACKGROUND_TYPE_NORMAL);
|
||||||
mActionFlags = style.getFlag(keyAttr, R.styleable.Keyboard_Key_keyActionFlags, 0);
|
mActionFlags = style.getFlag(keyAttr, R.styleable.Keyboard_Key_keyActionFlags, 0);
|
||||||
|
@ -292,14 +280,39 @@ public class Key {
|
||||||
mDisabledIconAttrId = KeyboardIconsSet.getIconAttrId(style.getInt(keyAttr,
|
mDisabledIconAttrId = KeyboardIconsSet.getIconAttrId(style.getInt(keyAttr,
|
||||||
R.styleable.Keyboard_Key_keyIconDisabled, KeyboardIconsSet.ICON_UNDEFINED));
|
R.styleable.Keyboard_Key_keyIconDisabled, KeyboardIconsSet.ICON_UNDEFINED));
|
||||||
|
|
||||||
mLabel = style.getString(keyAttr, R.styleable.Keyboard_Key_keyLabel);
|
|
||||||
mHintLabel = style.getString(keyAttr, R.styleable.Keyboard_Key_keyHintLabel);
|
|
||||||
mLabelFlags = style.getFlag(keyAttr, R.styleable.Keyboard_Key_keyLabelFlags, 0);
|
mLabelFlags = style.getFlag(keyAttr, R.styleable.Keyboard_Key_keyLabelFlags, 0);
|
||||||
mOutputText = style.getString(keyAttr, R.styleable.Keyboard_Key_keyOutputText);
|
final boolean preserveCase = (mLabelFlags & LABEL_FLAGS_PRESERVE_CASE) != 0;
|
||||||
|
|
||||||
|
final String[] moreKeys = style.getStringArray(keyAttr, R.styleable.Keyboard_Key_moreKeys);
|
||||||
|
if (moreKeys != null) {
|
||||||
|
for (int i = 0; i < moreKeys.length; i++) {
|
||||||
|
moreKeys[i] = adjustCaseOfStringForKeyboardId(
|
||||||
|
moreKeys[i], preserveCase, params.mId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// TODO: Add new key label flag to control this.
|
||||||
|
// In Arabic symbol layouts, we'd like to keep digits in more keys regardless of
|
||||||
|
// config_digit_more_keys_enabled.
|
||||||
|
if (params.mId.isAlphabetKeyboard()
|
||||||
|
&& !res.getBoolean(R.bool.config_digit_more_keys_enabled)) {
|
||||||
|
mMoreKeys = MoreKeySpecParser.filterOut(res, moreKeys, MoreKeySpecParser.DIGIT_FILTER);
|
||||||
|
} else {
|
||||||
|
mMoreKeys = moreKeys;
|
||||||
|
}
|
||||||
|
mMaxMoreKeysColumn = style.getInt(keyAttr,
|
||||||
|
R.styleable.Keyboard_Key_maxMoreKeysColumn, params.mMaxMiniKeyboardColumn);
|
||||||
|
|
||||||
|
mLabel = adjustCaseOfStringForKeyboardId(style.getString(
|
||||||
|
keyAttr, R.styleable.Keyboard_Key_keyLabel), preserveCase, params.mId);
|
||||||
|
mHintLabel = adjustCaseOfStringForKeyboardId(style.getString(
|
||||||
|
keyAttr, R.styleable.Keyboard_Key_keyHintLabel), preserveCase, params.mId);
|
||||||
|
mOutputText = adjustCaseOfStringForKeyboardId(style.getString(
|
||||||
|
keyAttr, R.styleable.Keyboard_Key_keyOutputText), preserveCase, params.mId);
|
||||||
// Choose the first letter of the label as primary code if not
|
// Choose the first letter of the label as primary code if not
|
||||||
// specified.
|
// specified.
|
||||||
final int code = style.getInt(keyAttr, R.styleable.Keyboard_Key_code,
|
final int code = adjustCaseOfCodeForKeyboardId(style.getInt(
|
||||||
Keyboard.CODE_UNSPECIFIED);
|
keyAttr, R.styleable.Keyboard_Key_code, Keyboard.CODE_UNSPECIFIED), preserveCase,
|
||||||
|
params.mId);
|
||||||
if (code == Keyboard.CODE_UNSPECIFIED && mOutputText == null
|
if (code == Keyboard.CODE_UNSPECIFIED && mOutputText == null
|
||||||
&& !TextUtils.isEmpty(mLabel)) {
|
&& !TextUtils.isEmpty(mLabel)) {
|
||||||
if (mLabel.length() != 1) {
|
if (mLabel.length() != 1) {
|
||||||
|
@ -312,13 +325,36 @@ public class Key {
|
||||||
} else {
|
} else {
|
||||||
mCode = code;
|
mCode = code;
|
||||||
}
|
}
|
||||||
mAltCode = style.getInt(keyAttr,
|
mAltCode = adjustCaseOfCodeForKeyboardId(style.getInt(keyAttr,
|
||||||
R.styleable.Keyboard_Key_altCode, Keyboard.CODE_UNSPECIFIED);
|
R.styleable.Keyboard_Key_altCode, Keyboard.CODE_UNSPECIFIED), preserveCase,
|
||||||
|
params.mId);
|
||||||
mHashCode = hashCode(this);
|
mHashCode = hashCode(this);
|
||||||
|
|
||||||
keyAttr.recycle();
|
keyAttr.recycle();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static int adjustCaseOfCodeForKeyboardId(int code, boolean preserveCase,
|
||||||
|
KeyboardId id) {
|
||||||
|
if (!Keyboard.isLetterCode(code) || preserveCase) return code;
|
||||||
|
final String text = new String(new int[] { code } , 0, 1);
|
||||||
|
final String casedText = adjustCaseOfStringForKeyboardId(text, preserveCase, id);
|
||||||
|
return casedText.codePointAt(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String adjustCaseOfStringForKeyboardId(String text, boolean preserveCase,
|
||||||
|
KeyboardId id) {
|
||||||
|
if (text == null || preserveCase) return text;
|
||||||
|
switch (id.mElementId) {
|
||||||
|
case KeyboardId.ELEMENT_ALPHABET_MANUAL_SHIFTED:
|
||||||
|
case KeyboardId.ELEMENT_ALPHABET_AUTOMATIC_SHIFTED:
|
||||||
|
case KeyboardId.ELEMENT_ALPHABET_SHIFT_LOCKED:
|
||||||
|
case KeyboardId.ELEMENT_ALPHABET_SHIFT_LOCK_SHIFTED:
|
||||||
|
return text.toUpperCase(id.mLocale);
|
||||||
|
default:
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static int hashCode(Key key) {
|
private static int hashCode(Key key) {
|
||||||
return Arrays.hashCode(new Object[] {
|
return Arrays.hashCode(new Object[] {
|
||||||
key.mX,
|
key.mX,
|
||||||
|
|
|
@ -293,6 +293,8 @@ public class Keyboard {
|
||||||
public final Set<Key> mShiftLockKeys = new HashSet<Key>();
|
public final Set<Key> mShiftLockKeys = new HashSet<Key>();
|
||||||
public final KeyboardIconsSet mIconsSet = new KeyboardIconsSet();
|
public final KeyboardIconsSet mIconsSet = new KeyboardIconsSet();
|
||||||
|
|
||||||
|
public KeyboardSet.KeysCache mKeysCache;
|
||||||
|
|
||||||
public int mMostCommonKeyHeight = 0;
|
public int mMostCommonKeyHeight = 0;
|
||||||
public int mMostCommonKeyWidth = 0;
|
public int mMostCommonKeyWidth = 0;
|
||||||
|
|
||||||
|
@ -361,7 +363,8 @@ public class Keyboard {
|
||||||
clearHistogram();
|
clearHistogram();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onAddKey(Key key) {
|
public void onAddKey(Key newKey) {
|
||||||
|
final Key key = (mKeysCache != null) ? mKeysCache.get(newKey) : newKey;
|
||||||
mKeys.add(key);
|
mKeys.add(key);
|
||||||
updateHistogram(key);
|
updateHistogram(key);
|
||||||
if (key.mCode == Keyboard.CODE_SHIFT) {
|
if (key.mCode == Keyboard.CODE_SHIFT) {
|
||||||
|
@ -688,6 +691,10 @@ public class Keyboard {
|
||||||
params.mTouchPositionCorrection.load(data);
|
params.mTouchPositionCorrection.load(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setAutoGenerate(KeyboardSet.KeysCache keysCache) {
|
||||||
|
mParams.mKeysCache = keysCache;
|
||||||
|
}
|
||||||
|
|
||||||
public Builder<KP> load(int xmlId, KeyboardId id) {
|
public Builder<KP> load(int xmlId, KeyboardId id) {
|
||||||
mParams.mId = id;
|
mParams.mId = id;
|
||||||
final XmlResourceParser parser = mResources.getXml(xmlId);
|
final XmlResourceParser parser = mResources.getXml(xmlId);
|
||||||
|
|
|
@ -57,6 +57,25 @@ public class KeyboardSet {
|
||||||
|
|
||||||
private final Context mContext;
|
private final Context mContext;
|
||||||
private final Params mParams;
|
private final Params mParams;
|
||||||
|
private final KeysCache mKeysCache = new KeysCache();
|
||||||
|
|
||||||
|
public static class KeysCache {
|
||||||
|
private final Map<Key, Key> mMap;
|
||||||
|
|
||||||
|
public KeysCache() {
|
||||||
|
mMap = new HashMap<Key, Key>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Key get(Key key) {
|
||||||
|
final Key existingKey = mMap.get(key);
|
||||||
|
if (existingKey != null) {
|
||||||
|
// Reuse the existing element that equals to "key" without adding "key" to the map.
|
||||||
|
return existingKey;
|
||||||
|
}
|
||||||
|
mMap.put(key, key);
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static class KeyboardElement {
|
static class KeyboardElement {
|
||||||
final int mElementId;
|
final int mElementId;
|
||||||
|
@ -99,15 +118,15 @@ public class KeyboardSet {
|
||||||
}
|
}
|
||||||
|
|
||||||
public Keyboard getMainKeyboard() {
|
public Keyboard getMainKeyboard() {
|
||||||
return getKeyboard(false, false);
|
return getKeyboard(false, false, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Keyboard getSymbolsKeyboard() {
|
public Keyboard getSymbolsKeyboard() {
|
||||||
return getKeyboard(true, false);
|
return getKeyboard(true, false, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Keyboard getSymbolsShiftedKeyboard() {
|
public Keyboard getSymbolsShiftedKeyboard() {
|
||||||
final Keyboard keyboard = getKeyboard(true, true);
|
final Keyboard keyboard = getKeyboard(true, false, true);
|
||||||
// TODO: Remove this logic once we introduce initial keyboard shift state attribute.
|
// TODO: Remove this logic once we introduce initial keyboard shift state attribute.
|
||||||
// Symbol shift keyboard may have a shift key that has a caps lock style indicator (a.k.a.
|
// Symbol shift keyboard may have a shift key that has a caps lock style indicator (a.k.a.
|
||||||
// sticky shift key). To show or dismiss the indicator, we need to call setShiftLocked()
|
// sticky shift key). To show or dismiss the indicator, we need to call setShiftLocked()
|
||||||
|
@ -116,22 +135,23 @@ public class KeyboardSet {
|
||||||
return keyboard;
|
return keyboard;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Keyboard getKeyboard(boolean isSymbols, boolean isShift) {
|
private Keyboard getKeyboard(boolean isSymbols, boolean isShiftLock, boolean isShift) {
|
||||||
final int elementId = KeyboardSet.getElementId(mParams.mMode, isSymbols, isShift);
|
final int elementId = KeyboardSet.getElementId(
|
||||||
|
mParams.mMode, isSymbols, isShiftLock, isShift);
|
||||||
final KeyboardElement keyboardElement = mParams.mElementKeyboards.get(elementId);
|
final KeyboardElement keyboardElement = mParams.mElementKeyboards.get(elementId);
|
||||||
// TODO: If keyboardElement.mAutoGenerate is true, the keyboard will be auto generated
|
// TODO: If keyboardElement.mAutoGenerate is true, the keyboard will be auto generated
|
||||||
// based on keyboardElement.mKayoutId Keyboard XML definition.
|
// based on keyboardElement.mKayoutId Keyboard XML definition.
|
||||||
final KeyboardId id = KeyboardSet.getKeyboardId(elementId, isSymbols, mParams);
|
final KeyboardId id = KeyboardSet.getKeyboardId(elementId, isSymbols, mParams);
|
||||||
final Keyboard keyboard = getKeyboard(mContext, keyboardElement.mLayoutId, id);
|
final Keyboard keyboard = getKeyboard(mContext, keyboardElement, id);
|
||||||
return keyboard;
|
return keyboard;
|
||||||
}
|
}
|
||||||
|
|
||||||
public KeyboardId getMainKeyboardId() {
|
public KeyboardId getMainKeyboardId() {
|
||||||
final int elementId = KeyboardSet.getElementId(mParams.mMode, false, false);
|
final int elementId = KeyboardSet.getElementId(mParams.mMode, false, false, false);
|
||||||
return KeyboardSet.getKeyboardId(elementId, false, mParams);
|
return KeyboardSet.getKeyboardId(elementId, false, mParams);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Keyboard getKeyboard(Context context, int xmlId, KeyboardId id) {
|
private Keyboard getKeyboard(Context context, KeyboardElement element, KeyboardId id) {
|
||||||
final Resources res = context.getResources();
|
final Resources res = context.getResources();
|
||||||
final SoftReference<Keyboard> ref = sKeyboardCache.get(id);
|
final SoftReference<Keyboard> ref = sKeyboardCache.get(id);
|
||||||
Keyboard keyboard = (ref == null) ? null : ref.get();
|
Keyboard keyboard = (ref == null) ? null : ref.get();
|
||||||
|
@ -140,7 +160,10 @@ public class KeyboardSet {
|
||||||
try {
|
try {
|
||||||
final Keyboard.Builder<Keyboard.Params> builder =
|
final Keyboard.Builder<Keyboard.Params> builder =
|
||||||
new Keyboard.Builder<Keyboard.Params>(context, new Keyboard.Params());
|
new Keyboard.Builder<Keyboard.Params>(context, new Keyboard.Params());
|
||||||
builder.load(xmlId, id);
|
if (element.mAutoGenerate) {
|
||||||
|
builder.setAutoGenerate(mKeysCache);
|
||||||
|
}
|
||||||
|
builder.load(element.mLayoutId, id);
|
||||||
builder.setTouchPositionCorrectionEnabled(mParams.mTouchPositionCorrectionEnabled);
|
builder.setTouchPositionCorrectionEnabled(mParams.mTouchPositionCorrectionEnabled);
|
||||||
keyboard = builder.build();
|
keyboard = builder.build();
|
||||||
} finally {
|
} finally {
|
||||||
|
@ -162,7 +185,8 @@ public class KeyboardSet {
|
||||||
return keyboard;
|
return keyboard;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int getElementId(int mode, boolean isSymbols, boolean isShift) {
|
private static int getElementId(int mode, boolean isSymbols, boolean isShiftLock,
|
||||||
|
boolean isShift) {
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
case KeyboardId.MODE_PHONE:
|
case KeyboardId.MODE_PHONE:
|
||||||
return (isSymbols && isShift)
|
return (isSymbols && isShift)
|
||||||
|
@ -174,6 +198,7 @@ public class KeyboardSet {
|
||||||
return isShift
|
return isShift
|
||||||
? KeyboardId.ELEMENT_SYMBOLS_SHIFTED : KeyboardId.ELEMENT_SYMBOLS;
|
? KeyboardId.ELEMENT_SYMBOLS_SHIFTED : KeyboardId.ELEMENT_SYMBOLS;
|
||||||
}
|
}
|
||||||
|
// TODO: Consult isShiftLock and isShift to determine the element.
|
||||||
return KeyboardId.ELEMENT_ALPHABET;
|
return KeyboardId.ELEMENT_ALPHABET;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue