diff options
89 files changed, 906 insertions, 505 deletions
diff --git a/common/Android.mk b/common/Android.mk index 99aed4c5d..085543f75 100644 --- a/common/Android.mk +++ b/common/Android.mk @@ -14,8 +14,9 @@ LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) -LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_MODULE := latinime-common +LOCAL_SRC_FILES := $(call all-java-files-under, src) +LOCAL_STATIC_JAVA_LIBRARIES := jsr305 LOCAL_SDK_VERSION := 21 include $(BUILD_STATIC_JAVA_LIBRARY) @@ -23,4 +24,5 @@ include $(BUILD_STATIC_JAVA_LIBRARY) include $(CLEAR_VARS) LOCAL_MODULE := latinime-common-host LOCAL_SRC_FILES := $(call all-java-files-under, src) +LOCAL_STATIC_JAVA_LIBRARIES := jsr305lib include $(BUILD_HOST_JAVA_LIBRARY) diff --git a/common/src/com/android/inputmethod/latin/common/Constants.java b/common/src/com/android/inputmethod/latin/common/Constants.java index 9a244d46a..8f4a1e50d 100644 --- a/common/src/com/android/inputmethod/latin/common/Constants.java +++ b/common/src/com/android/inputmethod/latin/common/Constants.java @@ -16,6 +16,8 @@ package com.android.inputmethod.latin.common; +import com.android.inputmethod.annotations.UsedForTesting; + public final class Constants { public static final class Color { /** @@ -305,6 +307,18 @@ public final class Constants { public static final int SCREEN_METRICS_LARGE_TABLET = 2; public static final int SCREEN_METRICS_SMALL_TABLET = 3; + @UsedForTesting + public static boolean isPhone(final int screenMetrics) { + return screenMetrics == SCREEN_METRICS_SMALL_PHONE + || screenMetrics == SCREEN_METRICS_LARGE_PHONE; + } + + @UsedForTesting + public static boolean isTablet(final int screenMetrics) { + return screenMetrics == SCREEN_METRICS_SMALL_TABLET + || screenMetrics == SCREEN_METRICS_LARGE_TABLET; + } + /** * Default capacity of gesture points container. * This constant is used by {@link com.android.inputmethod.keyboard.internal.BatchInputArbiter} diff --git a/java/src/com/android/inputmethod/latin/InputPointers.java b/common/src/com/android/inputmethod/latin/common/InputPointers.java index d57a881c0..40131aca4 100644 --- a/java/src/com/android/inputmethod/latin/InputPointers.java +++ b/common/src/com/android/inputmethod/latin/common/InputPointers.java @@ -14,18 +14,12 @@ * limitations under the License. */ -package com.android.inputmethod.latin; - -import android.util.Log; -import android.util.SparseIntArray; +package com.android.inputmethod.latin.common; import com.android.inputmethod.annotations.UsedForTesting; -import com.android.inputmethod.latin.define.DebugFlags; -import com.android.inputmethod.latin.utils.ResizableIntArray; // TODO: This class is not thread-safe. public final class InputPointers { - private static final String TAG = InputPointers.class.getSimpleName(); private static final boolean DEBUG_TIME = false; private final int mDefaultCapacity; @@ -61,14 +55,14 @@ public final class InputPointers { mXCoordinates.addAt(index, x); mYCoordinates.addAt(index, y); mPointerIds.addAt(index, pointerId); - if (DebugFlags.DEBUG_ENABLED || DEBUG_TIME) { + if (DEBUG_TIME) { fillWithLastTimeUntil(index); } mTimes.addAt(index, time); } @UsedForTesting - void addPointer(int x, int y, int pointerId, int time) { + public void addPointer(int x, int y, int pointerId, int time) { mXCoordinates.add(x); mYCoordinates.add(y); mPointerIds.add(pointerId); @@ -152,11 +146,6 @@ public final class InputPointers { * the sequence. */ public int[] getTimes() { - if (DebugFlags.DEBUG_ENABLED || DEBUG_TIME) { - if (!isValidTimeStamps()) { - throw new RuntimeException("Time stamps are invalid."); - } - } return mTimes.getPrimitiveArray(); } @@ -165,25 +154,4 @@ public final class InputPointers { return "size=" + getPointerSize() + " id=" + mPointerIds + " time=" + mTimes + " x=" + mXCoordinates + " y=" + mYCoordinates; } - - private boolean isValidTimeStamps() { - final int[] times = mTimes.getPrimitiveArray(); - final int[] pointerIds = mPointerIds.getPrimitiveArray(); - final SparseIntArray lastTimeOfPointers = new SparseIntArray(); - final int size = getPointerSize(); - for (int i = 0; i < size; ++i) { - final int pointerId = pointerIds[i]; - final int time = times[i]; - final int lastTime = lastTimeOfPointers.get(pointerId, time); - if (time < lastTime) { - // dump - for (int j = 0; j < size; ++j) { - Log.d(TAG, "--- (" + j + ") " + times[j]); - } - return false; - } - lastTimeOfPointers.put(pointerId, time); - } - return true; - } } diff --git a/java/src/com/android/inputmethod/latin/utils/ResizableIntArray.java b/common/src/com/android/inputmethod/latin/common/ResizableIntArray.java index 64c9e2cff..ea23d8a33 100644 --- a/java/src/com/android/inputmethod/latin/utils/ResizableIntArray.java +++ b/common/src/com/android/inputmethod/latin/common/ResizableIntArray.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.inputmethod.latin.utils; +package com.android.inputmethod.latin.common; import java.util.Arrays; diff --git a/java/src/com/android/inputmethod/latin/utils/StringUtils.java b/common/src/com/android/inputmethod/latin/common/StringUtils.java index f96ed0468..be7260308 100644 --- a/java/src/com/android/inputmethod/latin/utils/StringUtils.java +++ b/common/src/com/android/inputmethod/latin/common/StringUtils.java @@ -14,25 +14,23 @@ * limitations under the License. */ -package com.android.inputmethod.latin.utils; - -import android.text.Spanned; -import android.text.TextUtils; +package com.android.inputmethod.latin.common; import com.android.inputmethod.annotations.UsedForTesting; -import com.android.inputmethod.latin.common.Constants; import java.util.ArrayList; import java.util.Arrays; import java.util.Locale; -import java.util.regex.Matcher; -import java.util.regex.Pattern; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; public final class StringUtils { public static final int CAPITALIZE_NONE = 0; // No caps, or mixed case public static final int CAPITALIZE_FIRST = 1; // First only public static final int CAPITALIZE_ALL = 2; // All caps + @Nonnull private static final String EMPTY_STRING = ""; private static final char CHAR_LINE_FEED = 0X000A; @@ -47,12 +45,77 @@ public final class StringUtils { // This utility class is not publicly instantiable. } - public static int codePointCount(final CharSequence text) { - if (TextUtils.isEmpty(text)) return 0; + // Taken from android.text.TextUtils. We are extensively using this method in many places, + // some of which don't have the android libraries available. + /** + * Returns true if the string is null or 0-length. + * @param str the string to be examined + * @return true if str is null or zero length + */ + public static boolean isEmpty(@Nullable final CharSequence str) { + return (str == null || str.length() == 0); + } + + // Taken from android.text.TextUtils to cut the dependency to the Android framework. + /** + * Returns a string containing the tokens joined by delimiters. + * @param delimiter the delimiter + * @param tokens an array objects to be joined. Strings will be formed from + * the objects by calling object.toString(). + */ + @Nonnull + public static String join(@Nonnull final CharSequence delimiter, + @Nonnull final Iterable<?> tokens) { + final StringBuilder sb = new StringBuilder(); + boolean firstTime = true; + for (final Object token: tokens) { + if (firstTime) { + firstTime = false; + } else { + sb.append(delimiter); + } + sb.append(token); + } + return sb.toString(); + } + + // Taken from android.text.TextUtils to cut the dependency to the Android framework. + /** + * Returns true if a and b are equal, including if they are both null. + * <p><i>Note: In platform versions 1.1 and earlier, this method only worked well if + * both the arguments were instances of String.</i></p> + * @param a first CharSequence to check + * @param b second CharSequence to check + * @return true if a and b are equal + */ + public static boolean equals(@Nullable final CharSequence a, @Nullable final CharSequence b) { + if (a == b) { + return true; + } + final int length; + if (a != null && b != null && (length = a.length()) == b.length()) { + if (a instanceof String && b instanceof String) { + return a.equals(b); + } + for (int i = 0; i < length; i++) { + if (a.charAt(i) != b.charAt(i)) { + return false; + } + } + return true; + } + return false; + } + + public static int codePointCount(@Nullable final CharSequence text) { + if (isEmpty(text)) { + return 0; + } return Character.codePointCount(text, 0, text.length()); } - public static String newSingleCodePointString(int codePoint) { + @Nonnull + public static String newSingleCodePointString(final int codePoint) { if (Character.charCount(codePoint) == 1) { // Optimization: avoid creating a temporary array for characters that are // represented by a single char value @@ -62,9 +125,12 @@ public final class StringUtils { return new String(Character.toChars(codePoint)); } - public static boolean containsInArray(final String text, final String[] array) { + public static boolean containsInArray(@Nonnull final String text, + @Nonnull final String[] array) { for (final String element : array) { - if (text.equals(element)) return true; + if (text.equals(element)) { + return true; + } } return false; } @@ -74,19 +140,21 @@ public final class StringUtils { * Unlike CSV, Comma-Splittable Text has no escaping mechanism, so that the text can't contain * a comma character in it. */ + @Nonnull private static final String SEPARATOR_FOR_COMMA_SPLITTABLE_TEXT = ","; - public static boolean containsInCommaSplittableText(final String text, - final String extraValues) { - if (TextUtils.isEmpty(extraValues)) { + public static boolean containsInCommaSplittableText(@Nonnull final String text, + @Nullable final String extraValues) { + if (isEmpty(extraValues)) { return false; } return containsInArray(text, extraValues.split(SEPARATOR_FOR_COMMA_SPLITTABLE_TEXT)); } - public static String removeFromCommaSplittableTextIfExists(final String text, - final String extraValues) { - if (TextUtils.isEmpty(extraValues)) { + @Nonnull + public static String removeFromCommaSplittableTextIfExists(@Nonnull final String text, + @Nullable final String extraValues) { + if (isEmpty(extraValues)) { return EMPTY_STRING; } final String[] elements = extraValues.split(SEPARATOR_FOR_COMMA_SPLITTABLE_TEXT); @@ -99,7 +167,7 @@ public final class StringUtils { result.add(element); } } - return TextUtils.join(SEPARATOR_FOR_COMMA_SPLITTABLE_TEXT, result); + return join(SEPARATOR_FOR_COMMA_SPLITTABLE_TEXT, result); } /** @@ -108,8 +176,10 @@ public final class StringUtils { * This method will always keep the first occurrence of all strings at their position * in the array, removing the subsequent ones. */ - public static void removeDupes(final ArrayList<String> suggestions) { - if (suggestions.size() < 2) return; + public static void removeDupes(@Nonnull final ArrayList<String> suggestions) { + if (suggestions.size() < 2) { + return; + } int i = 1; // Don't cache suggestions.size(), since we may be removing items while (i < suggestions.size()) { @@ -117,7 +187,7 @@ public final class StringUtils { // Compare each suggestion with each previous suggestion for (int j = 0; j < i; j++) { final String previous = suggestions.get(j); - if (TextUtils.equals(cur, previous)) { + if (equals(cur, previous)) { suggestions.remove(i); i--; break; @@ -127,7 +197,9 @@ public final class StringUtils { } } - public static String capitalizeFirstCodePoint(final String s, final Locale locale) { + @Nonnull + public static String capitalizeFirstCodePoint(@Nonnull final String s, + @Nonnull final Locale locale) { if (s.length() <= 1) { return s.toUpperCase(locale); } @@ -137,7 +209,9 @@ public final class StringUtils { return s.substring(0, cutoff).toUpperCase(locale) + s.substring(cutoff); } - public static String capitalizeFirstAndDowncaseRest(final String s, final Locale locale) { + @Nonnull + public static String capitalizeFirstAndDowncaseRest(@Nonnull final String s, + @Nonnull final Locale locale) { if (s.length() <= 1) { return s.toUpperCase(locale); } @@ -153,12 +227,14 @@ public final class StringUtils { return s.substring(0, cutoff).toUpperCase(locale) + s.substring(cutoff).toLowerCase(locale); } - private static final int[] EMPTY_CODEPOINTS = {}; - - public static int[] toCodePointArray(final CharSequence charSequence) { + @Nonnull + public static int[] toCodePointArray(@Nonnull final CharSequence charSequence) { return toCodePointArray(charSequence, 0, charSequence.length()); } + @Nonnull + private static final int[] EMPTY_CODEPOINTS = {}; + /** * Converts a range of a string to an array of code points. * @param charSequence the source string. @@ -166,7 +242,8 @@ public final class StringUtils { * @param endIndex the end index inside the string in java chars, exclusive. * @return a new array of code points. At most endIndex - startIndex, but possibly less. */ - public static int[] toCodePointArray(final CharSequence charSequence, + @Nonnull + public static int[] toCodePointArray(@Nonnull final CharSequence charSequence, final int startIndex, final int endIndex) { final int length = charSequence.length(); if (length <= 0) { @@ -197,8 +274,8 @@ public final class StringUtils { * @param downCase if this is true, code points will be downcased before being copied. * @return the number of copied code points. */ - public static int copyCodePointsAndReturnCodePointCount(final int[] destination, - final CharSequence charSequence, final int startIndex, final int endIndex, + public static int copyCodePointsAndReturnCodePointCount(@Nonnull final int[] destination, + @Nonnull final CharSequence charSequence, final int startIndex, final int endIndex, final boolean downCase) { int destIndex = 0; for (int index = startIndex; index < endIndex; @@ -212,7 +289,8 @@ public final class StringUtils { return destIndex; } - public static int[] toSortedCodePointArray(final String string) { + @Nonnull + public static int[] toSortedCodePointArray(@Nonnull final String string) { final int[] codePoints = toCodePointArray(string); Arrays.sort(codePoints); return codePoints; @@ -225,7 +303,9 @@ public final class StringUtils { * shorter than the array length. * @return a string constructed from the code point array. */ - public static String getStringFromNullTerminatedCodePointArray(final int[] codePoints) { + @Nonnull + public static String getStringFromNullTerminatedCodePointArray( + @Nonnull final int[] codePoints) { int stringLength = codePoints.length; for (int i = 0; i < codePoints.length; i++) { if (codePoints[i] == 0) { @@ -237,7 +317,7 @@ public final class StringUtils { } // This method assumes the text is not null. For the empty string, it returns CAPITALIZE_NONE. - public static int getCapitalizationType(final String text) { + public static int getCapitalizationType(@Nonnull final String text) { // If the first char is not uppercase, then the word is either all lower case or // camel case, and in either case we return CAPITALIZE_NONE. final int len = text.length(); @@ -273,7 +353,7 @@ public final class StringUtils { return (letterCount == capsCount ? CAPITALIZE_ALL : CAPITALIZE_NONE); } - public static boolean isIdenticalAfterUpcase(final String text) { + public static boolean isIdenticalAfterUpcase(@Nonnull final String text) { final int length = text.length(); int i = 0; while (i < length) { @@ -286,7 +366,7 @@ public final class StringUtils { return true; } - public static boolean isIdenticalAfterDowncase(final String text) { + public static boolean isIdenticalAfterDowncase(@Nonnull final String text) { final int length = text.length(); int i = 0; while (i < length) { @@ -299,8 +379,8 @@ public final class StringUtils { return true; } - public static boolean isIdenticalAfterCapitalizeEachWord(final String text, - final int[] sortedSeparators) { + public static boolean isIdenticalAfterCapitalizeEachWord(@Nonnull final String text, + @Nonnull final int[] sortedSeparators) { boolean needsCapsNext = true; final int len = text.length(); for (int i = 0; i < len; i = text.offsetByCodePoints(i, 1)) { @@ -319,8 +399,9 @@ public final class StringUtils { // TODO: like capitalizeFirst*, this does not work perfectly for Dutch because of the IJ digraph // which should be capitalized together in *some* cases. - public static String capitalizeEachWord(final String text, final int[] sortedSeparators, - final Locale locale) { + @Nonnull + public static String capitalizeEachWord(@Nonnull final String text, + @Nonnull final int[] sortedSeparators, @Nonnull final Locale locale) { final StringBuilder builder = new StringBuilder(); boolean needsCapsNext = true; final int len = text.length(); @@ -354,9 +435,11 @@ public final class StringUtils { * TODO: This will return that "abc./def" and ".abc/def" look like URLs to keep down the * code complexity, but ideally it should not. It's acceptable for now. */ - public static boolean lastPartLooksLikeURL(final CharSequence text) { + public static boolean lastPartLooksLikeURL(@Nonnull final CharSequence text) { int i = text.length(); - if (0 == i) return false; + if (0 == i) { + return false; + } int wCount = 0; int slashCount = 0; boolean hasSlash = false; @@ -393,11 +476,17 @@ public final class StringUtils { } // End of the text run. // If it starts with www and includes a period, then it looks like a URL. - if (wCount >= 3 && hasPeriod) return true; + if (wCount >= 3 && hasPeriod) { + return true; + } // If it starts with a slash, and the code point before is whitespace, it looks like an URL. - if (1 == slashCount && (0 == i || Character.isWhitespace(codePoint))) return true; + if (1 == slashCount && (0 == i || Character.isWhitespace(codePoint))) { + return true; + } // If it has both a period and a slash, it looks like an URL. - if (hasPeriod && hasSlash) return true; + if (hasPeriod && hasSlash) { + return true; + } // Otherwise, it doesn't look like an URL. return false; } @@ -418,18 +507,24 @@ public final class StringUtils { * @param text the text to examine. * @return whether we're inside a double quote. */ - public static boolean isInsideDoubleQuoteOrAfterDigit(final CharSequence text) { + public static boolean isInsideDoubleQuoteOrAfterDigit(@Nonnull final CharSequence text) { int i = text.length(); - if (0 == i) return false; + if (0 == i) { + return false; + } int codePoint = Character.codePointBefore(text, i); - if (Character.isDigit(codePoint)) return true; + if (Character.isDigit(codePoint)) { + return true; + } int prevCodePoint = 0; while (i > 0) { codePoint = Character.codePointBefore(text, i); if (Constants.CODE_DOUBLE_QUOTE == codePoint) { // If we see a double quote followed by whitespace, then that // was a closing quote. - if (Character.isWhitespace(prevCodePoint)) return false; + if (Character.isWhitespace(prevCodePoint)) { + return false; + } } if (Character.isWhitespace(codePoint) && Constants.CODE_DOUBLE_QUOTE == prevCodePoint) { // If we see a double quote preceded by whitespace, then that @@ -444,7 +539,7 @@ public final class StringUtils { return Constants.CODE_DOUBLE_QUOTE == codePoint; } - public static boolean isEmptyStringOrWhiteSpaces(final String s) { + public static boolean isEmptyStringOrWhiteSpaces(@Nonnull final String s) { final int N = codePointCount(s); for (int i = 0; i < N; ++i) { if (!Character.isWhitespace(s.codePointAt(i))) { @@ -455,12 +550,13 @@ public final class StringUtils { } @UsedForTesting - public static String byteArrayToHexString(final byte[] bytes) { + @Nonnull + public static String byteArrayToHexString(@Nullable final byte[] bytes) { if (bytes == null || bytes.length == 0) { return EMPTY_STRING; } final StringBuilder sb = new StringBuilder(); - for (byte b : bytes) { + for (final byte b : bytes) { sb.append(String.format("%02x", b & 0xff)); } return sb.toString(); @@ -470,8 +566,9 @@ public final class StringUtils { * Convert hex string to byte array. The string length must be an even number. */ @UsedForTesting - public static byte[] hexStringToByteArray(final String hexString) { - if (TextUtils.isEmpty(hexString)) { + @Nullable + public static byte[] hexStringToByteArray(@Nullable final String hexString) { + if (isEmpty(hexString)) { return null; } final int N = hexString.length(); @@ -487,15 +584,20 @@ public final class StringUtils { return bytes; } - public static String toUpperCaseOfStringForLocale(final String text, - final boolean needsToUpperCase, final Locale locale) { - if (text == null || !needsToUpperCase) return text; + @Nullable + public static String toUpperCaseOfStringForLocale(@Nullable final String text, + final boolean needsToUpperCase, @Nonnull final Locale locale) { + if (text == null || !needsToUpperCase) { + return text; + } return text.toUpperCase(locale); } public static int toUpperCaseOfCodeForLocale(final int code, final boolean needsToUpperCase, - final Locale locale) { - if (!Constants.isLetterCode(code) || !needsToUpperCase) return code; + @Nonnull final Locale locale) { + if (!Constants.isLetterCode(code) || !needsToUpperCase) { + return code; + } final String text = newSingleCodePointString(code); final String casedText = toUpperCaseOfStringForLocale( text, needsToUpperCase, locale); @@ -503,7 +605,7 @@ public final class StringUtils { ? casedText.codePointAt(0) : Constants.CODE_UNSPECIFIED; } - public static int getTrailingSingleQuotesCount(final CharSequence charSequence) { + public static int getTrailingSingleQuotesCount(@Nonnull final CharSequence charSequence) { final int lastIndex = charSequence.length() - 1; int i = lastIndex; while (i >= 0 && charSequence.charAt(i) == Constants.CODE_SINGLE_QUOTE) { @@ -512,72 +614,36 @@ public final class StringUtils { return lastIndex - i; } - /** - * Splits the given {@code charSequence} with at occurrences of the given {@code regex}. - * <p> - * This is equivalent to - * {@code charSequence.toString().split(regex, preserveTrailingEmptySegments ? -1 : 0)} - * except that the spans are preserved in the result array. - * </p> - * @param charSequence the character sequence to be split. - * @param regex the regex pattern to be used as the separator. - * @param preserveTrailingEmptySegments {@code true} to preserve the trailing empty - * segments. Otherwise, trailing empty segments will be removed before being returned. - * @return the array which contains the result. All the spans in the <code>charSequence</code> - * is preserved. - */ - @UsedForTesting - public static CharSequence[] split(final CharSequence charSequence, final String regex, - final boolean preserveTrailingEmptySegments) { - // A short-cut for non-spanned strings. - if (!(charSequence instanceof Spanned)) { - // -1 means that trailing empty segments will be preserved. - return charSequence.toString().split(regex, preserveTrailingEmptySegments ? -1 : 0); - } - - // Hereafter, emulate String.split for CharSequence. - final ArrayList<CharSequence> sequences = new ArrayList<>(); - final Matcher matcher = Pattern.compile(regex).matcher(charSequence); - int nextStart = 0; - boolean matched = false; - while (matcher.find()) { - sequences.add(charSequence.subSequence(nextStart, matcher.start())); - nextStart = matcher.end(); - matched = true; - } - if (!matched) { - // never matched. preserveTrailingEmptySegments is ignored in this case. - return new CharSequence[] { charSequence }; - } - sequences.add(charSequence.subSequence(nextStart, charSequence.length())); - if (!preserveTrailingEmptySegments) { - for (int i = sequences.size() - 1; i >= 0; --i) { - if (!TextUtils.isEmpty(sequences.get(i))) { - break; - } - sequences.remove(i); - } - } - return sequences.toArray(new CharSequence[sequences.size()]); - } - @UsedForTesting public static class Stringizer<E> { - public String stringize(final E element) { - return element != null ? element.toString() : "null"; + @Nonnull + private static final String[] EMPTY_STRING_ARRAY = new String[0]; + + @UsedForTesting + @Nonnull + public String stringize(@Nullable final E element) { + if (element == null) { + return "null"; + } + return element.toString(); } @UsedForTesting - public final String join(final E[] array) { + @Nonnull + public final String join(@Nullable final E[] array) { return joinStringArray(toStringArray(array), null /* delimiter */); } @UsedForTesting - public final String join(final E[] array, final String delimiter) { + public final String join(@Nullable final E[] array, @Nullable final String delimiter) { return joinStringArray(toStringArray(array), delimiter); } - protected String[] toStringArray(final E[] array) { + @Nonnull + protected String[] toStringArray(@Nullable final E[] array) { + if (array == null) { + return EMPTY_STRING_ARRAY; + } final String[] stringArray = new String[array.length]; for (int index = 0; index < array.length; index++) { stringArray[index] = stringize(array[index]); @@ -585,10 +651,9 @@ public final class StringUtils { return stringArray; } - protected String joinStringArray(final String[] stringArray, final String delimiter) { - if (stringArray == null) { - return "null"; - } + @Nonnull + protected String joinStringArray(@Nonnull final String[] stringArray, + @Nullable final String delimiter) { if (delimiter == null) { return Arrays.toString(stringArray); } @@ -606,9 +671,8 @@ public final class StringUtils { * @param text the text to be examined. * @return {@code true} if the last composed word contains line-breaking separator. */ - @UsedForTesting - public static boolean hasLineBreakCharacter(final String text) { - if (TextUtils.isEmpty(text)) { + public static boolean hasLineBreakCharacter(@Nullable final String text) { + if (isEmpty(text)) { return false; } for (int i = text.length() - 1; i >= 0; --i) { diff --git a/java-overridable/src/com/android/inputmethod/latin/SpecialKeyDetector.java b/java-overridable/src/com/android/inputmethod/latin/SpecialKeyDetector.java deleted file mode 100644 index 27b2f5012..000000000 --- a/java-overridable/src/com/android/inputmethod/latin/SpecialKeyDetector.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (C) 2014, 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.latin; - -import android.content.Context; -import android.view.KeyEvent; - -final class SpecialKeyDetector { - /** - * Special physical key detector - * @param context a context of this detector. - */ - public SpecialKeyDetector(final Context context) { - } - - /** - * Record a down key event. - * @param keyEvent a down key event. - */ - public void onKeyDown(final KeyEvent keyEvent) { - } - - /** - * Record an up key event. - * @param keyEvent an up key event. - */ - public void onKeyUp(final KeyEvent keyEvent) { - } -} diff --git a/java-overridable/src/com/android/inputmethod/latin/touchinputconsumer/GestureConsumer.java b/java-overridable/src/com/android/inputmethod/latin/touchinputconsumer/GestureConsumer.java index 1d60e0cf5..4a44aaa94 100644 --- a/java-overridable/src/com/android/inputmethod/latin/touchinputconsumer/GestureConsumer.java +++ b/java-overridable/src/com/android/inputmethod/latin/touchinputconsumer/GestureConsumer.java @@ -19,8 +19,8 @@ package com.android.inputmethod.latin.touchinputconsumer; import android.view.inputmethod.EditorInfo; import com.android.inputmethod.keyboard.Keyboard; -import com.android.inputmethod.latin.InputPointers; import com.android.inputmethod.latin.SuggestedWords; +import com.android.inputmethod.latin.common.InputPointers; import com.android.inputmethod.latin.inputlogic.PrivateCommandPerformer; import java.util.List; diff --git a/java/res/values/donottranslate-debug-settings.xml b/java/res/values/donottranslate-debug-settings.xml index cc8c1a01d..c612010f6 100644 --- a/java/res/values/donottranslate-debug-settings.xml +++ b/java/res/values/donottranslate-debug-settings.xml @@ -22,7 +22,6 @@ <string name="english_ime_debug_settings">Android Keyboard Debug settings</string> <string name="prefs_debug_mode">Debug Mode</string> <string name="prefs_force_non_distinct_multitouch">Force non-distinct multitouch</string> - <string name="prefs_force_physical_keyboard_special_key">Force physical keyboard special key</string> <string name="prefs_should_show_lxx_suggestion_ui">Show LXX suggestion UI</string> <!-- Option to enable sliding key input indicator. The user can see a rubber band-like effect during sliding key input. [CHAR LIMIT=30]--> <string name="sliding_key_input_preview">Show slide indicator</string> diff --git a/java/res/values/donottranslate.xml b/java/res/values/donottranslate.xml index 817bb5187..08d8bb260 100644 --- a/java/res/values/donottranslate.xml +++ b/java/res/values/donottranslate.xml @@ -39,6 +39,8 @@ <item>hi_ZZ</item> <item>sr_ZZ</item> </string-array> + <string name="subtype_in_root_locale_hi_ZZ">Hinglish</string> + <string name="subtype_in_root_locale_sr_ZZ">Srpski</string> <!-- Generic subtype label --> <string name="subtype_generic">%s</string> diff --git a/java/res/values/strings.xml b/java/res/values/strings.xml index 54bfc51d3..e1a72c476 100644 --- a/java/res/values/strings.xml +++ b/java/res/values/strings.xml @@ -214,8 +214,7 @@ <!-- Description for Hinglish (https://en.wikipedia.org/wiki/Hinglish) keyboard subtype [CHAR LIMIT=25] --> <string name="subtype_hi_ZZ">Hinglish</string> <!-- Description for Serbian (Latin) keyboard subtype [CHAR LIMIT=25] - (Latin) can be an abbreviation to fit in the CHAR LIMIT. - Note for Serbian translator: this should be translated with Latin script and (Latin) should be omitted. --> + (Latin) can be an abbreviation to fit in the CHAR LIMIT. --> <string name="subtype_sr_ZZ">Serbian (Latin)</string> <!-- Description for English (UK) keyboard subtype with explicit keyboard layout [CHAR LIMIT=25] (UK) should be an abbreviation of United Kingdom to fit in the CHAR LIMIT. @@ -233,16 +232,14 @@ This should be identical to subtype_hi_ZZ aside from the trailing (%s). --> <string name="subtype_with_layout_hi_ZZ">Hinglish (<xliff:g id="KEYBOARD_LAYOUT" example="QWERTY">%s</xliff:g>)</string> <!-- Description for Serbian (Latin) keyboard subtype with explicit keyboard layout [CHAR LIMIT=25] - This should be identical to subtype_sr_ZZ aside from the trailing (%s). - Note for Serbian translator: this should be translated with Latin script. --> + This should be identical to subtype_sr_ZZ aside from the trailing (%s). --> <string name="subtype_with_layout_sr_ZZ">Serbian (<xliff:g id="KEYBOARD_LAYOUT" example="QWERTY">%s</xliff:g>)</string> <!-- Description for "LANGUAGE_NAME" (Traditional) keyboard subtype [CHAR LIMIT=25] (Traditional) can be an abbreviation to fit in the CHAR LIMIT. --> <string name="subtype_generic_traditional"><xliff:g id="LANGUAGE_NAME" example="Nepali">%s</xliff:g> (Traditional)</string> <!-- Description for "LANGUAGE_NAME" (Compact) keyboard subtype [CHAR LIMIT=25] - (Compact) can be an abbreviation to fit in the CHAR LIMIT. - TODO: Remove translatable=false once we are settled down with the naming. --> - <string name="subtype_generic_compact" translatable="false"><xliff:g id="LANGUAGE_NAME" example="Hindi">%s</xliff:g> (Compact)</string> + (Compact) can be an abbreviation to fit in the CHAR LIMIT. --> + <string name="subtype_generic_compact"><xliff:g id="LANGUAGE_NAME" example="Hindi">%s</xliff:g> (Compact)</string> <!-- This string is displayed in a language list that allows to choose a language for suggestions in a software keyboard. This setting won't give suggestions in any particular language, hence "No language". @@ -363,6 +360,12 @@ mobile devices. [CHAR LIMIT=25] --> <string name="prefs_keypress_sound_volume_settings">Keypress sound volume</string> <!-- Title of the settings for key long press delay [CHAR LIMIT=35] --> <string name="prefs_key_longpress_timeout_settings">Key long press delay</string> + <!-- TODO: Let's finalize title of the settings and remove translatable="false" --> + <!-- Title of the settings for enabling Emoji palette triggered by the Alt key on physical keyboards [CHAR LIMIT=35] --> + <string name="prefs_enable_emoji_alt_physical_key" translatable="false">Emoji for physical keyboard</string> + <!-- TODO: Let's finalize title of the settings and remove translatable="false" --> + <!-- Description of the settings for enabling Emoji palette triggered by the Alt key on physical keyboards [CHAR LIMIT=64] --> + <string name="prefs_enable_emoji_alt_physical_key_summary" translatable="false">Physical Alt key shows the emoji palette</string> <!-- Title of the button to revert to the default value of the device in the settings dialog [CHAR LIMIT=15] --> <string name="button_default">Default</string> diff --git a/java/res/xml/prefs_screen_advanced.xml b/java/res/xml/prefs_screen_advanced.xml index 329822093..1fa6fd0c4 100644 --- a/java/res/xml/prefs_screen_advanced.xml +++ b/java/res/xml/prefs_screen_advanced.xml @@ -37,6 +37,12 @@ latin:minValue="@integer/config_min_longpress_timeout" latin:maxValue="@integer/config_max_longpress_timeout" latin:stepValue="@integer/config_longpress_timeout_step" /> + <CheckBoxPreference + android:key="pref_enable_emoji_alt_physical_key" + android:title="@string/prefs_enable_emoji_alt_physical_key" + android:summary="@string/prefs_enable_emoji_alt_physical_key_summary" + android:defaultValue="true" + android:persistent="true" /> <!-- The settings for showing setup wizard application icon shouldn't be persistent and the default value is added programmatically. --> <CheckBoxPreference diff --git a/java/res/xml/prefs_screen_debug.xml b/java/res/xml/prefs_screen_debug.xml index 486d2367e..13edf3ec6 100644 --- a/java/res/xml/prefs_screen_debug.xml +++ b/java/res/xml/prefs_screen_debug.xml @@ -31,11 +31,6 @@ android:defaultValue="false" android:persistent="true" /> <CheckBoxPreference - android:key="force_physical_keyboard_special_key" - android:title="@string/prefs_force_physical_keyboard_special_key" - android:defaultValue="false" - android:persistent="true" /> - <CheckBoxPreference android:key="pref_should_show_lxx_suggestion_ui" android:title="@string/prefs_should_show_lxx_suggestion_ui" android:defaultValue="true" diff --git a/java/src/com/android/inputmethod/accessibility/KeyCodeDescriptionMapper.java b/java/src/com/android/inputmethod/accessibility/KeyCodeDescriptionMapper.java index 9f7caa47e..bbda9f8e2 100644 --- a/java/src/com/android/inputmethod/accessibility/KeyCodeDescriptionMapper.java +++ b/java/src/com/android/inputmethod/accessibility/KeyCodeDescriptionMapper.java @@ -28,7 +28,7 @@ import com.android.inputmethod.keyboard.Keyboard; import com.android.inputmethod.keyboard.KeyboardId; import com.android.inputmethod.latin.R; import com.android.inputmethod.latin.common.Constants; -import com.android.inputmethod.latin.utils.StringUtils; +import com.android.inputmethod.latin.common.StringUtils; import java.util.Locale; diff --git a/java/src/com/android/inputmethod/compat/UserDictionaryCompatUtils.java b/java/src/com/android/inputmethod/compat/UserDictionaryCompatUtils.java index 1fb597ba6..b78c357ab 100644 --- a/java/src/com/android/inputmethod/compat/UserDictionaryCompatUtils.java +++ b/java/src/com/android/inputmethod/compat/UserDictionaryCompatUtils.java @@ -16,42 +16,33 @@ package com.android.inputmethod.compat; +import android.annotation.TargetApi; import android.content.Context; -import android.provider.UserDictionary.Words; +import android.os.Build; +import android.provider.UserDictionary; -import java.lang.reflect.Method; import java.util.Locale; public final class UserDictionaryCompatUtils { - // UserDictionary.Words#addWord(Context, String, int, String, Locale) was introduced - // in API level 16 (Build.VERSION_CODES.JELLY_BEAN). - private static final Method METHOD_addWord = CompatUtils.getMethod(Words.class, "addWord", - Context.class, String.class, int.class, String.class, Locale.class); - @SuppressWarnings("deprecation") public static void addWord(final Context context, final String word, final int freq, final String shortcut, final Locale locale) { - if (hasNewerAddWord()) { - CompatUtils.invoke(Words.class, null, METHOD_addWord, context, word, freq, shortcut, - locale); - } else { - // Fall back to the pre-JellyBean method. - final int localeType; - if (null == locale) { - localeType = Words.LOCALE_TYPE_ALL; - } else { - final Locale currentLocale = context.getResources().getConfiguration().locale; - if (locale.equals(currentLocale)) { - localeType = Words.LOCALE_TYPE_CURRENT; - } else { - localeType = Words.LOCALE_TYPE_ALL; - } - } - Words.addWord(context, word, freq, localeType); + if (BuildCompatUtils.EFFECTIVE_SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { + addWordWithShortcut(context, word, freq, shortcut, locale); + return; } + // Fall back to the pre-JellyBean method. + final Locale currentLocale = context.getResources().getConfiguration().locale; + final int localeType = currentLocale.equals(locale) + ? UserDictionary.Words.LOCALE_TYPE_CURRENT : UserDictionary.Words.LOCALE_TYPE_ALL; + UserDictionary.Words.addWord(context, word, freq, localeType); } - public static final boolean hasNewerAddWord() { - return null != METHOD_addWord; + // {@link UserDictionary.Words#addWord(Context,String,int,String,Locale)} was introduced + // in API level 16 (Build.VERSION_CODES.JELLY_BEAN). + @TargetApi(Build.VERSION_CODES.JELLY_BEAN) + private static void addWordWithShortcut(final Context context, final String word, + final int freq, final String shortcut, final Locale locale) { + UserDictionary.Words.addWord(context, word, freq, shortcut, locale); } } diff --git a/java/src/com/android/inputmethod/event/Event.java b/java/src/com/android/inputmethod/event/Event.java index 92bcda455..a1226dc93 100644 --- a/java/src/com/android/inputmethod/event/Event.java +++ b/java/src/com/android/inputmethod/event/Event.java @@ -19,7 +19,7 @@ package com.android.inputmethod.event; import com.android.inputmethod.annotations.ExternallyReferenced; import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; import com.android.inputmethod.latin.common.Constants; -import com.android.inputmethod.latin.utils.StringUtils; +import com.android.inputmethod.latin.common.StringUtils; import javax.annotation.Nonnull; diff --git a/java/src/com/android/inputmethod/keyboard/Key.java b/java/src/com/android/inputmethod/keyboard/Key.java index 04a0f1e13..6b2094b9e 100644 --- a/java/src/com/android/inputmethod/keyboard/Key.java +++ b/java/src/com/android/inputmethod/keyboard/Key.java @@ -38,7 +38,7 @@ import com.android.inputmethod.keyboard.internal.KeyboardRow; import com.android.inputmethod.keyboard.internal.MoreKeySpec; import com.android.inputmethod.latin.R; import com.android.inputmethod.latin.common.Constants; -import com.android.inputmethod.latin.utils.StringUtils; +import com.android.inputmethod.latin.common.StringUtils; import java.util.Arrays; import java.util.Locale; diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardActionListener.java b/java/src/com/android/inputmethod/keyboard/KeyboardActionListener.java index ac66f7c6a..cdd632bc8 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyboardActionListener.java +++ b/java/src/com/android/inputmethod/keyboard/KeyboardActionListener.java @@ -16,8 +16,8 @@ package com.android.inputmethod.keyboard; -import com.android.inputmethod.latin.InputPointers; import com.android.inputmethod.latin.common.Constants; +import com.android.inputmethod.latin.common.InputPointers; public interface KeyboardActionListener { /** diff --git a/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java b/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java index e66523be0..6dbd94740 100644 --- a/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java +++ b/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java @@ -56,9 +56,9 @@ import com.android.inputmethod.latin.R; import com.android.inputmethod.latin.RichInputMethodSubtype; import com.android.inputmethod.latin.SuggestedWords; import com.android.inputmethod.latin.common.Constants; +import com.android.inputmethod.latin.common.StringUtils; import com.android.inputmethod.latin.settings.DebugSettings; import com.android.inputmethod.latin.utils.CoordinateUtils; -import com.android.inputmethod.latin.utils.StringUtils; import com.android.inputmethod.latin.utils.TypefaceUtils; import java.util.Locale; @@ -451,13 +451,6 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack windowContentView.addView(mDrawingPreviewPlacerView); } - // Implements {@link DrawingHandler.Callbacks} method. - @Override - public void dismissAllKeyPreviews() { - mKeyPreviewChoreographer.dismissAllKeyPreviews(); - PointerTracker.setReleasedKeyGraphicsToAllKeys(); - } - @Override public void showKeyPreview(final Key key) { // If the key is invalid or has no key preview, we must not show key preview. @@ -673,6 +666,12 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack @Override public void onShowMoreKeysPanel(final MoreKeysPanel panel) { locatePreviewPlacerView(); + // Dismiss another {@link MoreKeysPanel} that may be being showed. + onDismissMoreKeysPanel(); + // Dismiss all key previews that may be being showed. + PointerTracker.setReleasedKeyGraphicsToAllKeys(); + // Dismiss sliding key input preview that may be being showed. + dismissSlidingKeyInputPreview(); panel.showInParent(mDrawingPreviewPlacerView); mMoreKeysPanel = panel; } @@ -740,7 +739,7 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack public void cancelAllOngoingEvents() { mKeyTimerHandler.cancelAllMessages(); mDrawingHandler.cancelAllMessages(); - dismissAllKeyPreviews(); + PointerTracker.setReleasedKeyGraphicsToAllKeys(); dismissGestureFloatingPreviewText(); dismissSlidingKeyInputPreview(); PointerTracker.dismissAllMoreKeysPanels(); diff --git a/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboard.java b/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboard.java index abcfff8a6..f0de86ff9 100644 --- a/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboard.java +++ b/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboard.java @@ -24,7 +24,7 @@ import com.android.inputmethod.keyboard.internal.KeyboardBuilder; import com.android.inputmethod.keyboard.internal.KeyboardParams; import com.android.inputmethod.keyboard.internal.MoreKeySpec; import com.android.inputmethod.latin.R; -import com.android.inputmethod.latin.utils.StringUtils; +import com.android.inputmethod.latin.common.StringUtils; import com.android.inputmethod.latin.utils.TypefaceUtils; public final class MoreKeysKeyboard extends Keyboard { diff --git a/java/src/com/android/inputmethod/keyboard/PointerTracker.java b/java/src/com/android/inputmethod/keyboard/PointerTracker.java index fe6270fb5..5a540ff17 100644 --- a/java/src/com/android/inputmethod/keyboard/PointerTracker.java +++ b/java/src/com/android/inputmethod/keyboard/PointerTracker.java @@ -31,9 +31,9 @@ import com.android.inputmethod.keyboard.internal.GestureStrokeDrawingPoints; import com.android.inputmethod.keyboard.internal.GestureStrokeRecognitionParams; import com.android.inputmethod.keyboard.internal.PointerTrackerQueue; import com.android.inputmethod.keyboard.internal.TypingTimeRecorder; -import com.android.inputmethod.latin.InputPointers; import com.android.inputmethod.latin.R; import com.android.inputmethod.latin.common.Constants; +import com.android.inputmethod.latin.common.InputPointers; import com.android.inputmethod.latin.define.DebugFlags; import com.android.inputmethod.latin.settings.Settings; import com.android.inputmethod.latin.utils.CoordinateUtils; diff --git a/java/src/com/android/inputmethod/keyboard/emoji/EmojiCategory.java b/java/src/com/android/inputmethod/keyboard/emoji/EmojiCategory.java index c8e832b93..a9711aed2 100644 --- a/java/src/com/android/inputmethod/keyboard/emoji/EmojiCategory.java +++ b/java/src/com/android/inputmethod/keyboard/emoji/EmojiCategory.java @@ -30,7 +30,6 @@ import com.android.inputmethod.keyboard.Keyboard; import com.android.inputmethod.keyboard.KeyboardId; import com.android.inputmethod.keyboard.KeyboardLayoutSet; import com.android.inputmethod.latin.R; -import com.android.inputmethod.latin.common.Constants; import com.android.inputmethod.latin.settings.Settings; import java.util.ArrayList; diff --git a/java/src/com/android/inputmethod/keyboard/internal/BatchInputArbiter.java b/java/src/com/android/inputmethod/keyboard/internal/BatchInputArbiter.java index efb365e42..77d0e7a90 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/BatchInputArbiter.java +++ b/java/src/com/android/inputmethod/keyboard/internal/BatchInputArbiter.java @@ -16,8 +16,8 @@ package com.android.inputmethod.keyboard.internal; -import com.android.inputmethod.latin.InputPointers; import com.android.inputmethod.latin.common.Constants; +import com.android.inputmethod.latin.common.InputPointers; /** * This class arbitrates batch input. diff --git a/java/src/com/android/inputmethod/keyboard/internal/CodesArrayParser.java b/java/src/com/android/inputmethod/keyboard/internal/CodesArrayParser.java index 5797b7efd..2e2ed52dd 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/CodesArrayParser.java +++ b/java/src/com/android/inputmethod/keyboard/internal/CodesArrayParser.java @@ -17,7 +17,7 @@ package com.android.inputmethod.keyboard.internal; import com.android.inputmethod.latin.common.Constants; -import com.android.inputmethod.latin.utils.StringUtils; +import com.android.inputmethod.latin.common.StringUtils; import android.text.TextUtils; diff --git a/java/src/com/android/inputmethod/keyboard/internal/DrawingHandler.java b/java/src/com/android/inputmethod/keyboard/internal/DrawingHandler.java index 1a55359f5..6513485de 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/DrawingHandler.java +++ b/java/src/com/android/inputmethod/keyboard/internal/DrawingHandler.java @@ -29,7 +29,6 @@ import javax.annotation.Nonnull; public class DrawingHandler extends LeakGuardHandlerWrapper<Callbacks> { public interface Callbacks { public void dismissKeyPreviewWithoutDelay(Key key); - public void dismissAllKeyPreviews(); public void showGestureFloatingPreviewText(SuggestedWords suggestedWords); } @@ -60,20 +59,11 @@ public class DrawingHandler extends LeakGuardHandlerWrapper<Callbacks> { sendMessageDelayed(obtainMessage(MSG_DISMISS_KEY_PREVIEW, key), delay); } - private void cancelAllDismissKeyPreviews() { - removeMessages(MSG_DISMISS_KEY_PREVIEW); - final Callbacks callbacks = getOwnerInstance(); - if (callbacks == null) { - return; - } - callbacks.dismissAllKeyPreviews(); - } - public void dismissGestureFloatingPreviewText(final long delay) { sendMessageDelayed(obtainMessage(MSG_DISMISS_GESTURE_FLOATING_PREVIEW_TEXT), delay); } public void cancelAllMessages() { - cancelAllDismissKeyPreviews(); + removeMessages(MSG_DISMISS_KEY_PREVIEW); } } diff --git a/java/src/com/android/inputmethod/keyboard/internal/GestureStrokeDrawingPoints.java b/java/src/com/android/inputmethod/keyboard/internal/GestureStrokeDrawingPoints.java index 7d09e9d2f..07ef00924 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/GestureStrokeDrawingPoints.java +++ b/java/src/com/android/inputmethod/keyboard/internal/GestureStrokeDrawingPoints.java @@ -16,7 +16,7 @@ package com.android.inputmethod.keyboard.internal; -import com.android.inputmethod.latin.utils.ResizableIntArray; +import com.android.inputmethod.latin.common.ResizableIntArray; /** * This class holds drawing points to represent a gesture stroke on the screen. diff --git a/java/src/com/android/inputmethod/keyboard/internal/GestureStrokeRecognitionPoints.java b/java/src/com/android/inputmethod/keyboard/internal/GestureStrokeRecognitionPoints.java index 99ec18f4d..3e901114a 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/GestureStrokeRecognitionPoints.java +++ b/java/src/com/android/inputmethod/keyboard/internal/GestureStrokeRecognitionPoints.java @@ -18,9 +18,9 @@ package com.android.inputmethod.keyboard.internal; import android.util.Log; -import com.android.inputmethod.latin.InputPointers; import com.android.inputmethod.latin.common.Constants; -import com.android.inputmethod.latin.utils.ResizableIntArray; +import com.android.inputmethod.latin.common.InputPointers; +import com.android.inputmethod.latin.common.ResizableIntArray; /** * This class holds event points to recognize a gesture stroke. diff --git a/java/src/com/android/inputmethod/keyboard/internal/GestureTrailDrawingPoints.java b/java/src/com/android/inputmethod/keyboard/internal/GestureTrailDrawingPoints.java index 67683e247..4d998e443 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/GestureTrailDrawingPoints.java +++ b/java/src/com/android/inputmethod/keyboard/internal/GestureTrailDrawingPoints.java @@ -24,7 +24,7 @@ import android.graphics.Rect; import android.os.SystemClock; import com.android.inputmethod.latin.common.Constants; -import com.android.inputmethod.latin.utils.ResizableIntArray; +import com.android.inputmethod.latin.common.ResizableIntArray; /** * This class holds drawing points to represent a gesture trail. The gesture trail may contain diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyPreviewChoreographer.java b/java/src/com/android/inputmethod/keyboard/internal/KeyPreviewChoreographer.java index ddb193ead..d3764877c 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/KeyPreviewChoreographer.java +++ b/java/src/com/android/inputmethod/keyboard/internal/KeyPreviewChoreographer.java @@ -28,7 +28,6 @@ import com.android.inputmethod.latin.utils.ViewLayoutUtils; import java.util.ArrayDeque; import java.util.HashMap; -import java.util.HashSet; /** * This class controls pop up key previews. This class decides: @@ -69,12 +68,6 @@ public final class KeyPreviewChoreographer { return mShowingKeyPreviewViews.containsKey(key); } - public void dismissAllKeyPreviews() { - for (final Key key : new HashSet<>(mShowingKeyPreviewViews.keySet())) { - dismissKeyPreview(key, false /* withAnimation */); - } - } - public void dismissKeyPreview(final Key key, final boolean withAnimation) { if (key == null) { return; diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeySpecParser.java b/java/src/com/android/inputmethod/keyboard/internal/KeySpecParser.java index d33e53a61..63aab968b 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/KeySpecParser.java +++ b/java/src/com/android/inputmethod/keyboard/internal/KeySpecParser.java @@ -20,7 +20,7 @@ import static com.android.inputmethod.latin.common.Constants.CODE_OUTPUT_TEXT; import static com.android.inputmethod.latin.common.Constants.CODE_UNSPECIFIED; import com.android.inputmethod.latin.common.Constants; -import com.android.inputmethod.latin.utils.StringUtils; +import com.android.inputmethod.latin.common.StringUtils; /** * The string parser of the key specification. diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardBuilder.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardBuilder.java index 6c75fb6c1..c739bf3e0 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardBuilder.java +++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardBuilder.java @@ -34,8 +34,8 @@ import com.android.inputmethod.keyboard.KeyboardId; import com.android.inputmethod.keyboard.KeyboardTheme; import com.android.inputmethod.latin.R; import com.android.inputmethod.latin.common.Constants; +import com.android.inputmethod.latin.common.StringUtils; import com.android.inputmethod.latin.utils.ResourceUtils; -import com.android.inputmethod.latin.utils.StringUtils; import com.android.inputmethod.latin.utils.SubtypeLocaleUtils; import com.android.inputmethod.latin.utils.XmlParseUtils; import com.android.inputmethod.latin.utils.XmlParseUtils.ParseException; diff --git a/java/src/com/android/inputmethod/keyboard/internal/MoreKeySpec.java b/java/src/com/android/inputmethod/keyboard/internal/MoreKeySpec.java index 4392dbcbd..a0bb406aa 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/MoreKeySpec.java +++ b/java/src/com/android/inputmethod/keyboard/internal/MoreKeySpec.java @@ -22,9 +22,9 @@ import android.util.SparseIntArray; import com.android.inputmethod.compat.CharacterCompat; import com.android.inputmethod.keyboard.Key; import com.android.inputmethod.latin.common.Constants; +import com.android.inputmethod.latin.common.StringUtils; import com.android.inputmethod.latin.define.DebugFlags; import com.android.inputmethod.latin.utils.CollectionUtils; -import com.android.inputmethod.latin.utils.StringUtils; import java.util.ArrayList; import java.util.Arrays; diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionary.java b/java/src/com/android/inputmethod/latin/BinaryDictionary.java index 76459f817..8e9b5c6f6 100644 --- a/java/src/com/android/inputmethod/latin/BinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/BinaryDictionary.java @@ -24,6 +24,8 @@ import com.android.inputmethod.annotations.UsedForTesting; import com.android.inputmethod.keyboard.ProximityInfo; import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; import com.android.inputmethod.latin.common.Constants; +import com.android.inputmethod.latin.common.InputPointers; +import com.android.inputmethod.latin.common.StringUtils; import com.android.inputmethod.latin.makedict.DictionaryHeader; import com.android.inputmethod.latin.makedict.FormatSpec; import com.android.inputmethod.latin.makedict.FormatSpec.DictionaryOptions; @@ -33,7 +35,6 @@ import com.android.inputmethod.latin.settings.SettingsValuesForSuggestion; import com.android.inputmethod.latin.utils.BinaryDictionaryUtils; import com.android.inputmethod.latin.utils.FileUtils; import com.android.inputmethod.latin.utils.JniUtils; -import com.android.inputmethod.latin.utils.StringUtils; import com.android.inputmethod.latin.utils.WordInputEventForPersonalization; import java.io.File; diff --git a/java/src/com/android/inputmethod/latin/ContactsBinaryDictionary.java b/java/src/com/android/inputmethod/latin/ContactsBinaryDictionary.java index 08e1983d4..59763c0fc 100644 --- a/java/src/com/android/inputmethod/latin/ContactsBinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/ContactsBinaryDictionary.java @@ -30,9 +30,9 @@ import android.util.Log; import com.android.inputmethod.annotations.ExternallyReferenced; import com.android.inputmethod.latin.common.Constants; +import com.android.inputmethod.latin.common.StringUtils; import com.android.inputmethod.latin.personalization.AccountUtils; import com.android.inputmethod.latin.utils.ExecutorUtils; -import com.android.inputmethod.latin.utils.StringUtils; import java.io.File; import java.util.ArrayList; diff --git a/java/src/com/android/inputmethod/latin/EmojiAltPhysicalKeyDetector.java b/java/src/com/android/inputmethod/latin/EmojiAltPhysicalKeyDetector.java new file mode 100644 index 000000000..8116a4983 --- /dev/null +++ b/java/src/com/android/inputmethod/latin/EmojiAltPhysicalKeyDetector.java @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2014, 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.latin; + +import android.view.KeyEvent; + +import com.android.inputmethod.keyboard.KeyboardSwitcher; +import com.android.inputmethod.latin.settings.Settings; + +/** + * A class for detecting Emoji-Alt physical key. + */ +final class EmojiAltPhysicalKeyDetector { + // True if the Alt key has been used as a modifier. In this case the Alt key up isn't + // recognized as an emoji key. + private boolean mAltHasBeenUsedAsAModifier; + + /** + * Record a down key event. + * @param keyEvent a down key event. + */ + public void onKeyDown(final KeyEvent keyEvent) { + if (isAltKey(keyEvent)) { + mAltHasBeenUsedAsAModifier = false; + } + if (containsAltModifier(keyEvent)) { + mAltHasBeenUsedAsAModifier = true; + } + } + + /** + * Determine whether an up key event is a special key up or not. + * @param keyEvent an up key event. + */ + public void onKeyUp(final KeyEvent keyEvent) { + if (keyEvent.isCanceled()) { + // This key up event was a part of key combinations and should be ignored. + return; + } + if (!isAltKey(keyEvent)) { + mAltHasBeenUsedAsAModifier |= containsAltModifier(keyEvent); + return; + } + if (containsAltModifier(keyEvent)) { + mAltHasBeenUsedAsAModifier = true; + return; + } + if (!Settings.getInstance().getCurrent().mEnableEmojiAltPhysicalKey) { + return; + } + if (!mAltHasBeenUsedAsAModifier) { + onEmojiAltKeyDetected(); + } + } + + private static void onEmojiAltKeyDetected() { + KeyboardSwitcher.getInstance().onToggleEmojiKeyboard(); + } + + private static boolean isAltKey(final KeyEvent keyEvent) { + final int keyCode = keyEvent.getKeyCode(); + return keyCode == KeyEvent.KEYCODE_ALT_LEFT || keyCode == KeyEvent.KEYCODE_ALT_RIGHT; + } + + private static boolean containsAltModifier(final KeyEvent keyEvent) { + final int metaState = keyEvent.getMetaState(); + // TODO: Support multiple keyboards. Take device id into account. + switch (keyEvent.getKeyCode()) { + case KeyEvent.KEYCODE_ALT_LEFT: + // Return true if Left-Alt is pressed with Right-Alt pressed. + return (metaState & KeyEvent.META_ALT_RIGHT_ON) != 0; + case KeyEvent.KEYCODE_ALT_RIGHT: + // Return true if Right-Alt is pressed with Left-Alt pressed. + return (metaState & KeyEvent.META_ALT_LEFT_ON) != 0; + default: + return (metaState & (KeyEvent.META_ALT_LEFT_ON | KeyEvent.META_ALT_RIGHT_ON)) != 0; + } + } +} diff --git a/java/src/com/android/inputmethod/latin/InputAttributes.java b/java/src/com/android/inputmethod/latin/InputAttributes.java index 002222080..37effeead 100644 --- a/java/src/com/android/inputmethod/latin/InputAttributes.java +++ b/java/src/com/android/inputmethod/latin/InputAttributes.java @@ -24,8 +24,8 @@ import android.text.InputType; import android.util.Log; import android.view.inputmethod.EditorInfo; +import com.android.inputmethod.latin.common.StringUtils; import com.android.inputmethod.latin.utils.InputTypeUtils; -import com.android.inputmethod.latin.utils.StringUtils; import java.util.ArrayList; import java.util.Arrays; diff --git a/java/src/com/android/inputmethod/latin/LastComposedWord.java b/java/src/com/android/inputmethod/latin/LastComposedWord.java index c4c389411..9fcdb2229 100644 --- a/java/src/com/android/inputmethod/latin/LastComposedWord.java +++ b/java/src/com/android/inputmethod/latin/LastComposedWord.java @@ -20,6 +20,7 @@ import android.text.TextUtils; import com.android.inputmethod.event.Event; import com.android.inputmethod.latin.common.Constants; +import com.android.inputmethod.latin.common.InputPointers; import java.util.ArrayList; diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index 11cbec378..5fa28d571 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -77,6 +77,7 @@ import com.android.inputmethod.keyboard.TextDecoratorUi; import com.android.inputmethod.latin.Suggest.OnGetSuggestedWordsCallback; import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; import com.android.inputmethod.latin.common.Constants; +import com.android.inputmethod.latin.common.InputPointers; import com.android.inputmethod.latin.define.DebugFlags; import com.android.inputmethod.latin.define.ProductionFlags; import com.android.inputmethod.latin.inputlogic.InputLogic; @@ -167,7 +168,8 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen @UsedForTesting final KeyboardSwitcher mKeyboardSwitcher; final SubtypeSwitcher mSubtypeSwitcher; private final SubtypeState mSubtypeState = new SubtypeState(); - private final SpecialKeyDetector mSpecialKeyDetector; + private final EmojiAltPhysicalKeyDetector mEmojiAltPhysicalKeyDetector = + new EmojiAltPhysicalKeyDetector(); private StatsUtilsManager mStatsUtilsManager; // Working variable for {@link #startShowingInputView()} and // {@link #onEvaluateInputViewShown()}. @@ -545,7 +547,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen mSettings = Settings.getInstance(); mSubtypeSwitcher = SubtypeSwitcher.getInstance(); mKeyboardSwitcher = KeyboardSwitcher.getInstance(); - mSpecialKeyDetector = new SpecialKeyDetector(this); mStatsUtilsManager = StatsUtilsManager.getInstance(); mIsHardwareAcceleratedDrawingEnabled = InputMethodServiceCompatUtils.enableHardwareAcceleration(this); @@ -1765,7 +1766,8 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen // Hooks for hardware keyboard @Override public boolean onKeyDown(final int keyCode, final KeyEvent keyEvent) { - mSpecialKeyDetector.onKeyDown(keyEvent); + // TODO: This should be processed in {@link InputLogic}. + mEmojiAltPhysicalKeyDetector.onKeyDown(keyEvent); if (!ProductionFlags.IS_HARDWARE_KEYBOARD_SUPPORTED) { return super.onKeyDown(keyCode, keyEvent); } @@ -1786,7 +1788,8 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen @Override public boolean onKeyUp(final int keyCode, final KeyEvent keyEvent) { - mSpecialKeyDetector.onKeyUp(keyEvent); + // TODO: This should be processed in {@link InputLogic}. + mEmojiAltPhysicalKeyDetector.onKeyUp(keyEvent); if (!ProductionFlags.IS_HARDWARE_KEYBOARD_SUPPORTED) { return super.onKeyUp(keyCode, keyEvent); } diff --git a/java/src/com/android/inputmethod/latin/NgramContext.java b/java/src/com/android/inputmethod/latin/NgramContext.java index 0ccea4732..82a13274d 100644 --- a/java/src/com/android/inputmethod/latin/NgramContext.java +++ b/java/src/com/android/inputmethod/latin/NgramContext.java @@ -20,7 +20,7 @@ import android.text.TextUtils; import com.android.inputmethod.annotations.UsedForTesting; import com.android.inputmethod.latin.common.Constants; -import com.android.inputmethod.latin.utils.StringUtils; +import com.android.inputmethod.latin.common.StringUtils; import java.util.Arrays; diff --git a/java/src/com/android/inputmethod/latin/PunctuationSuggestions.java b/java/src/com/android/inputmethod/latin/PunctuationSuggestions.java index 93598d2fb..a65304cd0 100644 --- a/java/src/com/android/inputmethod/latin/PunctuationSuggestions.java +++ b/java/src/com/android/inputmethod/latin/PunctuationSuggestions.java @@ -18,7 +18,7 @@ package com.android.inputmethod.latin; import com.android.inputmethod.keyboard.internal.KeySpecParser; import com.android.inputmethod.latin.common.Constants; -import com.android.inputmethod.latin.utils.StringUtils; +import com.android.inputmethod.latin.common.StringUtils; import java.util.ArrayList; import java.util.Arrays; diff --git a/java/src/com/android/inputmethod/latin/RichInputConnection.java b/java/src/com/android/inputmethod/latin/RichInputConnection.java index 0763ef807..834f747d9 100644 --- a/java/src/com/android/inputmethod/latin/RichInputConnection.java +++ b/java/src/com/android/inputmethod/latin/RichInputConnection.java @@ -35,6 +35,7 @@ import android.view.inputmethod.InputMethodManager; import com.android.inputmethod.compat.InputConnectionCompatUtils; import com.android.inputmethod.latin.common.Constants; +import com.android.inputmethod.latin.common.StringUtils; import com.android.inputmethod.latin.inputlogic.PrivateCommandPerformer; import com.android.inputmethod.latin.settings.SpacingAndPunctuations; import com.android.inputmethod.latin.utils.CapsModeUtils; @@ -42,7 +43,6 @@ import com.android.inputmethod.latin.utils.DebugLogUtils; import com.android.inputmethod.latin.utils.NgramContextUtils; import com.android.inputmethod.latin.utils.ScriptUtils; import com.android.inputmethod.latin.utils.SpannableStringUtils; -import com.android.inputmethod.latin.utils.StringUtils; import com.android.inputmethod.latin.utils.TextRange; import javax.annotation.Nonnull; diff --git a/java/src/com/android/inputmethod/latin/Suggest.java b/java/src/com/android/inputmethod/latin/Suggest.java index 17df1eab4..bb7d24305 100644 --- a/java/src/com/android/inputmethod/latin/Suggest.java +++ b/java/src/com/android/inputmethod/latin/Suggest.java @@ -21,11 +21,11 @@ import android.text.TextUtils; import com.android.inputmethod.keyboard.ProximityInfo; import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; import com.android.inputmethod.latin.common.Constants; +import com.android.inputmethod.latin.common.StringUtils; import com.android.inputmethod.latin.define.DebugFlags; import com.android.inputmethod.latin.settings.SettingsValuesForSuggestion; import com.android.inputmethod.latin.utils.AutoCorrectionUtils; import com.android.inputmethod.latin.utils.BinaryDictionaryUtils; -import com.android.inputmethod.latin.utils.StringUtils; import com.android.inputmethod.latin.utils.SuggestionResults; import java.util.ArrayList; diff --git a/java/src/com/android/inputmethod/latin/SuggestedWords.java b/java/src/com/android/inputmethod/latin/SuggestedWords.java index a6428896e..b84de6919 100644 --- a/java/src/com/android/inputmethod/latin/SuggestedWords.java +++ b/java/src/com/android/inputmethod/latin/SuggestedWords.java @@ -21,8 +21,8 @@ import android.view.inputmethod.CompletionInfo; import com.android.inputmethod.annotations.UsedForTesting; import com.android.inputmethod.latin.common.Constants; +import com.android.inputmethod.latin.common.StringUtils; import com.android.inputmethod.latin.define.DebugFlags; -import com.android.inputmethod.latin.utils.StringUtils; import java.util.ArrayList; import java.util.Arrays; diff --git a/java/src/com/android/inputmethod/latin/WordComposer.java b/java/src/com/android/inputmethod/latin/WordComposer.java index 8830521c7..0b77f2ce3 100644 --- a/java/src/com/android/inputmethod/latin/WordComposer.java +++ b/java/src/com/android/inputmethod/latin/WordComposer.java @@ -20,9 +20,10 @@ import com.android.inputmethod.event.CombinerChain; import com.android.inputmethod.event.Event; import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; import com.android.inputmethod.latin.common.Constants; +import com.android.inputmethod.latin.common.InputPointers; +import com.android.inputmethod.latin.common.StringUtils; import com.android.inputmethod.latin.define.DebugFlags; import com.android.inputmethod.latin.utils.CoordinateUtils; -import com.android.inputmethod.latin.utils.StringUtils; import java.util.ArrayList; import java.util.Collections; diff --git a/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java index a67f46108..bafea178e 100644 --- a/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java +++ b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java @@ -41,7 +41,6 @@ import com.android.inputmethod.keyboard.TextDecorator; import com.android.inputmethod.keyboard.TextDecoratorUiOperator; import com.android.inputmethod.latin.Dictionary; import com.android.inputmethod.latin.DictionaryFacilitator; -import com.android.inputmethod.latin.InputPointers; import com.android.inputmethod.latin.LastComposedWord; import com.android.inputmethod.latin.LatinIME; import com.android.inputmethod.latin.NgramContext; @@ -52,6 +51,8 @@ import com.android.inputmethod.latin.SuggestedWords; import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; import com.android.inputmethod.latin.WordComposer; import com.android.inputmethod.latin.common.Constants; +import com.android.inputmethod.latin.common.InputPointers; +import com.android.inputmethod.latin.common.StringUtils; import com.android.inputmethod.latin.define.DebugFlags; import com.android.inputmethod.latin.settings.SettingsValues; import com.android.inputmethod.latin.settings.SettingsValuesForSuggestion; @@ -61,7 +62,6 @@ import com.android.inputmethod.latin.utils.AsyncResultHolder; import com.android.inputmethod.latin.utils.InputTypeUtils; import com.android.inputmethod.latin.utils.RecapitalizeStatus; import com.android.inputmethod.latin.utils.StatsUtils; -import com.android.inputmethod.latin.utils.StringUtils; import com.android.inputmethod.latin.utils.TextRange; import java.util.ArrayList; diff --git a/java/src/com/android/inputmethod/latin/inputlogic/InputLogicHandler.java b/java/src/com/android/inputmethod/latin/inputlogic/InputLogicHandler.java index 5f391dd9b..ddc4ad99c 100644 --- a/java/src/com/android/inputmethod/latin/inputlogic/InputLogicHandler.java +++ b/java/src/com/android/inputmethod/latin/inputlogic/InputLogicHandler.java @@ -21,10 +21,10 @@ import android.os.HandlerThread; import android.os.Message; import com.android.inputmethod.compat.LooperCompatUtils; -import com.android.inputmethod.latin.InputPointers; import com.android.inputmethod.latin.LatinIME; import com.android.inputmethod.latin.SuggestedWords; import com.android.inputmethod.latin.Suggest.OnGetSuggestedWordsCallback; +import com.android.inputmethod.latin.common.InputPointers; /** * A helper to manage deferred tasks for the input logic. diff --git a/java/src/com/android/inputmethod/latin/makedict/WordProperty.java b/java/src/com/android/inputmethod/latin/makedict/WordProperty.java index e7808e46e..388d57816 100644 --- a/java/src/com/android/inputmethod/latin/makedict/WordProperty.java +++ b/java/src/com/android/inputmethod/latin/makedict/WordProperty.java @@ -21,8 +21,8 @@ import com.android.inputmethod.latin.BinaryDictionary; import com.android.inputmethod.latin.Dictionary; import com.android.inputmethod.latin.NgramContext; import com.android.inputmethod.latin.NgramContext.WordInfo; +import com.android.inputmethod.latin.common.StringUtils; import com.android.inputmethod.latin.utils.CombinedFormatUtils; -import com.android.inputmethod.latin.utils.StringUtils; import java.util.ArrayList; import java.util.Arrays; diff --git a/java/src/com/android/inputmethod/latin/settings/AppearanceSettingsFragment.java b/java/src/com/android/inputmethod/latin/settings/AppearanceSettingsFragment.java index a9884ba13..554edc85c 100644 --- a/java/src/com/android/inputmethod/latin/settings/AppearanceSettingsFragment.java +++ b/java/src/com/android/inputmethod/latin/settings/AppearanceSettingsFragment.java @@ -19,9 +19,9 @@ package com.android.inputmethod.latin.settings; import android.os.Bundle; import com.android.inputmethod.latin.R; +import com.android.inputmethod.latin.common.Constants; import com.android.inputmethod.latin.define.ProductionFlags; - /** * "Appearance" settings sub screen. */ @@ -30,8 +30,8 @@ public final class AppearanceSettingsFragment extends SubScreenFragment { public void onCreate(final Bundle icicle) { super.onCreate(icicle); addPreferencesFromResource(R.xml.prefs_screen_appearance); - if (!ProductionFlags.IS_SPLIT_KEYBOARD_SUPPORTED - || !Settings.getInstance().getCurrent().isTablet()) { + if (!ProductionFlags.IS_SPLIT_KEYBOARD_SUPPORTED || + Constants.isPhone(Settings.readScreenMetrics(getResources()))) { removePreference(Settings.PREF_ENABLE_SPLIT_KEYBOARD); } } @@ -43,4 +43,4 @@ public final class AppearanceSettingsFragment extends SubScreenFragment { findPreference(Settings.PREF_CUSTOM_INPUT_STYLES)); ThemeSettingsFragment.updateKeyboardThemeSummary(findPreference(Settings.SCREEN_THEME)); } -}
\ No newline at end of file +} diff --git a/java/src/com/android/inputmethod/latin/settings/DebugSettings.java b/java/src/com/android/inputmethod/latin/settings/DebugSettings.java index 768cba9b2..4985c2f08 100644 --- a/java/src/com/android/inputmethod/latin/settings/DebugSettings.java +++ b/java/src/com/android/inputmethod/latin/settings/DebugSettings.java @@ -27,8 +27,6 @@ package com.android.inputmethod.latin.settings; public final class DebugSettings { public static final String PREF_DEBUG_MODE = "debug_mode"; public static final String PREF_FORCE_NON_DISTINCT_MULTITOUCH = "force_non_distinct_multitouch"; - public static final String PREF_FORCE_PHYSICAL_KEYBOARD_SPECIAL_KEY = - "force_physical_keyboard_special_key"; public static final String PREF_HAS_CUSTOM_KEY_PREVIEW_ANIMATION_PARAMS = "pref_has_custom_key_preview_animation_params"; public static final String PREF_KEY_PREVIEW_DISMISS_DURATION = diff --git a/java/src/com/android/inputmethod/latin/settings/DebugSettingsFragment.java b/java/src/com/android/inputmethod/latin/settings/DebugSettingsFragment.java index 475f1def7..2e5c3c479 100644 --- a/java/src/com/android/inputmethod/latin/settings/DebugSettingsFragment.java +++ b/java/src/com/android/inputmethod/latin/settings/DebugSettingsFragment.java @@ -142,8 +142,7 @@ public final class DebugSettingsFragment extends SubScreenFragment mServiceNeedsRestart = true; return; } - if (key.equals(DebugSettings.PREF_FORCE_NON_DISTINCT_MULTITOUCH) - || key.equals(DebugSettings.PREF_FORCE_PHYSICAL_KEYBOARD_SPECIAL_KEY)) { + if (key.equals(DebugSettings.PREF_FORCE_NON_DISTINCT_MULTITOUCH)) { mServiceNeedsRestart = true; return; } diff --git a/java/src/com/android/inputmethod/latin/settings/LocalSettingsConstants.java b/java/src/com/android/inputmethod/latin/settings/LocalSettingsConstants.java index c9e9dc8d9..0fd94b0f8 100644 --- a/java/src/com/android/inputmethod/latin/settings/LocalSettingsConstants.java +++ b/java/src/com/android/inputmethod/latin/settings/LocalSettingsConstants.java @@ -46,7 +46,6 @@ public class LocalSettingsConstants { // correctly set for it to work on a new device. DebugSettings.PREF_DEBUG_MODE, DebugSettings.PREF_FORCE_NON_DISTINCT_MULTITOUCH, - DebugSettings.PREF_FORCE_PHYSICAL_KEYBOARD_SPECIAL_KEY, DebugSettings.PREF_HAS_CUSTOM_KEY_PREVIEW_ANIMATION_PARAMS, DebugSettings.PREF_KEY_PREVIEW_DISMISS_DURATION, DebugSettings.PREF_KEY_PREVIEW_DISMISS_END_X_SCALE, diff --git a/java/src/com/android/inputmethod/latin/settings/Settings.java b/java/src/com/android/inputmethod/latin/settings/Settings.java index 5e23693d2..19db60655 100644 --- a/java/src/com/android/inputmethod/latin/settings/Settings.java +++ b/java/src/com/android/inputmethod/latin/settings/Settings.java @@ -29,11 +29,11 @@ import com.android.inputmethod.compat.BuildCompatUtils; import com.android.inputmethod.latin.AudioAndHapticFeedbackManager; import com.android.inputmethod.latin.InputAttributes; import com.android.inputmethod.latin.R; +import com.android.inputmethod.latin.common.StringUtils; import com.android.inputmethod.latin.utils.AdditionalSubtypeUtils; import com.android.inputmethod.latin.utils.ResourceUtils; import com.android.inputmethod.latin.utils.RunInLocale; import com.android.inputmethod.latin.utils.StatsUtils; -import com.android.inputmethod.latin.utils.StringUtils; import java.util.Collections; import java.util.Locale; @@ -97,6 +97,8 @@ public final class Settings implements SharedPreferences.OnSharedPreferenceChang "pref_vibration_duration_settings"; public static final String PREF_KEYPRESS_SOUND_VOLUME = "pref_keypress_sound_volume"; public static final String PREF_KEY_LONGPRESS_TIMEOUT = "pref_key_longpress_timeout"; + public static final String PREF_ENABLE_EMOJI_ALT_PHYSICAL_KEY = + "pref_enable_emoji_alt_physical_key"; public static final String PREF_GESTURE_PREVIEW_TRAIL = "pref_gesture_preview_trail"; public static final String PREF_GESTURE_FLOATING_PREVIEW_TEXT = "pref_gesture_floating_preview_text"; @@ -211,6 +213,10 @@ public final class Settings implements SharedPreferences.OnSharedPreferenceChang return mSettingsValues.mBlockPotentiallyOffensive; } + public static int readScreenMetrics(final Resources res) { + return res.getInteger(R.integer.config_screen_metrics); + } + // Accessed from the settings interface, hence public public static boolean readKeypressSoundEnabled(final SharedPreferences prefs, final Resources res) { diff --git a/java/src/com/android/inputmethod/latin/settings/SettingsValues.java b/java/src/com/android/inputmethod/latin/settings/SettingsValues.java index 660be06d6..bdb4e64e0 100644 --- a/java/src/com/android/inputmethod/latin/settings/SettingsValues.java +++ b/java/src/com/android/inputmethod/latin/settings/SettingsValues.java @@ -29,7 +29,6 @@ import com.android.inputmethod.latin.InputAttributes; import com.android.inputmethod.latin.R; import com.android.inputmethod.latin.RichInputMethodManager; import com.android.inputmethod.latin.SubtypeSwitcher; -import com.android.inputmethod.latin.common.Constants; import com.android.inputmethod.latin.utils.AsyncResultHolder; import com.android.inputmethod.latin.utils.ResourceUtils; import com.android.inputmethod.latin.utils.TargetPackageInfoGetterTask; @@ -80,6 +79,7 @@ public class SettingsValues { public final boolean mSlidingKeyInputPreviewEnabled; public final boolean mPhraseGestureEnabled; public final int mKeyLongpressTimeout; + public final boolean mEnableEmojiAltPhysicalKey; public final boolean mEnableMetricsLogging; public final boolean mShouldShowLxxSuggestionUi; // Use split layout for keyboard. @@ -157,7 +157,7 @@ public class SettingsValues { mHasHardwareKeyboard = Settings.readHasHardwareKeyboard(res.getConfiguration()); mEnableMetricsLogging = prefs.getBoolean(Settings.PREF_ENABLE_METRICS_LOGGING, true); mIsSplitKeyboardEnabled = prefs.getBoolean(Settings.PREF_ENABLE_SPLIT_KEYBOARD, false); - mScreenMetrics = res.getInteger(R.integer.config_screen_metrics); + mScreenMetrics = Settings.readScreenMetrics(res); mShouldShowLxxSuggestionUi = Settings.SHOULD_SHOW_LXX_SUGGESTION_UI && prefs.getBoolean(DebugSettings.PREF_SHOULD_SHOW_LXX_SUGGESTION_UI, true); @@ -166,6 +166,8 @@ public class SettingsValues { mKeypressVibrationDuration = Settings.readKeypressVibrationDuration(prefs, res); mKeypressSoundVolume = Settings.readKeypressSoundVolume(prefs, res); mKeyPreviewPopupDismissDelay = Settings.readKeyPreviewPopupDismissDelay(prefs, res); + mEnableEmojiAltPhysicalKey = prefs.getBoolean( + Settings.PREF_ENABLE_EMOJI_ALT_PHYSICAL_KEY, true); mAutoCorrectionThreshold = readAutoCorrectionThreshold(res, autoCorrectionThresholdRawValue); mGestureInputEnabled = Settings.readGestureInputEnabled(prefs, res); @@ -221,11 +223,6 @@ public class SettingsValues { return mEnableMetricsLogging; } - public boolean isTablet() { - return mScreenMetrics == Constants.SCREEN_METRICS_SMALL_TABLET - || mScreenMetrics == Constants.SCREEN_METRICS_LARGE_TABLET; - } - public boolean isApplicationSpecifiedCompletionsOn() { return mInputAttributes.mApplicationSpecifiedCompletionOn; } diff --git a/java/src/com/android/inputmethod/latin/settings/SpacingAndPunctuations.java b/java/src/com/android/inputmethod/latin/settings/SpacingAndPunctuations.java index 46aef89c4..70d97a5ba 100644 --- a/java/src/com/android/inputmethod/latin/settings/SpacingAndPunctuations.java +++ b/java/src/com/android/inputmethod/latin/settings/SpacingAndPunctuations.java @@ -23,7 +23,7 @@ import com.android.inputmethod.keyboard.internal.MoreKeySpec; import com.android.inputmethod.latin.PunctuationSuggestions; import com.android.inputmethod.latin.R; import com.android.inputmethod.latin.common.Constants; -import com.android.inputmethod.latin.utils.StringUtils; +import com.android.inputmethod.latin.common.StringUtils; import java.util.Arrays; import java.util.Locale; diff --git a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerSession.java b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerSession.java index ac395bf02..2c690aea7 100644 --- a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerSession.java +++ b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerSession.java @@ -28,7 +28,7 @@ import android.view.textservice.TextInfo; import com.android.inputmethod.compat.TextInfoCompatUtils; import com.android.inputmethod.latin.NgramContext; -import com.android.inputmethod.latin.utils.StringUtils; +import com.android.inputmethod.latin.utils.SpannableStringUtils; import java.util.ArrayList; import java.util.Locale; @@ -71,9 +71,10 @@ public final class AndroidSpellCheckerSession extends AndroidWordLevelSpellCheck if (!subText.toString().contains(AndroidSpellCheckerService.SINGLE_QUOTE)) { continue; } - final CharSequence[] splitTexts = StringUtils.split(subText, + // Split preserving spans. + final CharSequence[] splitTexts = SpannableStringUtils.split(subText, AndroidSpellCheckerService.SINGLE_QUOTE, - true /* preserveTrailingEmptySegments */ ); + true /* preserveTrailingEmptySegments */); if (splitTexts == null || splitTexts.length <= 1) { continue; } diff --git a/java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java b/java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java index 514bfca85..3ad8fb910 100644 --- a/java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java +++ b/java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java @@ -34,11 +34,11 @@ import com.android.inputmethod.latin.NgramContext; import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; import com.android.inputmethod.latin.WordComposer; import com.android.inputmethod.latin.common.Constants; +import com.android.inputmethod.latin.common.StringUtils; import com.android.inputmethod.latin.utils.BinaryDictionaryUtils; import com.android.inputmethod.latin.utils.CoordinateUtils; import com.android.inputmethod.latin.utils.LocaleUtils; import com.android.inputmethod.latin.utils.ScriptUtils; -import com.android.inputmethod.latin.utils.StringUtils; import com.android.inputmethod.latin.utils.SuggestionResults; import java.util.ArrayList; diff --git a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java index b18fcc744..b71bd1f50 100644 --- a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java +++ b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java @@ -344,12 +344,6 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick if (mSuggestedWords.size() <= mStartIndexOfMoreSuggestions) { return false; } - // Dismiss another {@link MoreKeysPanel} that may be being showed, for example - // {@link MoreKeysKeyboardView}. - mMainKeyboardView.onDismissMoreKeysPanel(); - // Dismiss all key previews and sliding key input preview that may be being showed. - mMainKeyboardView.dismissAllKeyPreviews(); - mMainKeyboardView.dismissSlidingKeyInputPreview(); final int stripWidth = getWidth(); final View container = mMoreSuggestionsContainer; final int maxWidth = stripWidth - container.getPaddingLeft() - container.getPaddingRight(); diff --git a/java/src/com/android/inputmethod/latin/utils/AdditionalSubtypeUtils.java b/java/src/com/android/inputmethod/latin/utils/AdditionalSubtypeUtils.java index 02ace6a1e..2aac7c57a 100644 --- a/java/src/com/android/inputmethod/latin/utils/AdditionalSubtypeUtils.java +++ b/java/src/com/android/inputmethod/latin/utils/AdditionalSubtypeUtils.java @@ -31,6 +31,7 @@ import android.view.inputmethod.InputMethodSubtype; import com.android.inputmethod.annotations.UsedForTesting; import com.android.inputmethod.compat.InputMethodSubtypeCompatUtils; import com.android.inputmethod.latin.R; +import com.android.inputmethod.latin.common.StringUtils; import java.util.ArrayList; import java.util.Arrays; diff --git a/java/src/com/android/inputmethod/latin/utils/BinaryDictionaryUtils.java b/java/src/com/android/inputmethod/latin/utils/BinaryDictionaryUtils.java index ce25fe6a4..23ffde2a2 100644 --- a/java/src/com/android/inputmethod/latin/utils/BinaryDictionaryUtils.java +++ b/java/src/com/android/inputmethod/latin/utils/BinaryDictionaryUtils.java @@ -18,6 +18,7 @@ package com.android.inputmethod.latin.utils; import com.android.inputmethod.annotations.UsedForTesting; import com.android.inputmethod.latin.BinaryDictionary; +import com.android.inputmethod.latin.common.StringUtils; import com.android.inputmethod.latin.makedict.DictionaryHeader; import com.android.inputmethod.latin.makedict.UnsupportedFormatException; import com.android.inputmethod.latin.personalization.PersonalizationHelper; diff --git a/java/src/com/android/inputmethod/latin/utils/CapsModeUtils.java b/java/src/com/android/inputmethod/latin/utils/CapsModeUtils.java index b087e9ee8..0db63fd9f 100644 --- a/java/src/com/android/inputmethod/latin/utils/CapsModeUtils.java +++ b/java/src/com/android/inputmethod/latin/utils/CapsModeUtils.java @@ -21,6 +21,7 @@ import android.text.TextUtils; import com.android.inputmethod.latin.WordComposer; import com.android.inputmethod.latin.common.Constants; +import com.android.inputmethod.latin.common.StringUtils; import com.android.inputmethod.latin.settings.SpacingAndPunctuations; import java.util.Locale; diff --git a/java/src/com/android/inputmethod/latin/utils/CollectionUtils.java b/java/src/com/android/inputmethod/latin/utils/CollectionUtils.java index d0df72479..f9839eb91 100644 --- a/java/src/com/android/inputmethod/latin/utils/CollectionUtils.java +++ b/java/src/com/android/inputmethod/latin/utils/CollectionUtils.java @@ -19,15 +19,17 @@ package com.android.inputmethod.latin.utils; import java.util.ArrayList; import java.util.Collection; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + public final class CollectionUtils { private CollectionUtils() { // This utility class is not publicly instantiable. } - public static <E> ArrayList<E> arrayAsList(final E[] array, final int start, final int end) { - if (array == null) { - throw new NullPointerException(); - } + @Nonnull + public static <E> ArrayList<E> arrayAsList(@Nonnull final E[] array, final int start, + final int end) { if (start < 0 || start > end || end > array.length) { throw new IllegalArgumentException(); } @@ -44,7 +46,7 @@ public final class CollectionUtils { * @param c Collection to test. * @return Whether c contains no elements. */ - public static boolean isNullOrEmpty(final Collection<?> c) { + public static boolean isNullOrEmpty(@Nullable final Collection<?> c) { return c == null || c.isEmpty(); } } diff --git a/java/src/com/android/inputmethod/latin/utils/CoordinateUtils.java b/java/src/com/android/inputmethod/latin/utils/CoordinateUtils.java index 87df013a6..3a9705904 100644 --- a/java/src/com/android/inputmethod/latin/utils/CoordinateUtils.java +++ b/java/src/com/android/inputmethod/latin/utils/CoordinateUtils.java @@ -16,7 +16,7 @@ package com.android.inputmethod.latin.utils; -import java.util.Arrays; +import javax.annotation.Nonnull; public final class CoordinateUtils { private static final int INDEX_X = 0; @@ -27,32 +27,35 @@ public final class CoordinateUtils { // This utility class is not publicly instantiable. } + @Nonnull public static int[] newInstance() { return new int[ELEMENT_SIZE]; } - public static int x(final int[] coords) { + public static int x(@Nonnull final int[] coords) { return coords[INDEX_X]; } - public static int y(final int[] coords) { + public static int y(@Nonnull final int[] coords) { return coords[INDEX_Y]; } - public static void set(final int[] coords, final int x, final int y) { + public static void set(@Nonnull final int[] coords, final int x, final int y) { coords[INDEX_X] = x; coords[INDEX_Y] = y; } - public static void copy(final int[] destination, final int[] source) { + public static void copy(@Nonnull final int[] destination, @Nonnull final int[] source) { destination[INDEX_X] = source[INDEX_X]; destination[INDEX_Y] = source[INDEX_Y]; } + @Nonnull public static int[] newCoordinateArray(final int arraySize) { return new int[ELEMENT_SIZE * arraySize]; } + @Nonnull public static int[] newCoordinateArray(final int arraySize, final int defaultX, final int defaultY) { final int[] result = new int[ELEMENT_SIZE * arraySize]; @@ -62,30 +65,30 @@ public final class CoordinateUtils { return result; } - public static int xFromArray(final int[] coordsArray, final int index) { + public static int xFromArray(@Nonnull final int[] coordsArray, final int index) { return coordsArray[ELEMENT_SIZE * index + INDEX_X]; } - public static int yFromArray(final int[] coordsArray, final int index) { + public static int yFromArray(@Nonnull final int[] coordsArray, final int index) { return coordsArray[ELEMENT_SIZE * index + INDEX_Y]; } - public static int[] coordinateFromArray(final int[] coordsArray, final int index) { - final int baseIndex = ELEMENT_SIZE * index; - return Arrays.copyOfRange(coordsArray, baseIndex, baseIndex + ELEMENT_SIZE); + @Nonnull + public static int[] coordinateFromArray(@Nonnull final int[] coordsArray, final int index) { + final int[] coords = newInstance(); + set(coords, xFromArray(coordsArray, index), yFromArray(coordsArray, index)); + return coords; } - public static void setXYInArray(final int[] coordsArray, final int index, + public static void setXYInArray(@Nonnull final int[] coordsArray, final int index, final int x, final int y) { final int baseIndex = ELEMENT_SIZE * index; coordsArray[baseIndex + INDEX_X] = x; coordsArray[baseIndex + INDEX_Y] = y; } - public static void setCoordinateInArray(final int[] coordsArray, final int index, - final int[] coords) { - final int baseIndex = ELEMENT_SIZE * index; - coordsArray[baseIndex + INDEX_X] = coords[INDEX_X]; - coordsArray[baseIndex + INDEX_Y] = coords[INDEX_Y]; + public static void setCoordinateInArray(@Nonnull final int[] coordsArray, final int index, + @Nonnull final int[] coords) { + setXYInArray(coordsArray, index, x(coords), y(coords)); } } diff --git a/java/src/com/android/inputmethod/latin/utils/DistracterFilterCheckingExactMatchesAndSuggestions.java b/java/src/com/android/inputmethod/latin/utils/DistracterFilterCheckingExactMatchesAndSuggestions.java index 8f0f9bb44..56c8249bd 100644 --- a/java/src/com/android/inputmethod/latin/utils/DistracterFilterCheckingExactMatchesAndSuggestions.java +++ b/java/src/com/android/inputmethod/latin/utils/DistracterFilterCheckingExactMatchesAndSuggestions.java @@ -40,6 +40,7 @@ import com.android.inputmethod.latin.NgramContext; import com.android.inputmethod.latin.RichInputMethodSubtype; import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; import com.android.inputmethod.latin.WordComposer; +import com.android.inputmethod.latin.common.StringUtils; import com.android.inputmethod.latin.settings.SettingsValuesForSuggestion; /** diff --git a/java/src/com/android/inputmethod/latin/utils/RecapitalizeStatus.java b/java/src/com/android/inputmethod/latin/utils/RecapitalizeStatus.java index e3cac97f0..21daddce7 100644 --- a/java/src/com/android/inputmethod/latin/utils/RecapitalizeStatus.java +++ b/java/src/com/android/inputmethod/latin/utils/RecapitalizeStatus.java @@ -16,6 +16,8 @@ package com.android.inputmethod.latin.utils; +import com.android.inputmethod.latin.common.StringUtils; + import java.util.Locale; /** diff --git a/java/src/com/android/inputmethod/latin/utils/SpannableStringUtils.java b/java/src/com/android/inputmethod/latin/utils/SpannableStringUtils.java index cea1d1d58..c41817fe6 100644 --- a/java/src/com/android/inputmethod/latin/utils/SpannableStringUtils.java +++ b/java/src/com/android/inputmethod/latin/utils/SpannableStringUtils.java @@ -24,6 +24,12 @@ import android.text.TextUtils; import android.text.style.SuggestionSpan; import android.text.style.URLSpan; +import com.android.inputmethod.annotations.UsedForTesting; + +import java.util.ArrayList; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + public final class SpannableStringUtils { /** * Copies the spans from the region <code>start...end</code> in @@ -125,4 +131,53 @@ public final class SpannableStringUtils { final URLSpan[] spans = spanned.getSpans(startIndex - 1, endIndex + 1, URLSpan.class); return null != spans && spans.length > 0; } + + /** + * Splits the given {@code charSequence} with at occurrences of the given {@code regex}. + * <p> + * This is equivalent to + * {@code charSequence.toString().split(regex, preserveTrailingEmptySegments ? -1 : 0)} + * except that the spans are preserved in the result array. + * </p> + * @param charSequence the character sequence to be split. + * @param regex the regex pattern to be used as the separator. + * @param preserveTrailingEmptySegments {@code true} to preserve the trailing empty + * segments. Otherwise, trailing empty segments will be removed before being returned. + * @return the array which contains the result. All the spans in the <code>charSequence</code> + * is preserved. + */ + @UsedForTesting + public static CharSequence[] split(final CharSequence charSequence, final String regex, + final boolean preserveTrailingEmptySegments) { + // A short-cut for non-spanned strings. + if (!(charSequence instanceof Spanned)) { + // -1 means that trailing empty segments will be preserved. + return charSequence.toString().split(regex, preserveTrailingEmptySegments ? -1 : 0); + } + + // Hereafter, emulate String.split for CharSequence. + final ArrayList<CharSequence> sequences = new ArrayList<>(); + final Matcher matcher = Pattern.compile(regex).matcher(charSequence); + int nextStart = 0; + boolean matched = false; + while (matcher.find()) { + sequences.add(charSequence.subSequence(nextStart, matcher.start())); + nextStart = matcher.end(); + matched = true; + } + if (!matched) { + // never matched. preserveTrailingEmptySegments is ignored in this case. + return new CharSequence[] { charSequence }; + } + sequences.add(charSequence.subSequence(nextStart, charSequence.length())); + if (!preserveTrailingEmptySegments) { + for (int i = sequences.size() - 1; i >= 0; --i) { + if (!TextUtils.isEmpty(sequences.get(i))) { + break; + } + sequences.remove(i); + } + } + return sequences.toArray(new CharSequence[sequences.size()]); + } } diff --git a/java/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtils.java b/java/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtils.java index eb85c1baf..55c1dc9e5 100644 --- a/java/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtils.java +++ b/java/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtils.java @@ -28,10 +28,10 @@ import android.view.inputmethod.InputMethodSubtype; import com.android.inputmethod.latin.R; import com.android.inputmethod.latin.RichInputMethodSubtype; +import com.android.inputmethod.latin.common.StringUtils; import java.util.Arrays; import java.util.HashMap; -import java.util.HashSet; import java.util.Locale; /** @@ -59,7 +59,8 @@ public final class SubtypeLocaleUtils { // Keyboard layout to subtype name resource id map. private static final HashMap<String, Integer> sKeyboardLayoutToNameIdsMap = new HashMap<>(); // Exceptional locale whose name should be displayed in Locale.ROOT. - static final HashSet<String> sExceptionalLocaleDisplayedInRootLocale = new HashSet<>(); + private static final HashMap<String, Integer> sExceptionalLocaleDisplayedInRootLocale = + new HashMap<>(); // Exceptional locale to subtype name resource id map. private static final HashMap<String, Integer> sExceptionalLocaleToNameIdsMap = new HashMap<>(); // Exceptional locale to subtype name with layout resource id map. @@ -73,6 +74,8 @@ public final class SubtypeLocaleUtils { "string/subtype_with_layout_"; private static final String SUBTYPE_NAME_RESOURCE_NO_LANGUAGE_PREFIX = "string/subtype_no_language_"; + private static final String SUBTYPE_NAME_RESOURCE_IN_ROOT_LOCALE_PREFIX = + "string/subtype_in_root_locale_"; // Keyboard layout set name for the subtypes that don't have a keyboardLayoutSet extra value. // This is for compatibility to keep the same subtype ids as pre-JellyBean. private static final HashMap<String, String> sLocaleAndExtraValueToKeyboardLayoutSetMap = @@ -117,7 +120,10 @@ public final class SubtypeLocaleUtils { final String[] exceptionalLocaleInRootLocale = res.getStringArray( R.array.subtype_locale_displayed_in_root_locale); for (int i = 0; i < exceptionalLocaleInRootLocale.length; i++) { - sExceptionalLocaleDisplayedInRootLocale.add(exceptionalLocaleInRootLocale[i]); + final String localeString = exceptionalLocaleInRootLocale[i]; + final String resourceName = SUBTYPE_NAME_RESOURCE_IN_ROOT_LOCALE_PREFIX + localeString; + final int resId = res.getIdentifier(resourceName, null, RESOURCE_PACKAGE_NAME); + sExceptionalLocaleDisplayedInRootLocale.put(localeString, resId); } final String[] exceptionalLocales = res.getStringArray( @@ -171,7 +177,7 @@ public final class SubtypeLocaleUtils { if (NO_LANGUAGE.equals(localeString)) { return sResources.getConfiguration().locale; } - if (sExceptionalLocaleDisplayedInRootLocale.contains(localeString)) { + if (sExceptionalLocaleDisplayedInRootLocale.containsKey(localeString)) { return Locale.ROOT; } return LocaleUtils.constructLocaleFromString(localeString); @@ -190,7 +196,7 @@ public final class SubtypeLocaleUtils { public static String getSubtypeLanguageDisplayName(final String localeString) { final Locale displayLocale = getDisplayLocaleOfSubtypeLocale(localeString); final String languageString; - if (sExceptionalLocaleDisplayedInRootLocale.contains(localeString)) { + if (sExceptionalLocaleDisplayedInRootLocale.containsKey(localeString)) { languageString = localeString; } else { final Locale locale = LocaleUtils.constructLocaleFromString(localeString); @@ -205,7 +211,16 @@ public final class SubtypeLocaleUtils { // No language subtype should be displayed in system locale. return sResources.getString(R.string.subtype_no_language); } - final Integer exceptionalNameResId = sExceptionalLocaleToNameIdsMap.get(localeString); + final Integer exceptionalNameResId; + if (displayLocale.equals(Locale.ROOT) + && sExceptionalLocaleDisplayedInRootLocale.containsKey(localeString)) { + exceptionalNameResId = sExceptionalLocaleDisplayedInRootLocale.get(localeString); + } else if (sExceptionalLocaleToNameIdsMap.containsKey(localeString)) { + exceptionalNameResId = sExceptionalLocaleToNameIdsMap.get(localeString); + } else { + exceptionalNameResId = null; + } + final String displayName; if (exceptionalNameResId != null) { final RunInLocale<String> getExceptionalName = new RunInLocale<String>() { diff --git a/java/src/com/android/inputmethod/latin/utils/WordInputEventForPersonalization.java b/java/src/com/android/inputmethod/latin/utils/WordInputEventForPersonalization.java index d3fa0c748..86a5b19ec 100644 --- a/java/src/com/android/inputmethod/latin/utils/WordInputEventForPersonalization.java +++ b/java/src/com/android/inputmethod/latin/utils/WordInputEventForPersonalization.java @@ -21,6 +21,7 @@ import android.util.Log; import com.android.inputmethod.annotations.UsedForTesting; import com.android.inputmethod.latin.NgramContext; import com.android.inputmethod.latin.common.Constants; +import com.android.inputmethod.latin.common.StringUtils; import com.android.inputmethod.latin.settings.SpacingAndPunctuations; import com.android.inputmethod.latin.utils.DistracterFilter.HandlingType; diff --git a/native/jni/src/suggest/core/policy/weighting.cpp b/native/jni/src/suggest/core/policy/weighting.cpp index a06e7d070..450203d98 100644 --- a/native/jni/src/suggest/core/policy/weighting.cpp +++ b/native/jni/src/suggest/core/policy/weighting.cpp @@ -119,7 +119,7 @@ static inline void profile(const CorrectionType correctionType, DicNode *const n return weighting->getSubstitutionCost() + weighting->getMatchedCost(traverseSession, dicNode, inputStateG); case CT_NEW_WORD_SPACE_OMISSION: - return weighting->getNewWordSpatialCost(traverseSession, dicNode, inputStateG); + return weighting->getSpaceOmissionCost(traverseSession, dicNode, inputStateG); case CT_MATCH: return weighting->getMatchedCost(traverseSession, dicNode, inputStateG); case CT_COMPLETION: diff --git a/native/jni/src/suggest/core/policy/weighting.h b/native/jni/src/suggest/core/policy/weighting.h index bd6b3cf41..863c4eabe 100644 --- a/native/jni/src/suggest/core/policy/weighting.h +++ b/native/jni/src/suggest/core/policy/weighting.h @@ -57,7 +57,7 @@ class Weighting { const DicTraverseSession *const traverseSession, const DicNode *const parentDicNode, const DicNode *const dicNode) const = 0; - virtual float getNewWordSpatialCost(const DicTraverseSession *const traverseSession, + virtual float getSpaceOmissionCost(const DicTraverseSession *const traverseSession, const DicNode *const dicNode, DicNode_InputStateG *const inputStateG) const = 0; virtual float getNewWordBigramLanguageCost( diff --git a/native/jni/src/suggest/core/suggest.cpp b/native/jni/src/suggest/core/suggest.cpp index c71526293..68a36454e 100644 --- a/native/jni/src/suggest/core/suggest.cpp +++ b/native/jni/src/suggest/core/suggest.cpp @@ -160,8 +160,7 @@ void Suggest::expandCurrentDicNodes(DicTraverseSession *traverseSession) const { // TODO: Remove. Do not prune node here. const bool allowsErrorCorrections = TRAVERSAL->allowsErrorCorrections(&dicNode); // Process for handling space substitution (e.g., hevis => he is) - if (allowsErrorCorrections - && TRAVERSAL->isSpaceSubstitutionTerminal(traverseSession, &dicNode)) { + if (TRAVERSAL->isSpaceSubstitutionTerminal(traverseSession, &dicNode)) { createNextWordDicNode(traverseSession, &dicNode, true /* spaceSubstitution */); } diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_policy.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_policy.cpp index 249d822b2..d3de322f9 100644 --- a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_policy.cpp +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_policy.cpp @@ -97,6 +97,9 @@ int Ver4PatriciaTriePolicy::getWordId(const CodePointArrayView wordCodePoints, return NOT_A_WORD_ID; } const PtNodeParams ptNodeParams = mNodeReader.fetchPtNodeParamsInBufferFromPtNodePos(ptNodePos); + if (ptNodeParams.isDeleted()) { + return NOT_A_WORD_ID; + } return ptNodeParams.getTerminalId(); } diff --git a/native/jni/src/suggest/policyimpl/typing/scoring_params.cpp b/native/jni/src/suggest/policyimpl/typing/scoring_params.cpp index 6a2db687d..a6f9a8b23 100644 --- a/native/jni/src/suggest/policyimpl/typing/scoring_params.cpp +++ b/native/jni/src/suggest/policyimpl/typing/scoring_params.cpp @@ -48,17 +48,17 @@ const float ScoringParams::INSERTION_COST_SAME_CHAR = 0.5508f; const float ScoringParams::INSERTION_COST_PROXIMITY_CHAR = 0.674f; const float ScoringParams::INSERTION_COST_FIRST_CHAR = 0.639f; const float ScoringParams::TRANSPOSITION_COST = 0.5608f; -const float ScoringParams::SPACE_SUBSTITUTION_COST = 0.334f; +const float ScoringParams::SPACE_SUBSTITUTION_COST = 0.33f; +const float ScoringParams::SPACE_OMISSION_COST = 0.1f; const float ScoringParams::ADDITIONAL_PROXIMITY_COST = 0.37972f; const float ScoringParams::SUBSTITUTION_COST = 0.3806f; -const float ScoringParams::COST_NEW_WORD = 0.0314f; const float ScoringParams::COST_SECOND_OR_LATER_WORD_FIRST_CHAR_UPPERCASE = 0.3224f; const float ScoringParams::DISTANCE_WEIGHT_LANGUAGE = 1.1214f; const float ScoringParams::COST_FIRST_COMPLETION = 0.4836f; const float ScoringParams::COST_COMPLETION = 0.00624f; const float ScoringParams::HAS_PROXIMITY_TERMINAL_COST = 0.0683f; const float ScoringParams::HAS_EDIT_CORRECTION_TERMINAL_COST = 0.0362f; -const float ScoringParams::HAS_MULTI_WORD_TERMINAL_COST = 0.4182f; +const float ScoringParams::HAS_MULTI_WORD_TERMINAL_COST = 0.3482f; const float ScoringParams::TYPING_BASE_OUTPUT_SCORE = 1.0f; const float ScoringParams::TYPING_MAX_OUTPUT_SCORE_PER_INPUT = 0.1f; const float ScoringParams::NORMALIZED_SPATIAL_DISTANCE_THRESHOLD_FOR_EDIT = 0.095f; diff --git a/native/jni/src/suggest/policyimpl/typing/scoring_params.h b/native/jni/src/suggest/policyimpl/typing/scoring_params.h index 731424f3d..b8f889559 100644 --- a/native/jni/src/suggest/policyimpl/typing/scoring_params.h +++ b/native/jni/src/suggest/policyimpl/typing/scoring_params.h @@ -56,9 +56,9 @@ class ScoringParams { static const float INSERTION_COST_FIRST_CHAR; static const float TRANSPOSITION_COST; static const float SPACE_SUBSTITUTION_COST; + static const float SPACE_OMISSION_COST; static const float ADDITIONAL_PROXIMITY_COST; static const float SUBSTITUTION_COST; - static const float COST_NEW_WORD; static const float COST_SECOND_OR_LATER_WORD_FIRST_CHAR_UPPERCASE; static const float DISTANCE_WEIGHT_LANGUAGE; static const float COST_FIRST_COMPLETION; diff --git a/native/jni/src/suggest/policyimpl/typing/typing_weighting.h b/native/jni/src/suggest/policyimpl/typing/typing_weighting.h index 84077174d..1338ac81a 100644 --- a/native/jni/src/suggest/policyimpl/typing/typing_weighting.h +++ b/native/jni/src/suggest/policyimpl/typing/typing_weighting.h @@ -150,9 +150,10 @@ class TypingWeighting : public Weighting { return cost + weightedDistance; } - float getNewWordSpatialCost(const DicTraverseSession *const traverseSession, + float getSpaceOmissionCost(const DicTraverseSession *const traverseSession, const DicNode *const dicNode, DicNode_InputStateG *inputStateG) const { - return ScoringParams::COST_NEW_WORD * traverseSession->getMultiWordCostMultiplier(); + const float cost = ScoringParams::SPACE_OMISSION_COST; + return cost * traverseSession->getMultiWordCostMultiplier(); } float getNewWordBigramLanguageCost(const DicTraverseSession *const traverseSession, @@ -202,7 +203,10 @@ class TypingWeighting : public Weighting { AK_FORCE_INLINE float getSpaceSubstitutionCost(const DicTraverseSession *const traverseSession, const DicNode *const dicNode) const { - const float cost = ScoringParams::SPACE_SUBSTITUTION_COST + ScoringParams::COST_NEW_WORD; + const int inputIndex = dicNode->getInputIndex(0); + const float distanceToSpaceKey = traverseSession->getProximityInfoState(0) + ->getPointToKeyLength(inputIndex, KEYCODE_SPACE); + const float cost = ScoringParams::SPACE_SUBSTITUTION_COST * distanceToSpaceKey; return cost * traverseSession->getMultiWordCostMultiplier(); } diff --git a/tests/src/com/android/inputmethod/keyboard/KeyboardLayoutSetTestsBase.java b/tests/src/com/android/inputmethod/keyboard/KeyboardLayoutSetTestsBase.java index ec836ccca..0246c49a1 100644 --- a/tests/src/com/android/inputmethod/keyboard/KeyboardLayoutSetTestsBase.java +++ b/tests/src/com/android/inputmethod/keyboard/KeyboardLayoutSetTestsBase.java @@ -17,9 +17,7 @@ package com.android.inputmethod.keyboard; import android.content.Context; -import android.content.SharedPreferences; import android.content.res.Resources; -import android.preference.PreferenceManager; import android.test.AndroidTestCase; import android.view.ContextThemeWrapper; import android.view.inputmethod.EditorInfo; @@ -62,8 +60,8 @@ public abstract class KeyboardLayoutSetTestsBase extends AndroidTestCase { } }; - private SharedPreferences mSharedPreferences; - private String mSavedAdditionalSubtypes; + private RichInputMethodManager mRichImm; + private InputMethodSubtype[] mSavedAdditionalSubtypes; private int mScreenMetrics; protected abstract int getKeyboardThemeForTests(); @@ -72,26 +70,26 @@ public abstract class KeyboardLayoutSetTestsBase extends AndroidTestCase { protected void setUp() throws Exception { super.setUp(); final Context context = getContext(); - mSharedPreferences = PreferenceManager.getDefaultSharedPreferences(context); final Resources res = context.getResources(); + RichInputMethodManager.init(context); + mRichImm = RichInputMethodManager.getInstance(); - // Save additional subtypes preference. - mSavedAdditionalSubtypes = Settings.readPrefAdditionalSubtypes(mSharedPreferences, res); - final String predefinedSubtypes = AdditionalSubtypeUtils.createPrefSubtypes( - res.getStringArray(R.array.predefined_subtypes)); - // Reset additional subtypes to predefined ones. - Settings.writePrefAdditionalSubtypes(mSharedPreferences, predefinedSubtypes); + // Save and reset additional subtypes preference. + mSavedAdditionalSubtypes = mRichImm.getAdditionalSubtypes(context); + final InputMethodSubtype[] predefinedAdditionalSubtypes = + AdditionalSubtypeUtils.createAdditionalSubtypesArray( + AdditionalSubtypeUtils.createPrefSubtypes( + res.getStringArray(R.array.predefined_subtypes))); + mRichImm.setAdditionalInputMethodSubtypes(predefinedAdditionalSubtypes); final KeyboardTheme keyboardTheme = KeyboardTheme.searchKeyboardThemeById( getKeyboardThemeForTests(), KeyboardTheme.KEYBOARD_THEMES); setContext(new ContextThemeWrapper(getContext(), keyboardTheme.mStyleId)); KeyboardLayoutSet.onKeyboardThemeChanged(); - mScreenMetrics = res.getInteger(R.integer.config_screen_metrics); - RichInputMethodManager.init(context); - final RichInputMethodManager richImm = RichInputMethodManager.getInstance(); + mScreenMetrics = Settings.readScreenMetrics(res); - final InputMethodInfo imi = richImm.getInputMethodInfoOfThisIme(); + final InputMethodInfo imi = mRichImm.getInputMethodInfoOfThisIme(); final int subtypeCount = imi.getSubtypeCount(); for (int index = 0; index < subtypeCount; index++) { mAllSubtypesList.add(imi.getSubtypeAt(index)); @@ -101,7 +99,7 @@ public abstract class KeyboardLayoutSetTestsBase extends AndroidTestCase { @Override protected void tearDown() throws Exception { // Restore additional subtypes preference. - Settings.writePrefAdditionalSubtypes(mSharedPreferences, mSavedAdditionalSubtypes); + mRichImm.setAdditionalInputMethodSubtypes(mSavedAdditionalSubtypes); super.tearDown(); } @@ -121,8 +119,7 @@ public abstract class KeyboardLayoutSetTestsBase extends AndroidTestCase { } protected final boolean isPhone() { - return mScreenMetrics == Constants.SCREEN_METRICS_SMALL_PHONE - || mScreenMetrics == Constants.SCREEN_METRICS_LARGE_PHONE; + return Constants.isPhone(mScreenMetrics); } protected final InputMethodSubtype getSubtype(final Locale locale, diff --git a/tests/src/com/android/inputmethod/keyboard/layout/expected/ActualKeyboardBuilder.java b/tests/src/com/android/inputmethod/keyboard/layout/expected/ActualKeyboardBuilder.java index a6aac3583..2a040f564 100644 --- a/tests/src/com/android/inputmethod/keyboard/layout/expected/ActualKeyboardBuilder.java +++ b/tests/src/com/android/inputmethod/keyboard/layout/expected/ActualKeyboardBuilder.java @@ -20,11 +20,14 @@ import com.android.inputmethod.keyboard.Key; import com.android.inputmethod.keyboard.internal.KeyboardIconsSet; import com.android.inputmethod.keyboard.internal.MoreKeySpec; import com.android.inputmethod.latin.common.Constants; -import com.android.inputmethod.latin.utils.StringUtils; +import com.android.inputmethod.latin.common.StringUtils; import java.util.ArrayList; import java.util.List; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + /** * This class builds an actual keyboard for unit test. * @@ -98,9 +101,13 @@ public final class ActualKeyboardBuilder extends AbstractKeyboardBuilder<Key> { @Override public String stringize(final MoreKeySpec spec) { + if (spec == null) { + return "null"; + } return toString(spec.mLabel, spec.mIconId, spec.mOutputText, spec.mCode); } + @Nonnull static String toString(final String label, final int iconId, final String outputText, final int code) { final String visual = (iconId != KeyboardIconsSet.ICON_UNDEFINED) @@ -125,7 +132,7 @@ public final class ActualKeyboardBuilder extends AbstractKeyboardBuilder<Key> { static final KeyStringizer STRINGIZER = new KeyStringizer(); @Override - public String stringize(final Key key) { + public String stringize(@Nullable final Key key) { if (key == null) { return "NULL"; } @@ -150,7 +157,8 @@ public final class ActualKeyboardBuilder extends AbstractKeyboardBuilder<Key> { * @param key the key to be converted to string. * @return the human readable representation of <code>key</code>. */ - public static String toString(final Key key) { + @Nonnull + public static String toString(@Nullable final Key key) { return KeyStringizer.STRINGIZER.stringize(key); } @@ -159,7 +167,8 @@ public final class ActualKeyboardBuilder extends AbstractKeyboardBuilder<Key> { * @param keys the keyboard row to be converted to string. * @return the human readable representation of <code>keys</code>. */ - public static String toString(final Key[] keys) { + @Nonnull + public static String toString(@Nullable final Key[] keys) { return KeyStringizer.STRINGIZER.join(keys); } @@ -168,7 +177,7 @@ public final class ActualKeyboardBuilder extends AbstractKeyboardBuilder<Key> { static final KeyArrayStringizer STRINGIZER = new KeyArrayStringizer(); @Override - public String stringize(final Key[] keyArray) { + public String stringize(@Nullable final Key[] keyArray) { return KeyStringizer.STRINGIZER.join(keyArray); } } @@ -178,7 +187,8 @@ public final class ActualKeyboardBuilder extends AbstractKeyboardBuilder<Key> { * @param rows the keyboard to be converted to string. * @return the human readable representation of <code>rows</code>. */ - public static String toString(final Key[][] rows) { + @Nonnull + public static String toString(@Nullable final Key[][] rows) { return KeyArrayStringizer.STRINGIZER.join(rows, "\n" /* delimiter */); } } diff --git a/tests/src/com/android/inputmethod/keyboard/layout/expected/ExpectedKeyOutput.java b/tests/src/com/android/inputmethod/keyboard/layout/expected/ExpectedKeyOutput.java index 0547ea31b..9bb5f187a 100644 --- a/tests/src/com/android/inputmethod/keyboard/layout/expected/ExpectedKeyOutput.java +++ b/tests/src/com/android/inputmethod/keyboard/layout/expected/ExpectedKeyOutput.java @@ -19,7 +19,7 @@ package com.android.inputmethod.keyboard.layout.expected; import com.android.inputmethod.keyboard.Key; import com.android.inputmethod.keyboard.internal.MoreKeySpec; import com.android.inputmethod.latin.common.Constants; -import com.android.inputmethod.latin.utils.StringUtils; +import com.android.inputmethod.latin.common.StringUtils; import java.util.Locale; diff --git a/tests/src/com/android/inputmethod/latin/BinaryDictionaryDecayingTests.java b/tests/src/com/android/inputmethod/latin/BinaryDictionaryDecayingTests.java index 47badc1f2..f90b266b6 100644 --- a/tests/src/com/android/inputmethod/latin/BinaryDictionaryDecayingTests.java +++ b/tests/src/com/android/inputmethod/latin/BinaryDictionaryDecayingTests.java @@ -746,7 +746,12 @@ public class BinaryDictionaryDecayingTests extends AndroidTestCase { assertTrue(binaryDictionary.isValidWord("aaa")); assertTrue(binaryDictionary.removeUnigramEntry("aaa")); assertFalse(binaryDictionary.isValidWord("aaa")); - + onInputWord(binaryDictionary, "aaa", false /* isValidWord */); + assertFalse(binaryDictionary.isValidWord("aaa")); + onInputWord(binaryDictionary, "aaa", false /* isValidWord */); + assertTrue(binaryDictionary.isValidWord("aaa")); + assertTrue(binaryDictionary.removeUnigramEntry("aaa")); + assertFalse(binaryDictionary.isValidWord("aaa")); binaryDictionary.close(); } diff --git a/tests/src/com/android/inputmethod/latin/InputLogicTests.java b/tests/src/com/android/inputmethod/latin/InputLogicTests.java index 7d356a4be..c76f6f446 100644 --- a/tests/src/com/android/inputmethod/latin/InputLogicTests.java +++ b/tests/src/com/android/inputmethod/latin/InputLogicTests.java @@ -674,10 +674,15 @@ public class InputLogicTests extends InputTestsBase { mEditText.getText().toString()); } - private void typeWordAndPutCursorInside(final String word, final int startPos) { + private void typeOrGestureWordAndPutCursorInside(final boolean gesture, final String word, + final int startPos) { final int END_OF_WORD = startPos + word.length(); final int NEW_CURSOR_POSITION = startPos + word.length() / 2; - type(word); + if (gesture) { + gesture(word); + } else { + type(word); + } sendUpdateForCursorMoveTo(END_OF_WORD); runMessages(); sendUpdateForCursorMoveTo(NEW_CURSOR_POSITION); @@ -687,6 +692,14 @@ public class InputLogicTests extends InputTestsBase { startPos, END_OF_WORD); } + private void typeWordAndPutCursorInside(final String word, final int startPos) { + typeOrGestureWordAndPutCursorInside(false /* gesture */, word, startPos); + } + + private void gestureWordAndPutCursorInside(final String word, final int startPos) { + typeOrGestureWordAndPutCursorInside(true /* gesture */, word, startPos); + } + private void ensureComposingSpanPos(final String message, final int from, final int to) { assertEquals(message, from, BaseInputConnection.getComposingSpanStart(mEditText.getText())); assertEquals(message, to, BaseInputConnection.getComposingSpanEnd(mEditText.getText())); @@ -703,6 +716,23 @@ public class InputLogicTests extends InputTestsBase { int cursorPos = sendUpdateForCursorMoveToEndOfLine(); runMessages(); type(" "); + assertEquals("mbo", "some thing ", mEditText.getText().toString()); + typeWordAndPutCursorInside(WORD_TO_TYPE, cursorPos + 1 /* startPos */); + type(Constants.CODE_DELETE); + ensureComposingSpanPos("space while in the middle of a word cancels composition", -1, -1); + } + + public void testTypeWithinGestureComposing() { + final String WORD_TO_TYPE = "something"; + final String EXPECTED_RESULT = "some thing"; + gestureWordAndPutCursorInside(WORD_TO_TYPE, 0 /* startPos */); + type(" "); + ensureComposingSpanPos("space while in the middle of a word cancels composition", -1, -1); + assertEquals("space in the middle of a composing word", EXPECTED_RESULT, + mEditText.getText().toString()); + int cursorPos = sendUpdateForCursorMoveToEndOfLine(); + runMessages(); + type(" "); typeWordAndPutCursorInside(WORD_TO_TYPE, cursorPos + 1 /* startPos */); type(Constants.CODE_DELETE); ensureComposingSpanPos("space while in the middle of a word cancels composition", -1, -1); diff --git a/tests/src/com/android/inputmethod/latin/InputTestsBase.java b/tests/src/com/android/inputmethod/latin/InputTestsBase.java index 78b4b18ec..926a2d3e1 100644 --- a/tests/src/com/android/inputmethod/latin/InputTestsBase.java +++ b/tests/src/com/android/inputmethod/latin/InputTestsBase.java @@ -43,10 +43,11 @@ import com.android.inputmethod.keyboard.Keyboard; import com.android.inputmethod.latin.Dictionary.PhonyDictionary; import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; import com.android.inputmethod.latin.common.Constants; +import com.android.inputmethod.latin.common.InputPointers; +import com.android.inputmethod.latin.common.StringUtils; import com.android.inputmethod.latin.settings.DebugSettings; import com.android.inputmethod.latin.settings.Settings; import com.android.inputmethod.latin.utils.LocaleUtils; -import com.android.inputmethod.latin.utils.StringUtils; import com.android.inputmethod.latin.utils.SubtypeLocaleUtils; import java.util.Locale; diff --git a/tests/src/com/android/inputmethod/latin/RichInputConnectionAndTextRangeTests.java b/tests/src/com/android/inputmethod/latin/RichInputConnectionAndTextRangeTests.java index 34c26004b..bcf016ae9 100644 --- a/tests/src/com/android/inputmethod/latin/RichInputConnectionAndTextRangeTests.java +++ b/tests/src/com/android/inputmethod/latin/RichInputConnectionAndTextRangeTests.java @@ -31,11 +31,11 @@ import android.view.inputmethod.InputConnection; import android.view.inputmethod.InputConnectionWrapper; import com.android.inputmethod.latin.common.Constants; +import com.android.inputmethod.latin.common.StringUtils; import com.android.inputmethod.latin.settings.SpacingAndPunctuations; import com.android.inputmethod.latin.utils.NgramContextUtils; import com.android.inputmethod.latin.utils.RunInLocale; import com.android.inputmethod.latin.utils.ScriptUtils; -import com.android.inputmethod.latin.utils.StringUtils; import com.android.inputmethod.latin.utils.TextRange; import java.util.Locale; diff --git a/tests/src/com/android/inputmethod/latin/WordComposerTests.java b/tests/src/com/android/inputmethod/latin/WordComposerTests.java index 8f5e8f7e5..20256e670 100644 --- a/tests/src/com/android/inputmethod/latin/WordComposerTests.java +++ b/tests/src/com/android/inputmethod/latin/WordComposerTests.java @@ -20,8 +20,8 @@ import android.test.AndroidTestCase; import android.test.suitebuilder.annotation.SmallTest; import com.android.inputmethod.latin.common.Constants; +import com.android.inputmethod.latin.common.StringUtils; import com.android.inputmethod.latin.utils.CoordinateUtils; -import com.android.inputmethod.latin.utils.StringUtils; /** * Unit tests for WordComposer. diff --git a/tests/src/com/android/inputmethod/latin/InputPointersTests.java b/tests/src/com/android/inputmethod/latin/common/InputPointersTests.java index 1a47cddf4..6b3490de8 100644 --- a/tests/src/com/android/inputmethod/latin/InputPointersTests.java +++ b/tests/src/com/android/inputmethod/latin/common/InputPointersTests.java @@ -14,13 +14,11 @@ * limitations under the License. */ -package com.android.inputmethod.latin; +package com.android.inputmethod.latin.common; import android.test.AndroidTestCase; import android.test.suitebuilder.annotation.SmallTest; -import com.android.inputmethod.latin.utils.ResizableIntArray; - import java.util.Arrays; @SmallTest diff --git a/tests/src/com/android/inputmethod/latin/utils/ResizableIntArrayTests.java b/tests/src/com/android/inputmethod/latin/common/ResizableIntArrayTests.java index 7519becbc..bd1629faf 100644 --- a/tests/src/com/android/inputmethod/latin/utils/ResizableIntArrayTests.java +++ b/tests/src/com/android/inputmethod/latin/common/ResizableIntArrayTests.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.inputmethod.latin.utils; +package com.android.inputmethod.latin.common; import android.test.AndroidTestCase; import android.test.suitebuilder.annotation.SmallTest; diff --git a/tests/src/com/android/inputmethod/latin/settings/SpacingAndPunctuationsTests.java b/tests/src/com/android/inputmethod/latin/settings/SpacingAndPunctuationsTests.java index f44673e0b..ed632db68 100644 --- a/tests/src/com/android/inputmethod/latin/settings/SpacingAndPunctuationsTests.java +++ b/tests/src/com/android/inputmethod/latin/settings/SpacingAndPunctuationsTests.java @@ -20,7 +20,6 @@ import android.content.res.Resources; import android.test.AndroidTestCase; import android.test.suitebuilder.annotation.SmallTest; -import com.android.inputmethod.latin.R; import com.android.inputmethod.latin.SuggestedWords; import com.android.inputmethod.latin.common.Constants; import com.android.inputmethod.latin.utils.RunInLocale; @@ -37,13 +36,11 @@ public class SpacingAndPunctuationsTests extends AndroidTestCase { private int mScreenMetrics; private boolean isPhone() { - return mScreenMetrics == Constants.SCREEN_METRICS_SMALL_PHONE - || mScreenMetrics == Constants.SCREEN_METRICS_LARGE_PHONE; + return Constants.isPhone(mScreenMetrics); } private boolean isTablet() { - return mScreenMetrics == Constants.SCREEN_METRICS_SMALL_TABLET - || mScreenMetrics == Constants.SCREEN_METRICS_LARGE_TABLET; + return Constants.isTablet(mScreenMetrics); } private SpacingAndPunctuations ENGLISH; @@ -70,7 +67,7 @@ public class SpacingAndPunctuationsTests extends AndroidTestCase { protected void setUp() throws Exception { super.setUp(); - mScreenMetrics = mContext.getResources().getInteger(R.integer.config_screen_metrics); + mScreenMetrics = Settings.readScreenMetrics(getContext().getResources()); // Language only ENGLISH = getSpacingAndPunctuations(Locale.ENGLISH); diff --git a/tests/src/com/android/inputmethod/latin/utils/CollectionUtilsTests.java b/tests/src/com/android/inputmethod/latin/utils/CollectionUtilsTests.java index 3feb60ec7..a5979c3df 100644 --- a/tests/src/com/android/inputmethod/latin/utils/CollectionUtilsTests.java +++ b/tests/src/com/android/inputmethod/latin/utils/CollectionUtilsTests.java @@ -51,5 +51,4 @@ public class CollectionUtilsTests extends AndroidTestCase { assertTrue(CollectionUtils.isNullOrEmpty(Collections.EMPTY_SET)); assertFalse(CollectionUtils.isNullOrEmpty(Collections.singleton("Not empty"))); } - } diff --git a/tests/src/com/android/inputmethod/latin/utils/SpacebarLanguageUtilsTests.java b/tests/src/com/android/inputmethod/latin/utils/SpacebarLanguageUtilsTests.java index e6131cf65..83afd782d 100644 --- a/tests/src/com/android/inputmethod/latin/utils/SpacebarLanguageUtilsTests.java +++ b/tests/src/com/android/inputmethod/latin/utils/SpacebarLanguageUtilsTests.java @@ -23,6 +23,7 @@ import android.test.suitebuilder.annotation.SmallTest; import android.view.inputmethod.InputMethodInfo; import android.view.inputmethod.InputMethodSubtype; +import com.android.inputmethod.latin.R; import com.android.inputmethod.latin.RichInputMethodManager; import com.android.inputmethod.latin.RichInputMethodSubtype; @@ -36,6 +37,7 @@ public class SpacebarLanguageUtilsTests extends AndroidTestCase { private RichInputMethodManager mRichImm; private Resources mRes; + private InputMethodSubtype mSavedAddtionalSubtypes[]; RichInputMethodSubtype EN_US; RichInputMethodSubtype EN_GB; @@ -45,6 +47,8 @@ public class SpacebarLanguageUtilsTests extends AndroidTestCase { RichInputMethodSubtype FR_CH; RichInputMethodSubtype DE; RichInputMethodSubtype DE_CH; + RichInputMethodSubtype HI; + RichInputMethodSubtype SR; RichInputMethodSubtype ZZ; RichInputMethodSubtype DE_QWERTY; RichInputMethodSubtype FR_QWERTZ; @@ -54,17 +58,27 @@ public class SpacebarLanguageUtilsTests extends AndroidTestCase { RichInputMethodSubtype ZZ_AZERTY; RichInputMethodSubtype ZZ_PC; - // This is a preliminary subtype and may not exist. - RichInputMethodSubtype HI_LATN; + // These are preliminary subtypes and may not exist. + RichInputMethodSubtype HI_LATN; // Hinglish + RichInputMethodSubtype SR_LATN; // Serbian Latin + RichInputMethodSubtype HI_LATN_DVORAK; + RichInputMethodSubtype SR_LATN_QWERTY; @Override protected void setUp() throws Exception { super.setUp(); final Context context = getContext(); + mRes = context.getResources(); RichInputMethodManager.init(context); mRichImm = RichInputMethodManager.getInstance(); - mRes = context.getResources(); - SubtypeLocaleUtils.init(context); + + // Save and reset additional subtypes + mSavedAddtionalSubtypes = mRichImm.getAdditionalSubtypes(context); + final InputMethodSubtype[] predefinedAddtionalSubtypes = + AdditionalSubtypeUtils.createAdditionalSubtypesArray( + AdditionalSubtypeUtils.createPrefSubtypes( + mRes.getStringArray(R.array.predefined_subtypes))); + mRichImm.setAdditionalInputMethodSubtypes(predefinedAddtionalSubtypes); final InputMethodInfo imi = mRichImm.getInputMethodInfoOfThisIme(); final int subtypeCount = imi.getSubtypeCount(); @@ -89,6 +103,10 @@ public class SpacebarLanguageUtilsTests extends AndroidTestCase { Locale.GERMAN.toString(), "qwertz")); DE_CH = new RichInputMethodSubtype(mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet( "de_CH", "swiss")); + HI = new RichInputMethodSubtype(mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet( + "hi", "hindi")); + SR = new RichInputMethodSubtype(mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet( + "sr", "south_slavic")); ZZ = new RichInputMethodSubtype(mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet( SubtypeLocaleUtils.NO_LANGUAGE, "qwerty")); DE_QWERTY = new RichInputMethodSubtype( @@ -117,9 +135,27 @@ public class SpacebarLanguageUtilsTests extends AndroidTestCase { "hi_ZZ", "qwerty"); if (hiLatn != null) { HI_LATN = new RichInputMethodSubtype(hiLatn); + HI_LATN_DVORAK = new RichInputMethodSubtype( + AdditionalSubtypeUtils.createAsciiEmojiCapableAdditionalSubtype( + "hi_ZZ", "dvorak")); + } + final InputMethodSubtype srLatn = mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet( + "sr_ZZ", "serbian_qwertz"); + if (srLatn != null) { + SR_LATN = new RichInputMethodSubtype(srLatn); + SR_LATN_QWERTY = new RichInputMethodSubtype( + AdditionalSubtypeUtils.createAsciiEmojiCapableAdditionalSubtype( + "sr_ZZ", "qwerty")); } } + @Override + protected void tearDown() throws Exception { + // Restore additional subtypes. + mRichImm.setAdditionalInputMethodSubtypes(mSavedAddtionalSubtypes); + super.tearDown(); + } + public void testAllFullDisplayNameForSpacebar() { for (final RichInputMethodSubtype subtype : mSubtypesList) { final String subtypeName = SubtypeLocaleUtils @@ -150,10 +186,11 @@ public class SpacebarLanguageUtilsTests extends AndroidTestCase { continue; } final Locale locale = locales[0]; - if (SubtypeLocaleUtils.sExceptionalLocaleDisplayedInRootLocale.contains( - locale.toString())) { + final Locale displayLocale = SubtypeLocaleUtils.getDisplayLocaleOfSubtypeLocale( + locale.toString()); + if (Locale.ROOT.equals(displayLocale)) { // Skip test because the language part of this locale string doesn't represent - // the locale to be displayed on the spacebar (for example hi_ZZ and Hinglish). + // the locale to be displayed on the spacebar (for example Hinglish). continue; } final String spacebarText = subtype.getMiddleDisplayName(); @@ -162,30 +199,36 @@ public class SpacebarLanguageUtilsTests extends AndroidTestCase { subtype.getRawSubtype()), spacebarText); } else { assertEquals(subtypeName, - SubtypeLocaleUtils.getSubtypeLocaleDisplayName(locale.getLanguage()), + SubtypeLocaleUtils.getSubtypeLanguageDisplayName(locale.toString()), spacebarText); } } } // InputMethodSubtype's display name for spacebar text in its locale. - // isAdditionalSubtype (T=true, F=false) - // locale layout | Middle Full - // ------ ------- - --------- ---------------------- - // en_US qwerty F English English (US) exception - // en_GB qwerty F English English (UK) exception - // es_US spanish F Español Español (EE.UU.) exception - // fr azerty F Français Français - // fr_CA qwerty F Français Français (Canada) - // fr_CH swiss F Français Français (Suisse) - // de qwertz F Deutsch Deutsch - // de_CH swiss F Deutsch Deutsch (Schweiz) - // hi_ZZ qwerty F Hinglish Hinglish - // zz qwerty F QWERTY QWERTY - // fr qwertz T Français Français - // de qwerty T Deutsch Deutsch - // en_US azerty T English English (US) - // zz azerty T AZERTY AZERTY + // isAdditionalSubtype (T=true, F=false) + // locale layout | Middle Full + // ------ -------------- - --------- ---------------------- + // en_US qwerty F English English (US) exception + // en_GB qwerty F English English (UK) exception + // es_US spanish F Español Español (EE.UU.) exception + // fr azerty F Français Français + // fr_CA qwerty F Français Français (Canada) + // fr_CH swiss F Français Français (Suisse) + // de qwertz F Deutsch Deutsch + // de_CH swiss F Deutsch Deutsch (Schweiz) + // hi hindi F हिन्दी हिन्दी + // hi_ZZ qwerty F Hinglish Hinglish exception + // sr south_slavic F Српски Српски + // sr_ZZ serbian_qwertz F Srpski Srpski exception + // zz qwerty F QWERTY QWERTY + // fr qwertz T Français Français + // de qwerty T Deutsch Deutsch + // en_US azerty T English English (US) + // en_GB dvorak T English English (UK) + // hi_ZZ dvorak T Hinglish Hinglish exception + // sr_ZZ qwerty T Srpski Srpski exception + // zz azerty T AZERTY AZERTY private final RunInLocale<Void> testsPredefinedSubtypesForSpacebar = new RunInLocale<Void>() { @Override @@ -198,11 +241,9 @@ public class SpacebarLanguageUtilsTests extends AndroidTestCase { assertEquals("fr_CH", "Français (Suisse)", FR_CH.getFullDisplayName()); assertEquals("de", "Deutsch", DE.getFullDisplayName()); assertEquals("de_CH", "Deutsch (Schweiz)", DE_CH.getFullDisplayName()); + assertEquals("hi", "हिन्दी", HI.getFullDisplayName()); + assertEquals("sr", "Српски", SR.getFullDisplayName()); assertEquals("zz", "QWERTY", ZZ.getFullDisplayName()); - // This is a preliminary subtype and may not exist. - if (HI_LATN != null) { - assertEquals("hi_ZZ", "Hinglish", HI_LATN.getFullDisplayName()); - } assertEquals("en_US", "English", EN_US.getMiddleDisplayName()); assertEquals("en_GB", "English", EN_GB.getMiddleDisplayName()); @@ -213,10 +254,16 @@ public class SpacebarLanguageUtilsTests extends AndroidTestCase { assertEquals("de", "Deutsch", DE.getMiddleDisplayName()); assertEquals("de_CH", "Deutsch", DE_CH.getMiddleDisplayName()); assertEquals("zz", "QWERTY", ZZ.getMiddleDisplayName()); - // This is a preliminary subtype and may not exist. + + // These are preliminary subtypes and may not exist. if (HI_LATN != null) { + assertEquals("hi_ZZ", "Hinglish", HI_LATN.getFullDisplayName()); assertEquals("hi_ZZ", "Hinglish", HI_LATN.getMiddleDisplayName()); } + if (SR_LATN != null) { + assertEquals("sr_ZZ", "Srpski", SR_LATN.getFullDisplayName()); + assertEquals("sr_ZZ", "Srpski", SR_LATN.getMiddleDisplayName()); + } return null; } }; @@ -239,6 +286,16 @@ public class SpacebarLanguageUtilsTests extends AndroidTestCase { assertEquals("es_US colemak", "Español", ES_US_COLEMAK.getMiddleDisplayName()); assertEquals("zz azerty", "AZERTY", ZZ_AZERTY.getMiddleDisplayName()); assertEquals("zz pc", "PC", ZZ_PC.getMiddleDisplayName()); + + // These are preliminary subtypes and may not exist. + if (HI_LATN_DVORAK != null) { + assertEquals("hi_ZZ dvorak", "Hinglish", HI_LATN_DVORAK.getFullDisplayName()); + assertEquals("hi_ZZ dvorak", "Hinglish", HI_LATN_DVORAK.getMiddleDisplayName()); + } + if (SR_LATN_QWERTY != null) { + assertEquals("sr_ZZ qwerty", "Srpski", SR_LATN_QWERTY.getFullDisplayName()); + assertEquals("sr_ZZ qwerty", "Srpski", SR_LATN_QWERTY.getMiddleDisplayName()); + } return null; } }; diff --git a/tests/src/com/android/inputmethod/latin/utils/StringAndJsonUtilsTests.java b/tests/src/com/android/inputmethod/latin/utils/StringAndJsonUtilsTests.java index 7d9d39959..0389fefb0 100644 --- a/tests/src/com/android/inputmethod/latin/utils/StringAndJsonUtilsTests.java +++ b/tests/src/com/android/inputmethod/latin/utils/StringAndJsonUtilsTests.java @@ -23,6 +23,8 @@ import android.text.Spanned; import android.text.SpannedString; import com.android.inputmethod.latin.common.Constants; +import com.android.inputmethod.latin.common.StringUtils; +import com.android.inputmethod.latin.utils.SpannableStringUtils; import java.util.Arrays; import java.util.List; @@ -375,9 +377,9 @@ public class StringAndJsonUtilsTests extends AndroidTestCase { spannableString.setSpan(span1, 0, 7, SPAN1_FLAGS); spannableString.setSpan(span2, 0, 5, SPAN2_FLAGS); spannableString.setSpan(span3, 12, 13, SPAN3_FLAGS); - final CharSequence[] charSequencesFromSpanned = StringUtils.split( + final CharSequence[] charSequencesFromSpanned = SpannableStringUtils.split( spannableString, " ", true /* preserveTrailingEmptySegmengs */); - final CharSequence[] charSequencesFromString = StringUtils.split( + final CharSequence[] charSequencesFromString = SpannableStringUtils.split( spannableString.toString(), " ", true /* preserveTrailingEmptySegmengs */); @@ -456,44 +458,44 @@ public class StringAndJsonUtilsTests extends AndroidTestCase { } public void testSplitCharSequencePreserveTrailingEmptySegmengs() { - assertEquals(1, StringUtils.split("", " ", + assertEquals(1, SpannableStringUtils.split("", " ", false /* preserveTrailingEmptySegmengs */).length); - assertEquals(1, StringUtils.split(new SpannedString(""), " ", + assertEquals(1, SpannableStringUtils.split(new SpannedString(""), " ", false /* preserveTrailingEmptySegmengs */).length); - assertEquals(1, StringUtils.split("", " ", + assertEquals(1, SpannableStringUtils.split("", " ", true /* preserveTrailingEmptySegmengs */).length); - assertEquals(1, StringUtils.split(new SpannedString(""), " ", + assertEquals(1, SpannableStringUtils.split(new SpannedString(""), " ", true /* preserveTrailingEmptySegmengs */).length); - assertEquals(0, StringUtils.split(" ", " ", + assertEquals(0, SpannableStringUtils.split(" ", " ", false /* preserveTrailingEmptySegmengs */).length); - assertEquals(0, StringUtils.split(new SpannedString(" "), " ", + assertEquals(0, SpannableStringUtils.split(new SpannedString(" "), " ", false /* preserveTrailingEmptySegmengs */).length); - assertEquals(2, StringUtils.split(" ", " ", + assertEquals(2, SpannableStringUtils.split(" ", " ", true /* preserveTrailingEmptySegmengs */).length); - assertEquals(2, StringUtils.split(new SpannedString(" "), " ", + assertEquals(2, SpannableStringUtils.split(new SpannedString(" "), " ", true /* preserveTrailingEmptySegmengs */).length); - assertEquals(3, StringUtils.split("a b c ", " ", + assertEquals(3, SpannableStringUtils.split("a b c ", " ", false /* preserveTrailingEmptySegmengs */).length); - assertEquals(3, StringUtils.split(new SpannedString("a b c "), " ", + assertEquals(3, SpannableStringUtils.split(new SpannedString("a b c "), " ", false /* preserveTrailingEmptySegmengs */).length); - assertEquals(5, StringUtils.split("a b c ", " ", + assertEquals(5, SpannableStringUtils.split("a b c ", " ", true /* preserveTrailingEmptySegmengs */).length); - assertEquals(5, StringUtils.split(new SpannedString("a b c "), " ", + assertEquals(5, SpannableStringUtils.split(new SpannedString("a b c "), " ", true /* preserveTrailingEmptySegmengs */).length); - assertEquals(6, StringUtils.split("a b ", " ", + assertEquals(6, SpannableStringUtils.split("a b ", " ", false /* preserveTrailingEmptySegmengs */).length); - assertEquals(6, StringUtils.split(new SpannedString("a b "), " ", + assertEquals(6, SpannableStringUtils.split(new SpannedString("a b "), " ", false /* preserveTrailingEmptySegmengs */).length); - assertEquals(7, StringUtils.split("a b ", " ", + assertEquals(7, SpannableStringUtils.split("a b ", " ", true /* preserveTrailingEmptySegmengs */).length); - assertEquals(7, StringUtils.split(new SpannedString("a b "), " ", + assertEquals(7, SpannableStringUtils.split(new SpannedString("a b "), " ", true /* preserveTrailingEmptySegmengs */).length); } } diff --git a/tests/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtilsTests.java b/tests/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtilsTests.java index dfc3fecfd..54f478f5a 100644 --- a/tests/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtilsTests.java +++ b/tests/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtilsTests.java @@ -23,6 +23,7 @@ import android.test.suitebuilder.annotation.SmallTest; import android.view.inputmethod.InputMethodInfo; import android.view.inputmethod.InputMethodSubtype; +import com.android.inputmethod.latin.R; import com.android.inputmethod.latin.RichInputMethodManager; import com.android.inputmethod.latin.RichInputMethodSubtype; @@ -36,6 +37,7 @@ public class SubtypeLocaleUtilsTests extends AndroidTestCase { private RichInputMethodManager mRichImm; private Resources mRes; + private InputMethodSubtype mSavedAddtionalSubtypes[]; InputMethodSubtype EN_US; InputMethodSubtype EN_GB; @@ -45,6 +47,8 @@ public class SubtypeLocaleUtilsTests extends AndroidTestCase { InputMethodSubtype FR_CH; InputMethodSubtype DE; InputMethodSubtype DE_CH; + InputMethodSubtype HI; + InputMethodSubtype SR; InputMethodSubtype ZZ; InputMethodSubtype DE_QWERTY; InputMethodSubtype FR_QWERTZ; @@ -54,17 +58,27 @@ public class SubtypeLocaleUtilsTests extends AndroidTestCase { InputMethodSubtype ZZ_AZERTY; InputMethodSubtype ZZ_PC; - // This is a preliminary subtype and may not exist. - InputMethodSubtype HI_LATN; + // These are preliminary subtypes and may not exist. + InputMethodSubtype HI_LATN; // Hinglish + InputMethodSubtype SR_LATN; // Serbian Latin + InputMethodSubtype HI_LATN_DVORAK; // Hinglis Dvorak + InputMethodSubtype SR_LATN_QWERTY; // Serbian Latin Qwerty @Override protected void setUp() throws Exception { super.setUp(); final Context context = getContext(); + mRes = context.getResources(); RichInputMethodManager.init(context); mRichImm = RichInputMethodManager.getInstance(); - mRes = context.getResources(); - SubtypeLocaleUtils.init(context); + + // Save and reset additional subtypes + mSavedAddtionalSubtypes = mRichImm.getAdditionalSubtypes(context); + final InputMethodSubtype[] predefinedAddtionalSubtypes = + AdditionalSubtypeUtils.createAdditionalSubtypesArray( + AdditionalSubtypeUtils.createPrefSubtypes( + mRes.getStringArray(R.array.predefined_subtypes))); + mRichImm.setAdditionalInputMethodSubtypes(predefinedAddtionalSubtypes); final InputMethodInfo imi = mRichImm.getInputMethodInfoOfThisIme(); final int subtypeCount = imi.getSubtypeCount(); @@ -89,6 +103,10 @@ public class SubtypeLocaleUtilsTests extends AndroidTestCase { Locale.GERMAN.toString(), "qwertz"); DE_CH = mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet( "de_CH", "swiss"); + HI = mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet( + "hi", "hindi"); + SR = mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet( + "sr", "south_slavic"); ZZ = mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet( SubtypeLocaleUtils.NO_LANGUAGE, "qwerty"); DE_QWERTY = AdditionalSubtypeUtils.createAsciiEmojiCapableAdditionalSubtype( @@ -107,6 +125,22 @@ public class SubtypeLocaleUtilsTests extends AndroidTestCase { SubtypeLocaleUtils.NO_LANGUAGE, "pcqwerty"); HI_LATN = mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet("hi_ZZ", "qwerty"); + if (HI_LATN != null) { + HI_LATN_DVORAK = AdditionalSubtypeUtils.createAsciiEmojiCapableAdditionalSubtype( + "hi_ZZ", "dvorak"); + } + SR_LATN = mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet("sr_ZZ", "serbian_qwertz"); + if (SR_LATN != null) { + SR_LATN_QWERTY = AdditionalSubtypeUtils.createAsciiEmojiCapableAdditionalSubtype( + "sr_ZZ", "qwerty"); + } + } + + @Override + protected void tearDown() throws Exception { + // Restore additional subtypes. + mRichImm.setAdditionalInputMethodSubtypes(mSavedAddtionalSubtypes); + super.tearDown(); } public void testAllFullDisplayName() { @@ -139,11 +173,9 @@ public class SubtypeLocaleUtilsTests extends AndroidTestCase { assertEquals("fr_CH", "swiss", SubtypeLocaleUtils.getKeyboardLayoutSetName(FR_CH)); assertEquals("de", "qwertz", SubtypeLocaleUtils.getKeyboardLayoutSetName(DE)); assertEquals("de_CH", "swiss", SubtypeLocaleUtils.getKeyboardLayoutSetName(DE_CH)); + assertEquals("hi", "hindi", SubtypeLocaleUtils.getKeyboardLayoutSetName(HI)); + assertEquals("sr", "south_slavic", SubtypeLocaleUtils.getKeyboardLayoutSetName(SR)); assertEquals("zz", "qwerty", SubtypeLocaleUtils.getKeyboardLayoutSetName(ZZ)); - // This is a preliminary subtype and may not exist. - if (HI_LATN != null) { - assertEquals("hi_ZZ", "qwerty", SubtypeLocaleUtils.getKeyboardLayoutSetName(HI_LATN)); - } assertEquals("de qwerty", "qwerty", SubtypeLocaleUtils.getKeyboardLayoutSetName(DE_QWERTY)); assertEquals("fr qwertz", "qwertz", SubtypeLocaleUtils.getKeyboardLayoutSetName(FR_QWERTZ)); @@ -155,28 +187,46 @@ public class SubtypeLocaleUtilsTests extends AndroidTestCase { SubtypeLocaleUtils.getKeyboardLayoutSetName(ES_US_COLEMAK)); assertEquals("zz azerty", "azerty", SubtypeLocaleUtils.getKeyboardLayoutSetName(ZZ_AZERTY)); + + // These are preliminary subtypes and may not exist. + if (HI_LATN != null) { + assertEquals("hi_ZZ", "qwerty", SubtypeLocaleUtils.getKeyboardLayoutSetName(HI_LATN)); + assertEquals("hi_ZZ dvorak", "dvorak", + SubtypeLocaleUtils.getKeyboardLayoutSetName(HI_LATN_DVORAK)); + } + if (SR_LATN != null) { + assertEquals("sr_ZZ", "serbian_qwertz", + SubtypeLocaleUtils.getKeyboardLayoutSetName(SR_LATN)); + assertEquals("sr_ZZ qwerty", "qwerty", + SubtypeLocaleUtils.getKeyboardLayoutSetName(SR_LATN_QWERTY)); + } } // InputMethodSubtype's display name in system locale (en_US). - // isAdditionalSubtype (T=true, F=false) - // locale layout | display name - // ------ ------- - ---------------------- - // en_US qwerty F English (US) exception - // en_GB qwerty F English (UK) exception - // es_US spanish F Spanish (US) exception - // fr azerty F French - // fr_CA qwerty F French (Canada) - // fr_CH swiss F French (Switzerland) - // de qwertz F German - // de_CH swiss F German (Switzerland) - // hi_ZZ qwerty F Hinglish - // zz qwerty F Alphabet (QWERTY) - // fr qwertz T French (QWERTZ) - // de qwerty T German (QWERTY) - // en_US azerty T English (US) (AZERTY) exception - // en_UK dvorak T English (UK) (Dvorak) exception - // es_US colemak T Spanish (US) (Colemak) exception - // zz pc T Alphabet (PC) + // isAdditionalSubtype (T=true, F=false) + // locale layout | display name + // ------ -------------- - ---------------------- + // en_US qwerty F English (US) exception + // en_GB qwerty F English (UK) exception + // es_US spanish F Spanish (US) exception + // fr azerty F French + // fr_CA qwerty F French (Canada) + // fr_CH swiss F French (Switzerland) + // de qwertz F German + // de_CH swiss F German (Switzerland) + // hi hindi F Hindi + // hi_ZZ qwerty F Hinglish exception + // sr south_slavic F Serbian + // sr_ZZ serbian_qwertz F Serbian (Latin) exception + // zz qwerty F Alphabet (QWERTY) + // fr qwertz T French (QWERTZ) + // de qwerty T German (QWERTY) + // en_US azerty T English (US) (AZERTY) exception + // en_UK dvorak T English (UK) (Dvorak) exception + // es_US colemak T Spanish (US) (Colemak) exception + // hi_ZZ dvorak T Hinglish (Dvorka) exception + // sr_ZZ qwerty T Serbian (QWERTY) exception + // zz pc T Alphabet (PC) public void testPredefinedSubtypesInEnglishSystemLocale() { final RunInLocale<Void> tests = new RunInLocale<Void>() { @@ -198,13 +248,21 @@ public class SubtypeLocaleUtilsTests extends AndroidTestCase { SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(DE)); assertEquals("de_CH", "German (Switzerland)", SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(DE_CH)); + assertEquals("hi", "Hindi", + SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(HI)); + assertEquals("sr", "Serbian", + SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(SR)); assertEquals("zz", "Alphabet (QWERTY)", SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(ZZ)); - // This is a preliminary subtype and may not exist. + // These are preliminary subtypes and may not exist. if (HI_LATN != null) { assertEquals("hi_ZZ", "Hinglish", SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(HI_LATN)); } + if (SR_LATN != null) { + assertEquals("sr_ZZ", "Serbian (Latin)", + SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(SR_LATN)); + } return null; } }; @@ -229,6 +287,15 @@ public class SubtypeLocaleUtilsTests extends AndroidTestCase { SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(ZZ_AZERTY)); assertEquals("zz pc", "Alphabet (PC)", SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(ZZ_PC)); + // These are preliminary subtypes and may not exist. + if (HI_LATN_DVORAK != null) { + assertEquals("hi_ZZ", "Hinglish (Dvorak)", + SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(HI_LATN_DVORAK)); + } + if (SR_LATN_QWERTY != null) { + assertEquals("sr_ZZ", "Serbian (QWERTY)", + SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(SR_LATN_QWERTY)); + } return null; } }; @@ -239,22 +306,27 @@ public class SubtypeLocaleUtilsTests extends AndroidTestCase { // isAdditionalSubtype (T=true, F=false) // locale layout | display name // ------ ------- - ---------------------- - // en_US qwerty F Anglais (États-Unis) exception - // en_GB qwerty F Anglais (Royaume-Uni) exception - // es_US spanish F Espagnol (États-Unis) exception - // fr azerty F Français - // fr_CA qwerty F Français (Canada) - // fr_CH swiss F Français (Suisse) - // de qwertz F Allemand - // de_CH swiss F Allemand (Suisse) - // hi_ZZ qwerty F Hinglish - // zz qwerty F Alphabet latin (QWERTY) - // fr qwertz T Français (QWERTZ) - // de qwerty T Allemand (QWERTY) - // en_US azerty T Anglais (États-Unis) (AZERTY) exception - // en_UK dvorak T Anglais (Royaume-Uni) (Dvorak) exception - // es_US colemak T Espagnol (États-Unis) (Colemak) exception - // zz pc T Alphabet latin (PC) + // en_US qwerty F Anglais (États-Unis) exception + // en_GB qwerty F Anglais (Royaume-Uni) exception + // es_US spanish F Espagnol (États-Unis) exception + // fr azerty F Français + // fr_CA qwerty F Français (Canada) + // fr_CH swiss F Français (Suisse) + // de qwertz F Allemand + // de_CH swiss F Allemand (Suisse) + // hi hindi F Hindi exception + // hi_ZZ qwerty F Hindi/Anglais exception + // sr south_slavic F Serbe exception + // sr_ZZ serbian_qwertz F Serbe (latin) exception + // zz qwerty F Alphabet latin (QWERTY) + // fr qwertz T Français (QWERTZ) + // de qwerty T Allemand (QWERTY) + // en_US azerty T Anglais (États-Unis) (AZERTY) exception + // en_UK dvorak T Anglais (Royaume-Uni) (Dvorak) exception + // es_US colemak T Espagnol (États-Unis) (Colemak) exception + // hi_ZZ dvorak T Hindi/Anglais (Dvorka) exception + // sr_ZZ qwerty T Serbe (QWERTY) exception + // zz pc T Alphabet latin (PC) public void testPredefinedSubtypesInFrenchSystemLocale() { final RunInLocale<Void> tests = new RunInLocale<Void>() { @@ -276,13 +348,21 @@ public class SubtypeLocaleUtilsTests extends AndroidTestCase { SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(DE)); assertEquals("de_CH", "Allemand (Suisse)", SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(DE_CH)); + assertEquals("hi", "Hindi", + SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(HI)); + assertEquals("sr", "Serbe", + SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(SR)); assertEquals("zz", "Alphabet latin (QWERTY)", SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(ZZ)); - // This is a preliminary subtype and may not exist. + // These are preliminary subtypes and may not exist. if (HI_LATN != null) { assertEquals("hi_ZZ", "Hindi/Anglais", SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(HI_LATN)); } + if (SR_LATN != null) { + assertEquals("sr_ZZ", "Serbe (latin)", + SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(SR_LATN)); + } return null; } }; @@ -307,12 +387,77 @@ public class SubtypeLocaleUtilsTests extends AndroidTestCase { SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(ZZ_AZERTY)); assertEquals("zz pc", "Alphabet latin (PC)", SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(ZZ_PC)); + // These are preliminary subtypes and may not exist. + if (HI_LATN_DVORAK != null) { + assertEquals("hi_ZZ", "Hindi/Anglais (Dvorak)", + SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(HI_LATN_DVORAK)); + } + if (SR_LATN_QWERTY != null) { + assertEquals("sr_ZZ", "Serbe (QWERTY)", + SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(SR_LATN_QWERTY)); + } return null; } }; tests.runInLocale(mRes, Locale.FRENCH); } + // InputMethodSubtype's display name in system locale (hi). + // isAdditionalSubtype (T=true, F=false) + // locale layout | display name + // ------ ------- - ---------------------- + // hi hindi F हिन्दी + // hi_ZZ qwerty F हिंग्लिश + // hi_ZZ dvorak T हिंग्लिश (Dvorak) + + public void testHinglishSubtypesInHindiSystemLocale() { + final RunInLocale<Void> tests = new RunInLocale<Void>() { + @Override + protected Void job (final Resources res) { + assertEquals("hi", "हिन्दी", + SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(HI)); + // These are preliminary subtypes and may not exist. + if (HI_LATN != null) { + assertEquals("hi_ZZ", "हिंग्लिश", + SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(HI_LATN)); + assertEquals("hi_ZZ", "हिंग्लिश (Dvorak)", + SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(HI_LATN_DVORAK)); + } + return null; + } + }; + tests.runInLocale(mRes, new Locale("hi")); + } + + // InputMethodSubtype's display name in system locale (sr). + // isAdditionalSubtype (T=true, F=false) + // locale layout | display name + // ------ -------------- - ---------------------- + // sr south_slavic F Српски + // sr_ZZ serbian_qwertz F српски (латиница) + // sr_ZZ qwerty T српски (QWERTY) + + public void testSerbianLatinSubtypesInSerbianSystemLocale() { + final RunInLocale<Void> tests = new RunInLocale<Void>() { + @Override + protected Void job (final Resources res) { + assertEquals("sr", "Српски", + SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(SR)); + // These are preliminary subtypes and may not exist. + if (SR_LATN != null) { + // TODO: Uncommented because of the current translation of these strings + // in Seriban are described in Latin script. +// assertEquals("sr_ZZ", "српски (латиница)", +// SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(SR_LATN)); +// assertEquals("sr_ZZ", "српски (QWERTY)", +// SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(SR_LATN_QWERTY)); + } + return null; + } + }; + tests.runInLocale(mRes, new Locale("sr")); + } + public void testIsRtlLanguage() { // Known Right-to-Left language subtypes. final InputMethodSubtype ARABIC = mRichImm diff --git a/tools/dicttool/Android.mk b/tools/dicttool/Android.mk index 09af9a020..81c0706c1 100644 --- a/tools/dicttool/Android.mk +++ b/tools/dicttool/Android.mk @@ -47,7 +47,6 @@ LATINIME_SRC_FILES_FOR_DICTTOOL := \ latin/BinaryDictionary.java \ latin/DicTraverseSession.java \ latin/Dictionary.java \ - latin/InputPointers.java \ latin/LastComposedWord.java \ latin/NgramContext.java \ latin/SuggestedWords.java \ @@ -59,9 +58,7 @@ LATINIME_SRC_FILES_FOR_DICTTOOL := \ latin/utils/CoordinateUtils.java \ latin/utils/FileUtils.java \ latin/utils/JniUtils.java \ - latin/utils/LocaleUtils.java \ - latin/utils/ResizableIntArray.java \ - latin/utils/StringUtils.java + latin/utils/LocaleUtils.java LATINIME_OVERRIDABLE_SRC_FILES_FOR_DICTTOOL := \ latin/define/DebugFlags.java |