aboutsummaryrefslogtreecommitdiffstats
path: root/common
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--common/Android.mk28
-rw-r--r--common/src/com/android/inputmethod/annotations/ExternallyReferenced.java (renamed from java/src/com/android/inputmethod/annotations/ExternallyReferenced.java)0
-rw-r--r--common/src/com/android/inputmethod/annotations/UsedForTesting.java (renamed from java/src/com/android/inputmethod/annotations/UsedForTesting.java)0
-rw-r--r--common/src/com/android/inputmethod/latin/common/CodePointUtils.java (renamed from tests/src/com/android/inputmethod/latin/makedict/CodePointUtils.java)8
-rw-r--r--common/src/com/android/inputmethod/latin/common/ComposedData.java61
-rw-r--r--common/src/com/android/inputmethod/latin/common/Constants.java (renamed from java/src/com/android/inputmethod/latin/Constants.java)39
-rw-r--r--common/src/com/android/inputmethod/latin/common/InputPointers.java (renamed from java/src/com/android/inputmethod/latin/InputPointers.java)44
-rw-r--r--common/src/com/android/inputmethod/latin/common/ResizableIntArray.java (renamed from java/src/com/android/inputmethod/latin/utils/ResizableIntArray.java)2
-rw-r--r--common/src/com/android/inputmethod/latin/common/StringUtils.java (renamed from java/src/com/android/inputmethod/latin/utils/StringUtils.java)310
9 files changed, 322 insertions, 170 deletions
diff --git a/common/Android.mk b/common/Android.mk
new file mode 100644
index 000000000..085543f75
--- /dev/null
+++ b/common/Android.mk
@@ -0,0 +1,28 @@
+# 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.
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+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)
+
+# Also build a host side 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/java/src/com/android/inputmethod/annotations/ExternallyReferenced.java b/common/src/com/android/inputmethod/annotations/ExternallyReferenced.java
index ea5f12ce2..ea5f12ce2 100644
--- a/java/src/com/android/inputmethod/annotations/ExternallyReferenced.java
+++ b/common/src/com/android/inputmethod/annotations/ExternallyReferenced.java
diff --git a/java/src/com/android/inputmethod/annotations/UsedForTesting.java b/common/src/com/android/inputmethod/annotations/UsedForTesting.java
index 2ada091e4..2ada091e4 100644
--- a/java/src/com/android/inputmethod/annotations/UsedForTesting.java
+++ b/common/src/com/android/inputmethod/annotations/UsedForTesting.java
diff --git a/tests/src/com/android/inputmethod/latin/makedict/CodePointUtils.java b/common/src/com/android/inputmethod/latin/common/CodePointUtils.java
index a270ee774..592da5c1f 100644
--- a/tests/src/com/android/inputmethod/latin/makedict/CodePointUtils.java
+++ b/common/src/com/android/inputmethod/latin/common/CodePointUtils.java
@@ -14,11 +14,15 @@
* limitations under the License.
*/
-package com.android.inputmethod.latin.makedict;
+package com.android.inputmethod.latin.common;
+
+import com.android.inputmethod.annotations.UsedForTesting;
import java.util.Random;
// Utility methods related with code points used for tests.
+// TODO: Figure out where this class should be.
+@UsedForTesting
public class CodePointUtils {
private CodePointUtils() {
// This utility class is not publicly instantiable.
@@ -60,6 +64,7 @@ public class CodePointUtils {
0x00FF /* LATIN SMALL LETTER Y WITH DIAERESIS */
};
+ @UsedForTesting
public static int[] generateCodePointSet(final int codePointSetSize, final Random random) {
final int[] codePointSet = new int[codePointSetSize];
for (int i = codePointSet.length - 1; i >= 0; ) {
@@ -80,6 +85,7 @@ public class CodePointUtils {
/**
* Generates a random word.
*/
+ @UsedForTesting
public static String generateWord(final Random random, final int[] codePointSet) {
StringBuilder builder = new StringBuilder();
// 8 * 4 = 32 chars max, but we do it the following way so as to bias the random toward
diff --git a/common/src/com/android/inputmethod/latin/common/ComposedData.java b/common/src/com/android/inputmethod/latin/common/ComposedData.java
new file mode 100644
index 000000000..0508d49cb
--- /dev/null
+++ b/common/src/com/android/inputmethod/latin/common/ComposedData.java
@@ -0,0 +1,61 @@
+/*
+ * 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.common;
+
+/**
+ * An immutable class that encapsulates a snapshot of word composition data.
+ */
+public class ComposedData {
+ public final InputPointers mInputPointers;
+ public final boolean mIsBatchMode;
+ public final String mTypedWord;
+ public ComposedData(final InputPointers inputPointers, final boolean isBatchMode,
+ final String typedWord) {
+ mInputPointers = inputPointers;
+ mIsBatchMode = isBatchMode;
+ mTypedWord = typedWord;
+ }
+
+ /**
+ * Copy the code points in the typed word to a destination array of ints.
+ *
+ * If the array is too small to hold the code points in the typed word, nothing is copied and
+ * -1 is returned.
+ *
+ * @param destination the array of ints.
+ * @return the number of copied code points.
+ */
+ public int copyCodePointsExceptTrailingSingleQuotesAndReturnCodePointCount(
+ final int[] destination) {
+ // lastIndex is exclusive
+ final int lastIndex = mTypedWord.length()
+ - StringUtils.getTrailingSingleQuotesCount(mTypedWord);
+ if (lastIndex <= 0) {
+ // The string is empty or contains only single quotes.
+ return 0;
+ }
+
+ // The following function counts the number of code points in the text range which begins
+ // at index 0 and extends to the character at lastIndex.
+ final int codePointSize = Character.codePointCount(mTypedWord, 0, lastIndex);
+ if (codePointSize > destination.length) {
+ return -1;
+ }
+ return StringUtils.copyCodePointsAndReturnCodePointCount(destination, mTypedWord, 0,
+ lastIndex, true /* downCase */);
+ }
+}
diff --git a/java/src/com/android/inputmethod/latin/Constants.java b/common/src/com/android/inputmethod/latin/common/Constants.java
index 43af66eb7..8f4a1e50d 100644
--- a/java/src/com/android/inputmethod/latin/Constants.java
+++ b/common/src/com/android/inputmethod/latin/common/Constants.java
@@ -14,7 +14,9 @@
* limitations under the License.
*/
-package com.android.inputmethod.latin;
+package com.android.inputmethod.latin.common;
+
+import com.android.inputmethod.annotations.UsedForTesting;
public final class Constants {
public static final class Color {
@@ -57,6 +59,13 @@ public final class Constants {
@SuppressWarnings("dep-ann")
public static final String FORCE_ASCII = "forceAscii";
+ /**
+ * The private IME option used to suppress the floating gesture preview for a given text
+ * field. This overrides the corresponding keyboard settings preference.
+ * {@link com.android.inputmethod.latin.settings.SettingsValues#mGestureFloatingPreviewTextEnabled}
+ */
+ public static final String NO_FLOATING_GESTURE_PREVIEW = "noGestureFloatingPreview";
+
private ImeOption() {
// This utility class is not publicly instantiable.
}
@@ -217,15 +226,17 @@ public final class Constants {
public static final int CODE_CLOSING_ANGLE_BRACKET = '>';
public static final int CODE_INVERTED_QUESTION_MARK = 0xBF; // ¿
public static final int CODE_INVERTED_EXCLAMATION_MARK = 0xA1; // ¡
+ public static final int CODE_GRAVE_ACCENT = '`';
+ public static final int CODE_CIRCUMFLEX_ACCENT = '^';
+ public static final int CODE_TILDE = '~';
public static final String REGEXP_PERIOD = "\\.";
public static final String STRING_SPACE = " ";
- public static final String STRING_PERIOD_AND_SPACE = ". ";
/**
* Special keys code. Must be negative.
- * These should be aligned with {@link KeyboardCodesSet#ID_TO_NAME},
- * {@link KeyboardCodesSet#DEFAULT}, and {@link KeyboardCodesSet#RTL}.
+ * These should be aligned with constants in
+ * {@link com.android.inputmethod.keyboard.internal.KeyboardCodesSet}.
*/
public static final int CODE_SHIFT = -1;
public static final int CODE_CAPSLOCK = -2;
@@ -287,21 +298,31 @@ public final class Constants {
return "[" + sb + "]";
}
- public static final int MAX_INT_BIT_COUNT = 32;
-
/**
* Screen metrics (a.k.a. Device form factor) constants of
- * {@link R.integer#config_screen_metrics}.
+ * {@link com.android.inputmethod.latin.R.integer#config_screen_metrics}.
*/
public static final int SCREEN_METRICS_SMALL_PHONE = 0;
public static final int SCREEN_METRICS_LARGE_PHONE = 1;
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 BatchInputArbiter} and etc. to preallocate regions that
- * contain gesture event points.
+ * This constant is used by {@link com.android.inputmethod.keyboard.internal.BatchInputArbiter}
+ * and etc. to preallocate regions that contain gesture event points.
*/
public static final int DEFAULT_GESTURE_POINTS_CAPACITY = 128;
diff --git a/java/src/com/android/inputmethod/latin/InputPointers.java b/common/src/com/android/inputmethod/latin/common/InputPointers.java
index 790e0d830..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);
@@ -145,12 +139,13 @@ public final class InputPointers {
return mPointerIds.getPrimitiveArray();
}
+ /**
+ * Gets the time each point was registered, in milliseconds, relative to the first event in the
+ * sequence.
+ * @return The time each point was registered, in milliseconds, relative to the first event in
+ * the sequence.
+ */
public int[] getTimes() {
- if (DebugFlags.DEBUG_ENABLED || DEBUG_TIME) {
- if (!isValidTimeStamps()) {
- throw new RuntimeException("Time stamps are invalid.");
- }
- }
return mTimes.getPrimitiveArray();
}
@@ -159,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 1781924ac..be7260308 100644
--- a/java/src/com/android/inputmethod/latin/utils/StringUtils.java
+++ b/common/src/com/android/inputmethod/latin/common/StringUtils.java
@@ -14,27 +14,23 @@
* limitations under the License.
*/
-package com.android.inputmethod.latin.utils;
-
-import static com.android.inputmethod.latin.Constants.CODE_UNSPECIFIED;
-
-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.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;
@@ -49,12 +45,77 @@ public final class StringUtils {
// This utility class is not publicly instantiable.
}
- public static int codePointCount(final String text) {
- if (TextUtils.isEmpty(text)) return 0;
- return text.codePointCount(0, text.length());
+ // 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 String newSingleCodePointString(int codePoint) {
+ public static int codePointCount(@Nullable final CharSequence text) {
+ if (isEmpty(text)) {
+ return 0;
+ }
+ return Character.codePointCount(text, 0, text.length());
+ }
+
+ @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
@@ -64,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;
}
@@ -76,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);
@@ -101,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);
}
/**
@@ -110,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()) {
@@ -119,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;
@@ -129,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);
}
@@ -139,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);
}
@@ -155,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.
@@ -168,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) {
@@ -199,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;
@@ -214,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;
@@ -227,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) {
@@ -239,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();
@@ -275,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) {
@@ -288,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) {
@@ -301,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)) {
@@ -321,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();
@@ -356,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;
@@ -395,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;
}
@@ -420,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
@@ -446,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))) {
@@ -457,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();
@@ -472,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();
@@ -489,23 +584,28 @@ 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);
return codePointCount(casedText) == 1
- ? casedText.codePointAt(0) : CODE_UNSPECIFIED;
+ ? 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) {
@@ -514,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 input 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 {@param input} 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]);
@@ -587,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);
}
@@ -608,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) {