diff --git a/java/res/values-land/dimens.xml b/java/res/values-land/dimens.xml index c78c25f86..d411cb954 100644 --- a/java/res/values-land/dimens.xml +++ b/java/res/values-land/dimens.xml @@ -79,4 +79,7 @@ 54dp 23dp 15dp + + + 8.3333%p diff --git a/java/res/values/attrs.xml b/java/res/values/attrs.xml index 4c5097654..7ebaf75be 100644 --- a/java/res/values/attrs.xml +++ b/java/res/values/attrs.xml @@ -215,6 +215,11 @@ + + + + + + 14.2857%p + 8dp diff --git a/java/res/xml/kbd_emoji_category1.xml b/java/res/xml/kbd_emoji_category1.xml new file mode 100644 index 000000000..92b0c3fbf --- /dev/null +++ b/java/res/xml/kbd_emoji_category1.xml @@ -0,0 +1,30 @@ + + + + + + diff --git a/java/res/xml/kbd_emoji_category2.xml b/java/res/xml/kbd_emoji_category2.xml new file mode 100644 index 000000000..17d36c52f --- /dev/null +++ b/java/res/xml/kbd_emoji_category2.xml @@ -0,0 +1,30 @@ + + + + + + diff --git a/java/res/xml/kbd_emoji_category3.xml b/java/res/xml/kbd_emoji_category3.xml new file mode 100644 index 000000000..9000a3a11 --- /dev/null +++ b/java/res/xml/kbd_emoji_category3.xml @@ -0,0 +1,30 @@ + + + + + + diff --git a/java/res/xml/kbd_emoji_category4.xml b/java/res/xml/kbd_emoji_category4.xml new file mode 100644 index 000000000..e79e124e7 --- /dev/null +++ b/java/res/xml/kbd_emoji_category4.xml @@ -0,0 +1,30 @@ + + + + + + diff --git a/java/res/xml/kbd_emoji_category5.xml b/java/res/xml/kbd_emoji_category5.xml new file mode 100644 index 000000000..07b3d908c --- /dev/null +++ b/java/res/xml/kbd_emoji_category5.xml @@ -0,0 +1,30 @@ + + + + + + diff --git a/java/res/xml/kbd_emoji_category6.xml b/java/res/xml/kbd_emoji_category6.xml new file mode 100644 index 000000000..a07966b07 --- /dev/null +++ b/java/res/xml/kbd_emoji_category6.xml @@ -0,0 +1,30 @@ + + + + + + diff --git a/java/res/xml/kbd_emoji_recents.xml b/java/res/xml/kbd_emoji_recents.xml new file mode 100644 index 000000000..8b4fa958c --- /dev/null +++ b/java/res/xml/kbd_emoji_recents.xml @@ -0,0 +1,30 @@ + + + + + + diff --git a/java/res/xml/keyboard_layout_set_emoji.xml b/java/res/xml/keyboard_layout_set_emoji.xml new file mode 100644 index 000000000..98e6b6b5c --- /dev/null +++ b/java/res/xml/keyboard_layout_set_emoji.xml @@ -0,0 +1,44 @@ + + + + + + + + + + + + diff --git a/java/src/com/android/inputmethod/keyboard/Keyboard.java b/java/src/com/android/inputmethod/keyboard/Keyboard.java index 0b3737e48..23f037fbd 100644 --- a/java/src/com/android/inputmethod/keyboard/Keyboard.java +++ b/java/src/com/android/inputmethod/keyboard/Keyboard.java @@ -51,6 +51,11 @@ public class Keyboard { /** Total width of the keyboard, including the padding and keys */ 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 */ public final int mTopPadding; /** Default gap between rows */ @@ -84,6 +89,8 @@ public class Keyboard { mThemeId = params.mThemeId; mOccupiedHeight = params.mOccupiedHeight; mOccupiedWidth = params.mOccupiedWidth; + mBaseHeight = params.mBaseHeight; + mBaseWidth = params.mBaseWidth; mMostCommonKeyHeight = params.mMostCommonKeyHeight; mMostCommonKeyWidth = params.mMostCommonKeyWidth; mMoreKeysTemplate = params.mMoreKeysTemplate; @@ -109,6 +116,8 @@ public class Keyboard { mThemeId = keyboard.mThemeId; mOccupiedHeight = keyboard.mOccupiedHeight; mOccupiedWidth = keyboard.mOccupiedWidth; + mBaseHeight = keyboard.mBaseHeight; + mBaseWidth = keyboard.mBaseWidth; mMostCommonKeyHeight = keyboard.mMostCommonKeyHeight; mMostCommonKeyWidth = keyboard.mMostCommonKeyWidth; mMoreKeysTemplate = keyboard.mMoreKeysTemplate; diff --git a/java/src/com/android/inputmethod/keyboard/internal/CodesArrayParser.java b/java/src/com/android/inputmethod/keyboard/internal/CodesArrayParser.java new file mode 100644 index 000000000..c10fdbace --- /dev/null +++ b/java/src/com/android/inputmethod/keyboard/internal/CodesArrayParser.java @@ -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 . 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: + *
+ *   codePointInHex[,codePoint2InHex]*(|outputTextCodePointInHex[,outputTextCodePoint2InHex]*)?
+ * 
+ */ +// 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(); + } +} diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardBuilder.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardBuilder.java index 3f0773e15..8c70389ba 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardBuilder.java +++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardBuilder.java @@ -29,6 +29,7 @@ import com.android.inputmethod.annotations.UsedForTesting; import com.android.inputmethod.keyboard.Key; import com.android.inputmethod.keyboard.Keyboard; import com.android.inputmethod.keyboard.KeyboardId; +import com.android.inputmethod.latin.Constants; import com.android.inputmethod.latin.R; import com.android.inputmethod.latin.utils.ResourceUtils; import com.android.inputmethod.latin.utils.RunInLocale; @@ -113,6 +114,7 @@ import java.util.Locale; * */ +// TODO: Write unit tests for this class. public class KeyboardBuilder { private static final String BUILDER_TAG = "Keyboard.Builder"; private static final boolean DEBUG = false; @@ -120,6 +122,7 @@ public class KeyboardBuilder { // Keyboard XML Tags private static final String TAG_KEYBOARD = "Keyboard"; 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_SPACER = "Spacer"; private static final String TAG_INCLUDE = "include"; @@ -312,6 +315,9 @@ public class KeyboardBuilder { startRow(row); } 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)) { parseIncludeKeyboardContent(parser, skip); } else if (TAG_SWITCH.equals(tag)) { @@ -389,6 +395,73 @@ public class KeyboardBuilder { } } + 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) throws XmlPullParserException, IOException { if (skip) { @@ -744,7 +817,10 @@ public class KeyboardBuilder { } 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) {