Add GridRows tag to support emoji keyboard

Bug: 6370846
Change-Id: Ia68284b2402e52d835040da900a51cca669add2f
main
Tadashi G. Takaoka 2013-08-26 13:09:19 +09:00
parent c120199f72
commit 2f5a933c04
14 changed files with 436 additions and 1 deletions

View File

@ -79,4 +79,7 @@
<dimen name="gesture_floating_preview_text_offset">54dp</dimen> <dimen name="gesture_floating_preview_text_offset">54dp</dimen>
<dimen name="gesture_floating_preview_horizontal_padding">23dp</dimen> <dimen name="gesture_floating_preview_horizontal_padding">23dp</dimen>
<dimen name="gesture_floating_preview_vertical_padding">15dp</dimen> <dimen name="gesture_floating_preview_vertical_padding">15dp</dimen>
<!-- Emoji keyboard -->
<fraction name="emoji_keyboard_key_width">8.3333%p</fraction>
</resources> </resources>

View File

@ -215,6 +215,11 @@
<attr name="iconEmojiKey" format="reference" /> <attr name="iconEmojiKey" format="reference" />
</declare-styleable> </declare-styleable>
<declare-styleable name="Keyboard_GridRows">
<attr name="codesArray" format="reference" />
<attr name="textsArray" format="reference" />
</declare-styleable>
<declare-styleable name="Keyboard_Key"> <declare-styleable name="Keyboard_Key">
<!-- The unicode value that this key outputs. <!-- The unicode value that this key outputs.
Code value represented in hexadecimal prefixed with "0x" or code value reference using Code value represented in hexadecimal prefixed with "0x" or code value reference using

View File

@ -123,6 +123,9 @@
<dimen name="gesture_floating_preview_vertical_padding">16dp</dimen> <dimen name="gesture_floating_preview_vertical_padding">16dp</dimen>
<dimen name="gesture_floating_preview_round_radius">3dp</dimen> <dimen name="gesture_floating_preview_round_radius">3dp</dimen>
<!-- Emoji keyboard -->
<fraction name="emoji_keyboard_key_width">14.2857%p</fraction>
<!-- Inset used in Accessibility mode to avoid accidental key presses when a finger slides off the screen. --> <!-- Inset used in Accessibility mode to avoid accidental key presses when a finger slides off the screen. -->
<dimen name="accessibility_edge_slop">8dp</dimen> <dimen name="accessibility_edge_slop">8dp</dimen>

