aboutsummaryrefslogtreecommitdiffstats
path: root/java/src/com/android/inputmethod
diff options
context:
space:
mode:
Diffstat (limited to 'java/src/com/android/inputmethod')
-rw-r--r--java/src/com/android/inputmethod/keyboard/KeyboardActionListener.java6
-rw-r--r--java/src/com/android/inputmethod/keyboard/MainKeyboardView.java10
-rw-r--r--java/src/com/android/inputmethod/keyboard/PointerTracker.java26
-rw-r--r--java/src/com/android/inputmethod/latin/AudioAndHapticFeedbackManager.java12
-rw-r--r--java/src/com/android/inputmethod/latin/LatinIME.java49
-rw-r--r--java/src/com/android/inputmethod/latin/settings/SettingsValues.java54
-rw-r--r--java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java2
-rw-r--r--java/src/com/android/inputmethod/latin/utils/StringUtils.java37
8 files changed, 150 insertions, 46 deletions
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardActionListener.java b/java/src/com/android/inputmethod/keyboard/KeyboardActionListener.java
index b26698665..dc760e685 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardActionListener.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardActionListener.java
@@ -26,10 +26,10 @@ public interface KeyboardActionListener {
*
* @param primaryCode the unicode of the key being pressed. If the touch is not on a valid key,
* the value will be zero.
- * @param isRepeatKey true if pressing has occurred while key repeat input.
+ * @param repeatCount how many times the key was repeated. Zero if it is the first press.
* @param isSinglePointer true if pressing has occurred while no other key is being pressed.
*/
- public void onPressKey(int primaryCode, boolean isRepeatKey, boolean isSinglePointer);
+ public void onPressKey(int primaryCode, int repeatCount, boolean isSinglePointer);
/**
* Called when the user releases a key. This is sent after the {@link #onCodeInput} is called.
@@ -103,7 +103,7 @@ public interface KeyboardActionListener {
public static class Adapter implements KeyboardActionListener {
@Override
- public void onPressKey(int primaryCode, boolean isRepeatKey, boolean isSinglePointer) {}
+ public void onPressKey(int primaryCode, int repeatCount, boolean isSinglePointer) {}
@Override
public void onReleaseKey(int primaryCode, boolean withSliding) {}
@Override
diff --git a/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java b/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java
index 526c2f1ec..f3d0eadc8 100644
--- a/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java
+++ b/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java
@@ -217,7 +217,7 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack
startWhileTypingFadeinAnimation(keyboardView);
break;
case MSG_REPEAT_KEY:
- tracker.onKeyRepeat(msg.arg1);
+ tracker.onKeyRepeat(msg.arg1 /* code */, msg.arg2 /* repeatCount */);
break;
case MSG_LONGPRESS_KEY:
keyboardView.onLongPress(tracker);
@@ -230,12 +230,14 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack
}
@Override
- public void startKeyRepeatTimer(final PointerTracker tracker, final int delay) {
+ public void startKeyRepeatTimer(final PointerTracker tracker, final int repeatCount,
+ final int delay) {
final Key key = tracker.getKey();
if (key == null || delay == 0) {
return;
}
- sendMessageDelayed(obtainMessage(MSG_REPEAT_KEY, key.mCode, 0, tracker), delay);
+ sendMessageDelayed(
+ obtainMessage(MSG_REPEAT_KEY, key.mCode, repeatCount, tracker), delay);
}
public void cancelKeyRepeatTimer() {
@@ -938,7 +940,7 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack
if (key.hasNoPanelAutoMoreKey()) {
final int moreKeyCode = key.mMoreKeys[0].mCode;
tracker.onLongPressed();
- listener.onPressKey(moreKeyCode, false /* isRepeatKey */, true /* isSinglePointer */);
+ listener.onPressKey(moreKeyCode, 0 /* repeatCount */, true /* isSinglePointer */);
listener.onCodeInput(moreKeyCode,
Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE);
listener.onReleaseKey(moreKeyCode, false /* withSliding */);
diff --git a/java/src/com/android/inputmethod/keyboard/PointerTracker.java b/java/src/com/android/inputmethod/keyboard/PointerTracker.java
index b66ee2a65..5387ddb6d 100644
--- a/java/src/com/android/inputmethod/keyboard/PointerTracker.java
+++ b/java/src/com/android/inputmethod/keyboard/PointerTracker.java
@@ -64,7 +64,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
/**
* Get KeyboardActionListener object that is used to register key code and so on.
- * @return the KeyboardActionListner for this PointerTracker
+ * @return the KeyboardActionListner for this PointerTracke
*/
public KeyboardActionListener getKeyboardActionListener();
@@ -94,7 +94,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
public interface TimerProxy {
public void startTypingStateTimer(Key typedKey);
public boolean isTypingState();
- public void startKeyRepeatTimer(PointerTracker tracker, int delay);
+ public void startKeyRepeatTimer(PointerTracker tracker, int repeatCount, int delay);
public void startLongPressTimer(PointerTracker tracker, int delay);
public void cancelLongPressTimer();
public void startDoubleTapShiftKeyTimer();
@@ -111,7 +111,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
@Override
public boolean isTypingState() { return false; }
@Override
- public void startKeyRepeatTimer(PointerTracker tracker, int delay) {}
+ public void startKeyRepeatTimer(PointerTracker tracker, int repeatCount, int delay) {}
@Override
public void startLongPressTimer(PointerTracker tracker, int delay) {}
@Override
@@ -490,7 +490,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
// Returns true if keyboard has been changed by this callback.
private boolean callListenerOnPressAndCheckKeyboardLayoutChange(final Key key,
- final boolean isRepeatKey) {
+ final int repeatCount) {
// While gesture input is going on, this method should be a no-operation. But when gesture
// input has been canceled, <code>sInGesture</code> and <code>mIsDetectingGesture</code>
// are set to false. To keep this method is a no-operation,
@@ -504,13 +504,13 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
KeyDetector.printableCode(key),
ignoreModifierKey ? " ignoreModifier" : "",
key.isEnabled() ? "" : " disabled",
- isRepeatKey ? " repeat" : ""));
+ repeatCount > 0 ? " repeatCount=" + repeatCount : ""));
}
if (ignoreModifierKey) {
return false;
}
if (key.isEnabled()) {
- mListener.onPressKey(key.mCode, isRepeatKey, getActivePointerTrackerCount() == 1);
+ mListener.onPressKey(key.mCode, repeatCount, getActivePointerTrackerCount() == 1);
final boolean keyboardLayoutHasBeenChanged = mKeyboardLayoutHasBeenChanged;
mKeyboardLayoutHasBeenChanged = false;
mTimerProxy.startTypingStateTimer(key);
@@ -967,7 +967,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
// This onPress call may have changed keyboard layout. Those cases are detected at
// {@link #setKeyboard}. In those cases, we should update key according to the new
// keyboard layout.
- if (callListenerOnPressAndCheckKeyboardLayoutChange(key, false /* isRepeatKey */)) {
+ if (callListenerOnPressAndCheckKeyboardLayoutChange(key, 0 /* repeatCount */)) {
key = onDownKey(x, y, eventTime);
}
@@ -1057,7 +1057,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
// at {@link #setKeyboard}. In those cases, we should update key according
// to the new keyboard layout.
Key key = newKey;
- if (callListenerOnPressAndCheckKeyboardLayoutChange(key, false /* isRepeatKey */)) {
+ if (callListenerOnPressAndCheckKeyboardLayoutChange(key, 0 /* repeatCount */)) {
key = onMoveKey(x, y);
}
onMoveToNewKey(key, x, y);
@@ -1413,16 +1413,18 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
// Don't start key repeat when we are in sliding input mode.
if (mIsInSlidingKeyInput) return;
detectAndSendKey(key, key.mX, key.mY, SystemClock.uptimeMillis());
- mTimerProxy.startKeyRepeatTimer(this, sParams.mKeyRepeatStartTimeout);
+ final int startRepeatCount = 1;
+ mTimerProxy.startKeyRepeatTimer(this, startRepeatCount, sParams.mKeyRepeatStartTimeout);
}
- public void onKeyRepeat(final int code) {
+ public void onKeyRepeat(final int code, final int repeatCount) {
final Key key = getKey();
if (key == null || key.mCode != code) {
return;
}
- mTimerProxy.startKeyRepeatTimer(this, sParams.mKeyRepeatInterval);
- callListenerOnPressAndCheckKeyboardLayoutChange(key, true /* isRepeatKey */);
+ final int nextRepeatCount = repeatCount + 1;
+ mTimerProxy.startKeyRepeatTimer(this, nextRepeatCount, sParams.mKeyRepeatInterval);
+ callListenerOnPressAndCheckKeyboardLayoutChange(key, repeatCount);
callListenerOnCodeInput(key, code, mKeyX, mKeyY, SystemClock.uptimeMillis());
}
diff --git a/java/src/com/android/inputmethod/latin/AudioAndHapticFeedbackManager.java b/java/src/com/android/inputmethod/latin/AudioAndHapticFeedbackManager.java
index 42c57946d..54bc29559 100644
--- a/java/src/com/android/inputmethod/latin/AudioAndHapticFeedbackManager.java
+++ b/java/src/com/android/inputmethod/latin/AudioAndHapticFeedbackManager.java
@@ -57,10 +57,10 @@ public final class AudioAndHapticFeedbackManager {
mVibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
}
- public void hapticAndAudioFeedback(final int primaryCode,
+ public void performHapticAndAudioFeedback(final int code,
final View viewToPerformHapticFeedbackOn) {
- vibrateInternal(viewToPerformHapticFeedbackOn);
- playKeyClick(primaryCode);
+ performHapticFeedback(viewToPerformHapticFeedbackOn);
+ performAudioFeedback(code);
}
public boolean hasVibrator() {
@@ -81,14 +81,14 @@ public final class AudioAndHapticFeedbackManager {
return mAudioManager.getRingerMode() == AudioManager.RINGER_MODE_NORMAL;
}
- private void playKeyClick(final int primaryCode) {
+ public void performAudioFeedback(final int code) {
// if mAudioManager is null, we can't play a sound anyway, so return
if (mAudioManager == null) {
return;
}
if (mSoundOn) {
final int sound;
- switch (primaryCode) {
+ switch (code) {
case Constants.CODE_DELETE:
sound = AudioManager.FX_KEYPRESS_DELETE;
break;
@@ -106,7 +106,7 @@ public final class AudioAndHapticFeedbackManager {
}
}
- private void vibrateInternal(final View viewToPerformHapticFeedbackOn) {
+ public void performHapticFeedback(final View viewToPerformHapticFeedbackOn) {
if (!mSettingsValues.mVibrateOn) {
return;
}
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index 8158ac055..ffe317161 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -122,6 +122,8 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
private static final int PENDING_IMS_CALLBACK_DURATION = 800;
+ private static final int PERIOD_FOR_AUDIO_AND_HAPTIC_FEEDBACK_IN_KEY_REPEAT = 2;
+
/**
* The name of the scheme used by the Package Manager to warn of a new package installation,
* replacement or removal.
@@ -1355,10 +1357,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
}
}
- private static boolean isAlphabet(final int code) {
- return Character.isLetter(code);
- }
-
private void onSettingsKeyPressed() {
if (isShowingOptionDialog()) return;
showSubtypeSelectorAndSettings();
@@ -1466,7 +1464,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
break;
case Constants.CODE_SHIFT:
// Note: Calling back to the keyboard on Shift key is handled in
- // {@link #onPressKey(int,boolean)} and {@link #onReleaseKey(int,boolean)}.
+ // {@link #onPressKey(int,int,boolean)} and {@link #onReleaseKey(int,boolean)}.
final Keyboard currentKeyboard = switcher.getKeyboard();
if (null != currentKeyboard && currentKeyboard.mId.isAlphabetKeyboard()) {
// TODO: Instead of checking for alphabetic keyboard here, separate keycodes for
@@ -1480,7 +1478,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
break;
case Constants.CODE_SWITCH_ALPHA_SYMBOL:
// Note: Calling back to the keyboard on symbol key is handled in
- // {@link #onPressKey(int,boolean)} and {@link #onReleaseKey(int,boolean)}.
+ // {@link #onPressKey(int,int,boolean)} and {@link #onReleaseKey(int,boolean)}.
break;
case Constants.CODE_SETTINGS:
onSettingsKeyPressed();
@@ -1861,6 +1859,11 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
}
mConnection.setComposingText(getTextWithUnderline(mWordComposer.getTypedWord()), 1);
mHandler.postUpdateSuggestionStrip();
+ if (!mWordComposer.isComposingWord()) {
+ // If we just removed the last character, auto-caps mode may have changed so we
+ // need to re-evaluate.
+ mKeyboardSwitcher.updateShiftState();
+ }
} else {
final SettingsValues currentSettings = mSettings.getCurrent();
if (mLastComposedWord.canRevertCommit()) {
@@ -1948,6 +1951,8 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
if (currentSettings.isSuggestionsRequested(mDisplayOrientation)) {
restartSuggestionsOnWordBeforeCursorIfAtEndOfWord();
}
+ // We just removed a character. We need to update the auto-caps state.
+ mKeyboardSwitcher.updateShiftState();
}
}
@@ -1994,8 +1999,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
// NOTE: isCursorTouchingWord() is a blocking IPC call, so it often takes several
// dozen milliseconds. Avoid calling it as much as possible, since we are on the UI
// thread here.
- if (!isComposingWord && (isAlphabet(primaryCode)
- || currentSettings.isWordConnector(primaryCode))
+ if (!isComposingWord && currentSettings.isWordCodePoint(primaryCode)
&& currentSettings.isSuggestionsRequested(mDisplayOrientation) &&
!mConnection.isCursorTouchingWord(currentSettings)) {
// Reset entirely the composing state anyway, then start composing a new word unless
@@ -2696,30 +2700,43 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
}
}
- private void hapticAndAudioFeedback(final int code, final boolean isRepeatKey) {
+ private void hapticAndAudioFeedback(final int code, final int repeatCount) {
final MainKeyboardView keyboardView = mKeyboardSwitcher.getMainKeyboardView();
if (keyboardView != null && keyboardView.isInSlidingKeyInput()) {
// No need to feedback while sliding input.
return;
}
- if (isRepeatKey) {
- // No need to feedback when repeating key.
- return;
+ if (repeatCount > 0) {
+ if (code == Constants.CODE_DELETE && !mConnection.canDeleteCharacters()) {
+ // No need to feedback when repeat delete key will have no effect.
+ return;
+ }
+ // TODO: Use event time that the last feedback has been generated instead of relying on
+ // a repeat count to thin out feedback.
+ if (repeatCount % PERIOD_FOR_AUDIO_AND_HAPTIC_FEEDBACK_IN_KEY_REPEAT == 0) {
+ return;
+ }
+ }
+ final AudioAndHapticFeedbackManager feedbackManager =
+ AudioAndHapticFeedbackManager.getInstance();
+ if (repeatCount == 0) {
+ // TODO: Reconsider how to perform haptic feedback when repeating key.
+ feedbackManager.performHapticFeedback(keyboardView);
}
- AudioAndHapticFeedbackManager.getInstance().hapticAndAudioFeedback(code, keyboardView);
+ feedbackManager.performAudioFeedback(code);
}
// Callback of the {@link KeyboardActionListener}. This is called when a key is depressed;
// release matching call is {@link #onReleaseKey(int,boolean)} below.
@Override
- public void onPressKey(final int primaryCode, final boolean isRepeatKey,
+ public void onPressKey(final int primaryCode, final int repeatCount,
final boolean isSinglePointer) {
mKeyboardSwitcher.onPressKey(primaryCode, isSinglePointer);
- hapticAndAudioFeedback(primaryCode, isRepeatKey);
+ hapticAndAudioFeedback(primaryCode, repeatCount);
}
// Callback of the {@link KeyboardActionListener}. This is called when a key is released;
- // press matching call is {@link #onPressKey(int,boolean,boolean)} above.
+ // press matching call is {@link #onPressKey(int,int,boolean)} above.
@Override
public void onReleaseKey(final int primaryCode, final boolean withSliding) {
mKeyboardSwitcher.onReleaseKey(primaryCode, withSliding);
diff --git a/java/src/com/android/inputmethod/latin/settings/SettingsValues.java b/java/src/com/android/inputmethod/latin/settings/SettingsValues.java
index a25cf620c..195f9f8ef 100644
--- a/java/src/com/android/inputmethod/latin/settings/SettingsValues.java
+++ b/java/src/com/android/inputmethod/latin/settings/SettingsValues.java
@@ -22,6 +22,7 @@ import android.content.res.Resources;
import android.util.Log;
import android.view.inputmethod.EditorInfo;
+import com.android.inputmethod.annotations.UsedForTesting;
import com.android.inputmethod.keyboard.internal.KeySpecParser;
import com.android.inputmethod.latin.Dictionary;
import com.android.inputmethod.latin.InputAttributes;
@@ -170,6 +171,55 @@ public final class SettingsValues {
mIsInternal = Settings.isInternal(prefs);
}
+ // Only for tests
+ private SettingsValues(final Locale locale) {
+ // TODO: locale is saved, but not used yet. May have to change this if tests require.
+ mLocale = locale;
+ mDelayUpdateOldSuggestions = 0;
+ mSymbolsPrecededBySpace = new int[] { '(', '[', '{', '&' };
+ Arrays.sort(mSymbolsPrecededBySpace);
+ mSymbolsFollowedBySpace = new int[] { '.', ',', ';', ':', '!', '?', ')', ']', '}', '&' };
+ Arrays.sort(mSymbolsFollowedBySpace);
+ mWordConnectors = new int[] { '\'', '-' };
+ Arrays.sort(mWordConnectors);
+ final String[] suggestPuncsSpec = new String[] { "!", "?", ",", ":", ";" };
+ mSuggestPuncList = createSuggestPuncList(suggestPuncsSpec);
+ mWordSeparators = "&\t \n()[]{}*&<>+=|.,;:!?/_\"";
+ mHintToSaveText = "Touch again to save";
+ mInputAttributes = new InputAttributes(null, false /* isFullscreenMode */);
+ mAutoCap = true;
+ mVibrateOn = true;
+ mSoundOn = true;
+ mKeyPreviewPopupOn = true;
+ mSlidingKeyInputPreviewEnabled = true;
+ mVoiceMode = "0";
+ mIncludesOtherImesInLanguageSwitchList = false;
+ mShowsLanguageSwitchKey = true;
+ mUseContactsDict = true;
+ mUseDoubleSpacePeriod = true;
+ mBlockPotentiallyOffensive = true;
+ mAutoCorrectEnabled = true;
+ mBigramPredictionEnabled = true;
+ mKeyLongpressTimeout = 300;
+ mKeypressVibrationDuration = 5;
+ mKeypressSoundVolume = 1;
+ mKeyPreviewPopupDismissDelay = 70;
+ mAutoCorrectionThreshold = 1;
+ mVoiceKeyEnabled = true;
+ mVoiceKeyOnMain = true;
+ mGestureInputEnabled = true;
+ mGestureTrailEnabled = true;
+ mGestureFloatingPreviewTextEnabled = true;
+ mCorrectionEnabled = mAutoCorrectEnabled && !mInputAttributes.mInputTypeNoAutoCorrect;
+ mSuggestionVisibility = 0;
+ mIsInternal = false;
+ }
+
+ @UsedForTesting
+ public static SettingsValues makeDummySettingsValuesForTest(final Locale locale) {
+ return new SettingsValues(locale);
+ }
+
public boolean isApplicationSpecifiedCompletionsOn() {
return mInputAttributes.mApplicationSpecifiedCompletionOn;
}
@@ -194,6 +244,10 @@ public final class SettingsValues {
return Arrays.binarySearch(mWordConnectors, code) >= 0;
}
+ public boolean isWordCodePoint(final int code) {
+ return Character.isLetter(code) || isWordConnector(code);
+ }
+
public boolean isUsuallyPrecededBySpace(final int code) {
return Arrays.binarySearch(mSymbolsPrecededBySpace, code) >= 0;
}
diff --git a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java
index 2644f3c9c..badc942b9 100644
--- a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java
+++ b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java
@@ -198,7 +198,7 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick
@Override
public boolean onLongClick(final View view) {
- AudioAndHapticFeedbackManager.getInstance().hapticAndAudioFeedback(
+ AudioAndHapticFeedbackManager.getInstance().performHapticAndAudioFeedback(
Constants.NOT_A_CODE, this);
return showMoreSuggestions();
}
diff --git a/java/src/com/android/inputmethod/latin/utils/StringUtils.java b/java/src/com/android/inputmethod/latin/utils/StringUtils.java
index 7406d855a..f88f2cca7 100644
--- a/java/src/com/android/inputmethod/latin/utils/StringUtils.java
+++ b/java/src/com/android/inputmethod/latin/utils/StringUtils.java
@@ -19,6 +19,7 @@ package com.android.inputmethod.latin.utils;
import android.text.TextUtils;
import com.android.inputmethod.latin.Constants;
+import com.android.inputmethod.latin.settings.SettingsValues;
import java.util.ArrayList;
import java.util.Locale;
@@ -193,27 +194,55 @@ public final class StringUtils {
}
public static boolean isIdenticalAfterUpcase(final String text) {
- final int len = text.length();
- for (int i = 0; i < len; i = text.offsetByCodePoints(i, 1)) {
+ final int length = text.length();
+ int i = 0;
+ while (i < length) {
final int codePoint = text.codePointAt(i);
if (Character.isLetter(codePoint) && !Character.isUpperCase(codePoint)) {
return false;
}
+ i += Character.charCount(codePoint);
}
return true;
}
public static boolean isIdenticalAfterDowncase(final String text) {
- final int len = text.length();
- for (int i = 0; i < len; i = text.offsetByCodePoints(i, 1)) {
+ final int length = text.length();
+ int i = 0;
+ while (i < length) {
final int codePoint = text.codePointAt(i);
if (Character.isLetter(codePoint) && !Character.isLowerCase(codePoint)) {
return false;
}
+ i += Character.charCount(codePoint);
}
return true;
}
+ public static boolean looksValidForDictionaryInsertion(final CharSequence text,
+ final SettingsValues settings) {
+ if (TextUtils.isEmpty(text)) return false;
+ final int length = text.length();
+ int i = 0;
+ int digitCount = 0;
+ while (i < length) {
+ final int codePoint = Character.codePointAt(text, i);
+ final int charCount = Character.charCount(codePoint);
+ i += charCount;
+ if (Character.isDigit(codePoint)) {
+ // Count digits: see below
+ digitCount += charCount;
+ continue;
+ }
+ if (!settings.isWordCodePoint(codePoint)) return false;
+ }
+ // We reject strings entirely comprised of digits to avoid using PIN codes or credit
+ // card numbers. It would come in handy for word prediction though; a good example is
+ // when writing one's address where the street number is usually quite discriminative,
+ // as well as the postal code.
+ return digitCount < length;
+ }
+
public static boolean isIdenticalAfterCapitalizeEachWord(final String text,
final String separators) {
boolean needCapsNext = true;