View File

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
/*
**
** Copyright 2013, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
-->
<Keyboard
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
latin:keyWidth="@fraction/emoji_keyboard_key_width"
latin:keyLetterSize="90%p"
>
<GridRows
latin:codesArray="@array/emoji_faces"
latin:keyLabelFlags="fontNormal"
latin:backgroundType="empty" />
</Keyboard>

View File

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
/*
**
** Copyright 2013, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
-->
<Keyboard
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
latin:keyWidth="@fraction/emoji_keyboard_key_width"
latin:keyLetterSize="90%p"
>
<GridRows
latin:codesArray="@array/emoji_objects"
latin:keyLabelFlags="fontNormal"
latin:backgroundType="empty" />
</Keyboard>

View File

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
/*
**
** Copyright 2013, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
-->
<Keyboard
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
latin:keyWidth="@fraction/emoji_keyboard_key_width"
latin:keyLetterSize="90%p"
>
<GridRows
latin:codesArray="@array/emoji_nature"
latin:keyLabelFlags="fontNormal"
latin:backgroundType="empty" />
</Keyboard>

View File

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
/*
**
** Copyright 2013, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
-->
<Keyboard
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
latin:keyWidth="@fraction/emoji_keyboard_key_width"
latin:keyLetterSize="90%p"
>
<GridRows
latin:codesArray="@array/emoji_places"
latin:keyLabelFlags="fontNormal"
latin:backgroundType="empty" />
</Keyboard>

View File

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
/*
**
** Copyright 2013, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
-->
<Keyboard
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
latin:keyWidth="@fraction/emoji_keyboard_key_width"
latin:keyLetterSize="90%p"
>
<GridRows
latin:codesArray="@array/emoji_symbols"
latin:keyLabelFlags="fontNormal"
latin:backgroundType="empty" />
</Keyboard>

View File

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
/*
**
** Copyright 2013, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
-->
<Keyboard
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
latin:keyWidth="@fraction/emoji_keyboard_key_width"
latin:keyLetterSize="90%p"
>
<GridRows
latin:textsArray="@array/emoji_emoticons"
latin:keyLabelFlags="fontNormal"
latin:backgroundType="empty" />
</Keyboard>

View File

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
/*
**
** Copyright 2013, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
-->
<Keyboard
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
latin:keyWidth="@fraction/emoji_keyboard_key_width"
latin:keyLetterSize="90%p"
>
<GridRows
latin:codesArray="@array/emoji_recents"
latin:keyLabelFlags="fontNormal"
latin:backgroundType="empty" />
</Keyboard>

View File

@ -0,0 +1,44 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
/*
**
** Copyright 2013, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
-->
<KeyboardLayoutSet
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin">
<Element
latin:elementName="emojiRecents"
latin:elementKeyboard="@xml/kbd_emoji_recents" />
<Element
latin:elementName="emojiCategory1"
latin:elementKeyboard="@xml/kbd_emoji_category1" />
<Element
latin:elementName="emojiCategory2"
latin:elementKeyboard="@xml/kbd_emoji_category2" />
<Element
latin:elementName="emojiCategory3"
latin:elementKeyboard="@xml/kbd_emoji_category3" />
<Element
latin:elementName="emojiCategory4"
latin:elementKeyboard="@xml/kbd_emoji_category4" />
<Element
latin:elementName="emojiCategory5"
latin:elementKeyboard="@xml/kbd_emoji_category5" />
<Element
latin:elementName="emojiCategory6"
latin:elementKeyboard="@xml/kbd_emoji_category6" />
</KeyboardLayoutSet>

View File

@ -51,6 +51,11 @@ public class Keyboard {
/** Total width of the keyboard, including the padding and keys */ /** Total width of the keyboard, including the padding and keys */
public final int mOccupiedWidth; public final int mOccupiedWidth;
/** Base height of the keyboard, used to calculate rows' height */
public final int mBaseHeight;
/** Base width of the keyboard, used to calculate keys' width */
public final int mBaseWidth;
/** The padding above the keyboard */ /** The padding above the keyboard */
public final int mTopPadding; public final int mTopPadding;
/** Default gap between rows */ /** Default gap between rows */
@ -84,6 +89,8 @@ public class Keyboard {
mThemeId = params.mThemeId; mThemeId = params.mThemeId;
mOccupiedHeight = params.mOccupiedHeight; mOccupiedHeight = params.mOccupiedHeight;
mOccupiedWidth = params.mOccupiedWidth; mOccupiedWidth = params.mOccupiedWidth;
mBaseHeight = params.mBaseHeight;
mBaseWidth = params.mBaseWidth;
mMostCommonKeyHeight = params.mMostCommonKeyHeight; mMostCommonKeyHeight = params.mMostCommonKeyHeight;
mMostCommonKeyWidth = params.mMostCommonKeyWidth; mMostCommonKeyWidth = params.mMostCommonKeyWidth;
mMoreKeysTemplate = params.mMoreKeysTemplate; mMoreKeysTemplate = params.mMoreKeysTemplate;
@ -109,6 +116,8 @@ public class Keyboard {
mThemeId = keyboard.mThemeId; mThemeId = keyboard.mThemeId;
mOccupiedHeight = keyboard.mOccupiedHeight; mOccupiedHeight = keyboard.mOccupiedHeight;
mOccupiedWidth = keyboard.mOccupiedWidth; mOccupiedWidth = keyboard.mOccupiedWidth;
mBaseHeight = keyboard.mBaseHeight;
mBaseWidth = keyboard.mBaseWidth;
mMostCommonKeyHeight = keyboard.mMostCommonKeyHeight; mMostCommonKeyHeight = keyboard.mMostCommonKeyHeight;
mMostCommonKeyWidth = keyboard.mMostCommonKeyWidth; mMostCommonKeyWidth = keyboard.mMostCommonKeyWidth;
mMoreKeysTemplate = keyboard.mMoreKeysTemplate; mMoreKeysTemplate = keyboard.mMoreKeysTemplate;

View File

@ -0,0 +1,85 @@
/*
* Copyright (C) 2013 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.inputmethod.keyboard.internal;
import com.android.inputmethod.latin.Constants;
/**
* The string parser of codesArray specification for <GridRows />. The attribute codesArray is an
* array of string.
* Each element of the array defines a key label by specifying a code point as a hexadecimal string.
* A key label may consist of multiple code points separated by comma.
* Each element of the array optionally can have an output text definition after vertical bar
* marker. An output text may consist of multiple code points separated by comma.
* The format of the codesArray element should be:
* <pre>
* codePointInHex[,codePoint2InHex]*(|outputTextCodePointInHex[,outputTextCodePoint2InHex]*)?
* </pre>
*/
// TODO: Write unit tests for this class.
public final class CodesArrayParser {
// Constants for parsing.
private static final char COMMA = ',';
private static final char VERTICAL_BAR = '|';
private static final String COMMA_STRING = ",";
private static final int BASE_HEX = 16;
private CodesArrayParser() {
// This utility class is not publicly instantiable.
}
private static String getLabelSpec(final String codesArraySpec) {
final int pos = codesArraySpec.indexOf(VERTICAL_BAR);
return (pos < 0) ? codesArraySpec : codesArraySpec.substring(0, pos);
}
public static String parseLabel(final String codesArraySpec) {
final String labelSpec = getLabelSpec(codesArraySpec);
final StringBuilder sb = new StringBuilder();
for (final String codeInHex : labelSpec.split(COMMA_STRING)) {
final int codePoint = Integer.parseInt(codeInHex, BASE_HEX);
sb.appendCodePoint(codePoint);
}
return sb.toString();
}
private static String getCodeSpec(final String codesArraySpec) {
final int pos = codesArraySpec.indexOf(VERTICAL_BAR);
return (pos < 0) ? codesArraySpec : codesArraySpec.substring(pos + 1);
}
public static int parseCode(final String codesArraySpec) {
final String codeSpec = getCodeSpec(codesArraySpec);
if (codeSpec.indexOf(COMMA) < 0) {
return Integer.parseInt(codeSpec, BASE_HEX);
}
return Constants.CODE_OUTPUT_TEXT;
}
public static String parseOutputText(final String codesArraySpec) {
final String codeSpec = getCodeSpec(codesArraySpec);
if (codeSpec.indexOf(COMMA) < 0) {
return null;
}
final StringBuilder sb = new StringBuilder();
for (final String codeInHex : codeSpec.split(COMMA_STRING)) {
final int codePoint = Integer.parseInt(codeInHex, BASE_HEX);
sb.appendCodePoint(codePoint);
}
return sb.toString();
}
}

View File

@ -29,6 +29,7 @@ import com.android.inputmethod.annotations.UsedForTesting;
import com.android.inputmethod.keyboard.Key; import com.android.inputmethod.keyboard.Key;
import com.android.inputmethod.keyboard.Keyboard; import com.android.inputmethod.keyboard.Keyboard;
import com.android.inputmethod.keyboard.KeyboardId; import com.android.inputmethod.keyboard.KeyboardId;
import com.android.inputmethod.latin.Constants;
import com.android.inputmethod.latin.R; import com.android.inputmethod.latin.R;
import com.android.inputmethod.latin.utils.ResourceUtils; import com.android.inputmethod.latin.utils.ResourceUtils;
import com.android.inputmethod.latin.utils.RunInLocale; import com.android.inputmethod.latin.utils.RunInLocale;
@ -113,6 +114,7 @@ import java.util.Locale;
* </pre> * </pre>
*/ */
// TODO: Write unit tests for this class.
public class KeyboardBuilder<KP extends KeyboardParams> { public class KeyboardBuilder<KP extends KeyboardParams> {
private static final String BUILDER_TAG = "Keyboard.Builder"; private static final String BUILDER_TAG = "Keyboard.Builder";
private static final boolean DEBUG = false; private static final boolean DEBUG = false;
@ -120,6 +122,7 @@ public class KeyboardBuilder<KP extends KeyboardParams> {
// Keyboard XML Tags // Keyboard XML Tags
private static final String TAG_KEYBOARD = "Keyboard"; private static final String TAG_KEYBOARD = "Keyboard";
private static final String TAG_ROW = "Row"; private static final String TAG_ROW = "Row";
private static final String TAG_GRID_ROWS = "GridRows";
private static final String TAG_KEY = "Key"; private static final String TAG_KEY = "Key";
private static final String TAG_SPACER = "Spacer"; private static final String TAG_SPACER = "Spacer";
private static final String TAG_INCLUDE = "include"; private static final String TAG_INCLUDE = "include";
@ -312,6 +315,9 @@ public class KeyboardBuilder<KP extends KeyboardParams> {
startRow(row); startRow(row);
} }
parseRowContent(parser, row, skip); parseRowContent(parser, row, skip);
} else if (TAG_GRID_ROWS.equals(tag)) {
if (DEBUG) startTag("<%s>%s", TAG_GRID_ROWS, skip ? " skipped" : "");
parseGridRows(parser, skip);
} else if (TAG_INCLUDE.equals(tag)) { } else if (TAG_INCLUDE.equals(tag)) {
parseIncludeKeyboardContent(parser, skip); parseIncludeKeyboardContent(parser, skip);
} else if (TAG_SWITCH.equals(tag)) { } else if (TAG_SWITCH.equals(tag)) {
@ -389,6 +395,73 @@ public class KeyboardBuilder<KP extends KeyboardParams> {
} }
} }
private void parseGridRows(final XmlPullParser parser, final boolean skip)
throws XmlPullParserException, IOException {
if (skip) {
XmlParseUtils.checkEndTag(TAG_GRID_ROWS, parser);
if (DEBUG) {
startEndTag("<%s /> skipped", TAG_GRID_ROWS);
}
return;
}
final KeyboardRow gridRows = new KeyboardRow(mResources, mParams, parser, mCurrentY);
final TypedArray gridRowAttr = mResources.obtainAttributes(
Xml.asAttributeSet(parser), R.styleable.Keyboard_GridRows);
final int codesArrayId = gridRowAttr.getResourceId(
R.styleable.Keyboard_GridRows_codesArray, 0);
final int textsArrayId = gridRowAttr.getResourceId(
R.styleable.Keyboard_GridRows_textsArray, 0);
gridRowAttr.recycle();
if (codesArrayId == 0 && textsArrayId == 0) {
throw new XmlParseUtils.ParseException(
"Missing codesArray or textsArray attributes", parser);
}
if (codesArrayId != 0 && textsArrayId != 0) {
throw new XmlParseUtils.ParseException(
"Both codesArray and textsArray attributes specifed", parser);
}
final String[] array = mResources.getStringArray(
codesArrayId != 0 ? codesArrayId : textsArrayId);
final int counts = array.length;
final float keyWidth = gridRows.getKeyWidth(null, 0.0f);
final int numColumns = (int)(mParams.mOccupiedWidth / keyWidth);
for (int index = 0; index < counts; index += numColumns) {
final KeyboardRow row = new KeyboardRow(mResources, mParams, parser, mCurrentY);
startRow(row);
for (int c = 0; c < numColumns; c++) {
final int i = index + c;
if (i >= counts) {
break;
}
final String label;
final int code;
final String outputText;
if (codesArrayId != 0) {
final String codeArraySpec = array[i];
label = CodesArrayParser.parseLabel(codeArraySpec);
code = CodesArrayParser.parseCode(codeArraySpec);
outputText = CodesArrayParser.parseOutputText(codeArraySpec);
} else {
final String textArraySpec = array[i];
// TODO: Utilize KeySpecParser or write more generic TextsArrayParser.
label = textArraySpec;
code = Constants.CODE_OUTPUT_TEXT;
outputText = textArraySpec + (char)Constants.CODE_SPACE;
}
final int x = (int)row.getKeyX(null);
final int y = row.getKeyY();
final Key key = new Key(mParams, label, null /* hintLabel */, 0 /* iconId */,
code, outputText, x, y, (int)keyWidth, (int)row.getRowHeight(),
row.getDefaultKeyLabelFlags(), row.getDefaultBackgroundType());
endKey(key);
row.advanceXPos(keyWidth);
}
endRow(row);
}
XmlParseUtils.checkEndTag(TAG_GRID_ROWS, parser);
}
private void parseKey(final XmlPullParser parser, final KeyboardRow row, final boolean skip) private void parseKey(final XmlPullParser parser, final KeyboardRow row, final boolean skip)
throws XmlPullParserException, IOException { throws XmlPullParserException, IOException {
if (skip) { if (skip) {
@ -744,7 +817,10 @@ public class KeyboardBuilder<KP extends KeyboardParams> {
} }
private void endKeyboard() { private void endKeyboard() {
// nothing to do here. // {@link #parseGridRows(XmlPullParser,boolean)} may populate keyboard rows higher than
// previously expected.
final int actualHeight = mCurrentY - mParams.mVerticalGap + mParams.mBottomPadding;
mParams.mOccupiedHeight = Math.max(mParams.mOccupiedHeight, actualHeight);
} }
private void addEdgeSpace(final float width, final KeyboardRow row) { private void addEdgeSpace(final float width, final KeyboardRow row) {