Split Utils class to StringUtils, SubtypeUtils, and JniUtils
Change-Id: I09e91675fe7d573dad8c933ad513b21d7e409144main
parent
3e2d385810
commit
cc8c8b99bd
|
@ -32,7 +32,7 @@ import android.view.inputmethod.InputMethodManager;
|
||||||
import com.android.inputmethod.deprecated.LanguageSwitcherProxy;
|
import com.android.inputmethod.deprecated.LanguageSwitcherProxy;
|
||||||
import com.android.inputmethod.latin.R;
|
import com.android.inputmethod.latin.R;
|
||||||
import com.android.inputmethod.latin.SubtypeSwitcher;
|
import com.android.inputmethod.latin.SubtypeSwitcher;
|
||||||
import com.android.inputmethod.latin.Utils;
|
import com.android.inputmethod.latin.SubtypeUtils;
|
||||||
|
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
@ -163,7 +163,7 @@ public class InputMethodManagerCompatWrapper {
|
||||||
private InputMethodInfoCompatWrapper getLatinImeInputMethodInfo() {
|
private InputMethodInfoCompatWrapper getLatinImeInputMethodInfo() {
|
||||||
if (TextUtils.isEmpty(mLatinImePackageName))
|
if (TextUtils.isEmpty(mLatinImePackageName))
|
||||||
return null;
|
return null;
|
||||||
return Utils.getInputMethodInfo(mLatinImePackageName);
|
return SubtypeUtils.getInputMethodInfo(mLatinImePackageName);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static InputMethodSubtypeCompatWrapper getLastResortSubtype(String mode) {
|
private static InputMethodSubtypeCompatWrapper getLastResortSubtype(String mode) {
|
||||||
|
@ -260,7 +260,8 @@ public class InputMethodManagerCompatWrapper {
|
||||||
|
|
||||||
// The code below are based on {@link InputMethodManager#showInputMethodMenuInternal}.
|
// The code below are based on {@link InputMethodManager#showInputMethodMenuInternal}.
|
||||||
|
|
||||||
final InputMethodInfoCompatWrapper myImi = Utils.getInputMethodInfo(mLatinImePackageName);
|
final InputMethodInfoCompatWrapper myImi = SubtypeUtils.getInputMethodInfo(
|
||||||
|
mLatinImePackageName);
|
||||||
final List<InputMethodSubtypeCompatWrapper> myImsList = getEnabledInputMethodSubtypeList(
|
final List<InputMethodSubtypeCompatWrapper> myImsList = getEnabledInputMethodSubtypeList(
|
||||||
myImi, true);
|
myImi, true);
|
||||||
final InputMethodSubtypeCompatWrapper currentIms = getCurrentInputMethodSubtype();
|
final InputMethodSubtypeCompatWrapper currentIms = getCurrentInputMethodSubtype();
|
||||||
|
|
|
@ -61,8 +61,8 @@ import com.android.inputmethod.latin.LatinIME;
|
||||||
import com.android.inputmethod.latin.LatinIME.UIHandler;
|
import com.android.inputmethod.latin.LatinIME.UIHandler;
|
||||||
import com.android.inputmethod.latin.LatinImeLogger;
|
import com.android.inputmethod.latin.LatinImeLogger;
|
||||||
import com.android.inputmethod.latin.R;
|
import com.android.inputmethod.latin.R;
|
||||||
|
import com.android.inputmethod.latin.StringUtils;
|
||||||
import com.android.inputmethod.latin.SubtypeSwitcher;
|
import com.android.inputmethod.latin.SubtypeSwitcher;
|
||||||
import com.android.inputmethod.latin.SuggestedWords;
|
|
||||||
import com.android.inputmethod.latin.Utils;
|
import com.android.inputmethod.latin.Utils;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
@ -662,9 +662,9 @@ public class VoiceProxy implements VoiceInput.UiListener {
|
||||||
|
|
||||||
private boolean shouldShowVoiceButton(FieldContext fieldContext, EditorInfo editorInfo) {
|
private boolean shouldShowVoiceButton(FieldContext fieldContext, EditorInfo editorInfo) {
|
||||||
@SuppressWarnings("deprecation")
|
@SuppressWarnings("deprecation")
|
||||||
final boolean noMic = Utils.inPrivateImeOptions(null,
|
final boolean noMic = StringUtils.inPrivateImeOptions(null,
|
||||||
LatinIME.IME_OPTION_NO_MICROPHONE_COMPAT, editorInfo)
|
LatinIME.IME_OPTION_NO_MICROPHONE_COMPAT, editorInfo)
|
||||||
|| Utils.inPrivateImeOptions(mService.getPackageName(),
|
|| StringUtils.inPrivateImeOptions(mService.getPackageName(),
|
||||||
LatinIME.IME_OPTION_NO_MICROPHONE, editorInfo);
|
LatinIME.IME_OPTION_NO_MICROPHONE, editorInfo);
|
||||||
return ENABLE_VOICE_BUTTON && fieldCanDoVoice(fieldContext) && !noMic
|
return ENABLE_VOICE_BUTTON && fieldCanDoVoice(fieldContext) && !noMic
|
||||||
&& SpeechRecognizer.isRecognitionAvailable(mService);
|
&& SpeechRecognizer.isRecognitionAvailable(mService);
|
||||||
|
|
|
@ -16,16 +16,6 @@
|
||||||
|
|
||||||
package com.android.inputmethod.deprecated.languageswitcher;
|
package com.android.inputmethod.deprecated.languageswitcher;
|
||||||
|
|
||||||
import com.android.inputmethod.compat.SharedPreferencesCompat;
|
|
||||||
import com.android.inputmethod.keyboard.KeyboardSet;
|
|
||||||
import com.android.inputmethod.latin.DictionaryFactory;
|
|
||||||
import com.android.inputmethod.latin.LocaleUtils;
|
|
||||||
import com.android.inputmethod.latin.R;
|
|
||||||
import com.android.inputmethod.latin.Settings;
|
|
||||||
import com.android.inputmethod.latin.Utils;
|
|
||||||
|
|
||||||
import org.xmlpull.v1.XmlPullParserException;
|
|
||||||
|
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.content.SharedPreferences.Editor;
|
import android.content.SharedPreferences.Editor;
|
||||||
import android.content.res.Resources;
|
import android.content.res.Resources;
|
||||||
|
@ -37,6 +27,16 @@ import android.preference.PreferenceManager;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.util.Pair;
|
import android.util.Pair;
|
||||||
|
|
||||||
|
import com.android.inputmethod.compat.SharedPreferencesCompat;
|
||||||
|
import com.android.inputmethod.keyboard.KeyboardSet;
|
||||||
|
import com.android.inputmethod.latin.DictionaryFactory;
|
||||||
|
import com.android.inputmethod.latin.LocaleUtils;
|
||||||
|
import com.android.inputmethod.latin.R;
|
||||||
|
import com.android.inputmethod.latin.Settings;
|
||||||
|
import com.android.inputmethod.latin.StringUtils;
|
||||||
|
|
||||||
|
import org.xmlpull.v1.XmlPullParserException;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.text.Collator;
|
import java.text.Collator;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
@ -237,12 +237,12 @@ public class InputLanguageSelection extends PreferenceActivity {
|
||||||
|
|
||||||
if (finalSize == 0) {
|
if (finalSize == 0) {
|
||||||
preprocess[finalSize++] =
|
preprocess[finalSize++] =
|
||||||
new LocaleEntry(Utils.getFullDisplayName(l, false), l);
|
new LocaleEntry(StringUtils.getFullDisplayName(l, false), l);
|
||||||
} else {
|
} else {
|
||||||
if (s.equals("zz_ZZ")) {
|
if (s.equals("zz_ZZ")) {
|
||||||
// ignore this locale
|
// ignore this locale
|
||||||
} else {
|
} else {
|
||||||
final String displayName = Utils.getFullDisplayName(l, false);
|
final String displayName = StringUtils.getFullDisplayName(l, false);
|
||||||
preprocess[finalSize++] = new LocaleEntry(displayName, l);
|
preprocess[finalSize++] = new LocaleEntry(displayName, l);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,10 +16,6 @@
|
||||||
|
|
||||||
package com.android.inputmethod.deprecated.voice;
|
package com.android.inputmethod.deprecated.voice;
|
||||||
|
|
||||||
import com.android.inputmethod.latin.R;
|
|
||||||
import com.android.inputmethod.latin.SubtypeSwitcher;
|
|
||||||
import com.android.inputmethod.latin.Utils;
|
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.res.Resources;
|
import android.content.res.Resources;
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
|
@ -39,6 +35,10 @@ import android.widget.ImageView;
|
||||||
import android.widget.ProgressBar;
|
import android.widget.ProgressBar;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import com.android.inputmethod.latin.R;
|
||||||
|
import com.android.inputmethod.latin.StringUtils;
|
||||||
|
import com.android.inputmethod.latin.SubtypeSwitcher;
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.ByteOrder;
|
import java.nio.ByteOrder;
|
||||||
|
@ -222,7 +222,7 @@ public class RecognitionView {
|
||||||
Locale locale = SubtypeSwitcher.getInstance().getInputLocale();
|
Locale locale = SubtypeSwitcher.getInstance().getInputLocale();
|
||||||
|
|
||||||
mLanguage.setVisibility(View.VISIBLE);
|
mLanguage.setVisibility(View.VISIBLE);
|
||||||
mLanguage.setText(Utils.getFullDisplayName(locale, true));
|
mLanguage.setText(StringUtils.getFullDisplayName(locale, true));
|
||||||
|
|
||||||
mPopupLayout.setBackgroundDrawable(mListeningBorder);
|
mPopupLayout.setBackgroundDrawable(mListeningBorder);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -30,7 +30,7 @@ import com.android.inputmethod.keyboard.internal.KeyStyles;
|
||||||
import com.android.inputmethod.keyboard.internal.KeyStyles.KeyStyle;
|
import com.android.inputmethod.keyboard.internal.KeyStyles.KeyStyle;
|
||||||
import com.android.inputmethod.keyboard.internal.KeyboardIconsSet;
|
import com.android.inputmethod.keyboard.internal.KeyboardIconsSet;
|
||||||
import com.android.inputmethod.latin.R;
|
import com.android.inputmethod.latin.R;
|
||||||
import com.android.inputmethod.latin.Utils;
|
import com.android.inputmethod.latin.StringUtils;
|
||||||
import com.android.inputmethod.latin.XmlParseUtils;
|
import com.android.inputmethod.latin.XmlParseUtils;
|
||||||
|
|
||||||
import org.xmlpull.v1.XmlPullParser;
|
import org.xmlpull.v1.XmlPullParser;
|
||||||
|
@ -293,7 +293,7 @@ public class Key {
|
||||||
// Choose the first letter of the label as primary code if not specified.
|
// Choose the first letter of the label as primary code if not specified.
|
||||||
if (code == Keyboard.CODE_UNSPECIFIED && TextUtils.isEmpty(outputText)
|
if (code == Keyboard.CODE_UNSPECIFIED && TextUtils.isEmpty(outputText)
|
||||||
&& !TextUtils.isEmpty(mLabel)) {
|
&& !TextUtils.isEmpty(mLabel)) {
|
||||||
if (Utils.codePointCount(mLabel) == 1) {
|
if (StringUtils.codePointCount(mLabel) == 1) {
|
||||||
// Use the first letter of the hint label if shiftedLetterActivated flag is
|
// Use the first letter of the hint label if shiftedLetterActivated flag is
|
||||||
// specified.
|
// specified.
|
||||||
if (hasShiftedLetterHint() && isShiftedLetterActivated()
|
if (hasShiftedLetterHint() && isShiftedLetterActivated()
|
||||||
|
@ -309,7 +309,7 @@ public class Key {
|
||||||
mCode = Keyboard.CODE_OUTPUT_TEXT;
|
mCode = Keyboard.CODE_OUTPUT_TEXT;
|
||||||
}
|
}
|
||||||
} else if (code == Keyboard.CODE_UNSPECIFIED && outputText != null) {
|
} else if (code == Keyboard.CODE_UNSPECIFIED && outputText != null) {
|
||||||
if (Utils.codePointCount(outputText) == 1) {
|
if (StringUtils.codePointCount(outputText) == 1) {
|
||||||
mCode = outputText.codePointAt(0);
|
mCode = outputText.codePointAt(0);
|
||||||
outputText = null;
|
outputText = null;
|
||||||
} else {
|
} else {
|
||||||
|
@ -336,7 +336,7 @@ public class Key {
|
||||||
if (!Keyboard.isLetterCode(code) || preserveCase) return code;
|
if (!Keyboard.isLetterCode(code) || preserveCase) return code;
|
||||||
final String text = new String(new int[] { code } , 0, 1);
|
final String text = new String(new int[] { code } , 0, 1);
|
||||||
final String casedText = adjustCaseOfStringForKeyboardId(text, preserveCase, id);
|
final String casedText = adjustCaseOfStringForKeyboardId(text, preserveCase, id);
|
||||||
return Utils.codePointCount(casedText) == 1
|
return StringUtils.codePointCount(casedText) == 1
|
||||||
? casedText.codePointAt(0) : Keyboard.CODE_UNSPECIFIED;
|
? casedText.codePointAt(0) : Keyboard.CODE_UNSPECIFIED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -484,7 +484,7 @@ public class Key {
|
||||||
}
|
}
|
||||||
|
|
||||||
public int selectTextSize(int letter, int largeLetter, int label, int hintLabel) {
|
public int selectTextSize(int letter, int largeLetter, int label, int hintLabel) {
|
||||||
if (Utils.codePointCount(mLabel) > 1
|
if (StringUtils.codePointCount(mLabel) > 1
|
||||||
&& (mLabelFlags & (LABEL_FLAGS_FOLLOW_KEY_LETTER_RATIO
|
&& (mLabelFlags & (LABEL_FLAGS_FOLLOW_KEY_LETTER_RATIO
|
||||||
| LABEL_FLAGS_FOLLOW_KEY_HINT_LABEL_RATIO)) == 0) {
|
| LABEL_FLAGS_FOLLOW_KEY_HINT_LABEL_RATIO)) == 0) {
|
||||||
return label;
|
return label;
|
||||||
|
|
|
@ -21,16 +21,18 @@ import android.content.res.Configuration;
|
||||||
import android.content.res.Resources;
|
import android.content.res.Resources;
|
||||||
import android.content.res.TypedArray;
|
import android.content.res.TypedArray;
|
||||||
import android.content.res.XmlResourceParser;
|
import android.content.res.XmlResourceParser;
|
||||||
|
import android.text.InputType;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.util.Xml;
|
import android.util.Xml;
|
||||||
import android.view.inputmethod.EditorInfo;
|
import android.view.inputmethod.EditorInfo;
|
||||||
|
|
||||||
import com.android.inputmethod.compat.EditorInfoCompatUtils;
|
import com.android.inputmethod.compat.EditorInfoCompatUtils;
|
||||||
|
import com.android.inputmethod.compat.InputTypeCompatUtils;
|
||||||
import com.android.inputmethod.latin.LatinIME;
|
import com.android.inputmethod.latin.LatinIME;
|
||||||
import com.android.inputmethod.latin.LatinImeLogger;
|
import com.android.inputmethod.latin.LatinImeLogger;
|
||||||
import com.android.inputmethod.latin.LocaleUtils;
|
import com.android.inputmethod.latin.LocaleUtils;
|
||||||
import com.android.inputmethod.latin.R;
|
import com.android.inputmethod.latin.R;
|
||||||
import com.android.inputmethod.latin.Utils;
|
import com.android.inputmethod.latin.StringUtils;
|
||||||
import com.android.inputmethod.latin.XmlParseUtils;
|
import com.android.inputmethod.latin.XmlParseUtils;
|
||||||
|
|
||||||
import org.xmlpull.v1.XmlPullParser;
|
import org.xmlpull.v1.XmlPullParser;
|
||||||
|
@ -215,9 +217,9 @@ public class KeyboardSet {
|
||||||
mEditorInfo = editorInfo;
|
mEditorInfo = editorInfo;
|
||||||
final Params params = mParams;
|
final Params params = mParams;
|
||||||
|
|
||||||
params.mMode = Utils.getKeyboardMode(editorInfo);
|
params.mMode = getKeyboardMode(editorInfo);
|
||||||
params.mEditorInfo = (editorInfo != null) ? editorInfo : EMPTY_EDITOR_INFO;
|
params.mEditorInfo = (editorInfo != null) ? editorInfo : EMPTY_EDITOR_INFO;
|
||||||
params.mNoSettingsKey = Utils.inPrivateImeOptions(
|
params.mNoSettingsKey = StringUtils.inPrivateImeOptions(
|
||||||
mPackageName, LatinIME.IME_OPTION_NO_SETTINGS_KEY, mEditorInfo);
|
mPackageName, LatinIME.IME_OPTION_NO_SETTINGS_KEY, mEditorInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -230,7 +232,7 @@ public class KeyboardSet {
|
||||||
// TODO: Use InputMethodSubtype object as argument.
|
// TODO: Use InputMethodSubtype object as argument.
|
||||||
public Builder setSubtype(Locale inputLocale, boolean asciiCapable,
|
public Builder setSubtype(Locale inputLocale, boolean asciiCapable,
|
||||||
boolean touchPositionCorrectionEnabled) {
|
boolean touchPositionCorrectionEnabled) {
|
||||||
final boolean deprecatedForceAscii = Utils.inPrivateImeOptions(
|
final boolean deprecatedForceAscii = StringUtils.inPrivateImeOptions(
|
||||||
mPackageName, LatinIME.IME_OPTION_FORCE_ASCII, mEditorInfo);
|
mPackageName, LatinIME.IME_OPTION_FORCE_ASCII, mEditorInfo);
|
||||||
final boolean forceAscii = EditorInfoCompatUtils.hasFlagForceAscii(
|
final boolean forceAscii = EditorInfoCompatUtils.hasFlagForceAscii(
|
||||||
mParams.mEditorInfo.imeOptions)
|
mParams.mEditorInfo.imeOptions)
|
||||||
|
@ -243,9 +245,9 @@ public class KeyboardSet {
|
||||||
public Builder setOptions(boolean voiceKeyEnabled, boolean voiceKeyOnMain,
|
public Builder setOptions(boolean voiceKeyEnabled, boolean voiceKeyOnMain,
|
||||||
boolean languageSwitchKeyEnabled) {
|
boolean languageSwitchKeyEnabled) {
|
||||||
@SuppressWarnings("deprecation")
|
@SuppressWarnings("deprecation")
|
||||||
final boolean deprecatedNoMicrophone = Utils.inPrivateImeOptions(
|
final boolean deprecatedNoMicrophone = StringUtils.inPrivateImeOptions(
|
||||||
null, LatinIME.IME_OPTION_NO_MICROPHONE_COMPAT, mEditorInfo);
|
null, LatinIME.IME_OPTION_NO_MICROPHONE_COMPAT, mEditorInfo);
|
||||||
final boolean noMicrophone = Utils.inPrivateImeOptions(
|
final boolean noMicrophone = StringUtils.inPrivateImeOptions(
|
||||||
mPackageName, LatinIME.IME_OPTION_NO_MICROPHONE, mEditorInfo)
|
mPackageName, LatinIME.IME_OPTION_NO_MICROPHONE, mEditorInfo)
|
||||||
|| deprecatedNoMicrophone;
|
|| deprecatedNoMicrophone;
|
||||||
mParams.mVoiceKeyEnabled = voiceKeyEnabled && !noMicrophone;
|
mParams.mVoiceKeyEnabled = voiceKeyEnabled && !noMicrophone;
|
||||||
|
@ -337,6 +339,44 @@ public class KeyboardSet {
|
||||||
a.recycle();
|
a.recycle();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static int getKeyboardMode(EditorInfo editorInfo) {
|
||||||
|
if (editorInfo == null)
|
||||||
|
return KeyboardId.MODE_TEXT;
|
||||||
|
|
||||||
|
final int inputType = editorInfo.inputType;
|
||||||
|
final int variation = inputType & InputType.TYPE_MASK_VARIATION;
|
||||||
|
|
||||||
|
switch (inputType & InputType.TYPE_MASK_CLASS) {
|
||||||
|
case InputType.TYPE_CLASS_NUMBER:
|
||||||
|
return KeyboardId.MODE_NUMBER;
|
||||||
|
case InputType.TYPE_CLASS_DATETIME:
|
||||||
|
switch (variation) {
|
||||||
|
case InputType.TYPE_DATETIME_VARIATION_DATE:
|
||||||
|
return KeyboardId.MODE_DATE;
|
||||||
|
case InputType.TYPE_DATETIME_VARIATION_TIME:
|
||||||
|
return KeyboardId.MODE_TIME;
|
||||||
|
default: // InputType.TYPE_DATETIME_VARIATION_NORMAL
|
||||||
|
return KeyboardId.MODE_DATETIME;
|
||||||
|
}
|
||||||
|
case InputType.TYPE_CLASS_PHONE:
|
||||||
|
return KeyboardId.MODE_PHONE;
|
||||||
|
case InputType.TYPE_CLASS_TEXT:
|
||||||
|
if (InputTypeCompatUtils.isEmailVariation(variation)) {
|
||||||
|
return KeyboardId.MODE_EMAIL;
|
||||||
|
} else if (variation == InputType.TYPE_TEXT_VARIATION_URI) {
|
||||||
|
return KeyboardId.MODE_URL;
|
||||||
|
} else if (variation == InputType.TYPE_TEXT_VARIATION_SHORT_MESSAGE) {
|
||||||
|
return KeyboardId.MODE_IM;
|
||||||
|
} else if (variation == InputType.TYPE_TEXT_VARIATION_FILTER) {
|
||||||
|
return KeyboardId.MODE_TEXT;
|
||||||
|
} else {
|
||||||
|
return KeyboardId.MODE_TEXT;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return KeyboardId.MODE_TEXT;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String parseKeyboardLocale(Resources res, int resId)
|
public static String parseKeyboardLocale(Resources res, int resId)
|
||||||
|
|
|
@ -41,7 +41,7 @@ import com.android.inputmethod.compat.FrameLayoutCompatUtils;
|
||||||
import com.android.inputmethod.latin.LatinImeLogger;
|
import com.android.inputmethod.latin.LatinImeLogger;
|
||||||
import com.android.inputmethod.latin.R;
|
import com.android.inputmethod.latin.R;
|
||||||
import com.android.inputmethod.latin.StaticInnerHandlerWrapper;
|
import com.android.inputmethod.latin.StaticInnerHandlerWrapper;
|
||||||
import com.android.inputmethod.latin.Utils;
|
import com.android.inputmethod.latin.StringUtils;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
@ -853,7 +853,7 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy {
|
||||||
if (key.mLabel != null) {
|
if (key.mLabel != null) {
|
||||||
// TODO Should take care of temporaryShiftLabel here.
|
// TODO Should take care of temporaryShiftLabel here.
|
||||||
previewText.setCompoundDrawables(null, null, null, null);
|
previewText.setCompoundDrawables(null, null, null, null);
|
||||||
if (Utils.codePointCount(key.mLabel) > 1) {
|
if (StringUtils.codePointCount(key.mLabel) > 1) {
|
||||||
previewText.setTextSize(TypedValue.COMPLEX_UNIT_PX, params.mKeyLetterSize);
|
previewText.setTextSize(TypedValue.COMPLEX_UNIT_PX, params.mKeyLetterSize);
|
||||||
previewText.setTypeface(Typeface.DEFAULT_BOLD);
|
previewText.setTypeface(Typeface.DEFAULT_BOLD);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -46,6 +46,8 @@ import com.android.inputmethod.latin.LatinIME;
|
||||||
import com.android.inputmethod.latin.LatinImeLogger;
|
import com.android.inputmethod.latin.LatinImeLogger;
|
||||||
import com.android.inputmethod.latin.R;
|
import com.android.inputmethod.latin.R;
|
||||||
import com.android.inputmethod.latin.StaticInnerHandlerWrapper;
|
import com.android.inputmethod.latin.StaticInnerHandlerWrapper;
|
||||||
|
import com.android.inputmethod.latin.StringUtils;
|
||||||
|
import com.android.inputmethod.latin.SubtypeUtils;
|
||||||
import com.android.inputmethod.latin.Utils;
|
import com.android.inputmethod.latin.Utils;
|
||||||
import com.android.inputmethod.latin.Utils.UsabilityStudyLogUtils;
|
import com.android.inputmethod.latin.Utils.UsabilityStudyLogUtils;
|
||||||
|
|
||||||
|
@ -779,12 +781,13 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke
|
||||||
|
|
||||||
// Whether space key needs to show the "..." popup hint for special purposes
|
// Whether space key needs to show the "..." popup hint for special purposes
|
||||||
if (mIsSpacebarTriggeringPopupByLongPress
|
if (mIsSpacebarTriggeringPopupByLongPress
|
||||||
&& Utils.hasMultipleEnabledIMEsOrSubtypes(true /* include aux subtypes */)) {
|
&& SubtypeUtils.hasMultipleEnabledIMEsOrSubtypes(
|
||||||
|
true /* include aux subtypes */)) {
|
||||||
drawKeyPopupHint(key, canvas, paint, params);
|
drawKeyPopupHint(key, canvas, paint, params);
|
||||||
}
|
}
|
||||||
} else if (key.mCode == Keyboard.CODE_LANGUAGE_SWITCH) {
|
} else if (key.mCode == Keyboard.CODE_LANGUAGE_SWITCH) {
|
||||||
super.onDrawKeyTopVisuals(key, canvas, paint, params);
|
super.onDrawKeyTopVisuals(key, canvas, paint, params);
|
||||||
if (Utils.hasMultipleEnabledIMEsOrSubtypes(true /* include aux subtypes */)) {
|
if (SubtypeUtils.hasMultipleEnabledIMEsOrSubtypes(true /* include aux subtypes */)) {
|
||||||
drawKeyPopupHint(key, canvas, paint, params);
|
drawKeyPopupHint(key, canvas, paint, params);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -810,7 +813,7 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke
|
||||||
paint.setTextAlign(Align.CENTER);
|
paint.setTextAlign(Align.CENTER);
|
||||||
paint.setTypeface(Typeface.DEFAULT);
|
paint.setTypeface(Typeface.DEFAULT);
|
||||||
// Estimate appropriate language name text size to fit in maxTextWidth.
|
// Estimate appropriate language name text size to fit in maxTextWidth.
|
||||||
String language = Utils.getFullDisplayName(locale, true);
|
String language = StringUtils.getFullDisplayName(locale, true);
|
||||||
int textWidth = getTextWidth(paint, language, origTextSize);
|
int textWidth = getTextWidth(paint, language, origTextSize);
|
||||||
// Assuming text width and text size are proportional to each other.
|
// Assuming text width and text size are proportional to each other.
|
||||||
float textSize = origTextSize * Math.min(width / textWidth, 1.0f);
|
float textSize = origTextSize * Math.min(width / textWidth, 1.0f);
|
||||||
|
@ -822,7 +825,7 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke
|
||||||
|
|
||||||
final boolean useShortName;
|
final boolean useShortName;
|
||||||
if (useMiddleName) {
|
if (useMiddleName) {
|
||||||
language = Utils.getMiddleDisplayLanguage(locale);
|
language = StringUtils.getMiddleDisplayLanguage(locale);
|
||||||
textWidth = getTextWidth(paint, language, origTextSize);
|
textWidth = getTextWidth(paint, language, origTextSize);
|
||||||
textSize = origTextSize * Math.min(width / textWidth, 1.0f);
|
textSize = origTextSize * Math.min(width / textWidth, 1.0f);
|
||||||
useShortName = (textSize / origTextSize < MINIMUM_SCALE_OF_LANGUAGE_NAME)
|
useShortName = (textSize / origTextSize < MINIMUM_SCALE_OF_LANGUAGE_NAME)
|
||||||
|
@ -832,7 +835,7 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke
|
||||||
}
|
}
|
||||||
|
|
||||||
if (useShortName) {
|
if (useShortName) {
|
||||||
language = Utils.getShortDisplayLanguage(locale);
|
language = StringUtils.getShortDisplayLanguage(locale);
|
||||||
textWidth = getTextWidth(paint, language, origTextSize);
|
textWidth = getTextWidth(paint, language, origTextSize);
|
||||||
textSize = origTextSize * Math.min(width / textWidth, 1.0f);
|
textSize = origTextSize * Math.min(width / textWidth, 1.0f);
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,7 @@ import android.graphics.drawable.Drawable;
|
||||||
import com.android.inputmethod.keyboard.internal.KeySpecParser;
|
import com.android.inputmethod.keyboard.internal.KeySpecParser;
|
||||||
import com.android.inputmethod.keyboard.internal.KeyboardIconsSet;
|
import com.android.inputmethod.keyboard.internal.KeyboardIconsSet;
|
||||||
import com.android.inputmethod.latin.R;
|
import com.android.inputmethod.latin.R;
|
||||||
import com.android.inputmethod.latin.Utils;
|
import com.android.inputmethod.latin.StringUtils;
|
||||||
|
|
||||||
public class MoreKeysKeyboard extends Keyboard {
|
public class MoreKeysKeyboard extends Keyboard {
|
||||||
private final int mDefaultKeyCoordX;
|
private final int mDefaultKeyCoordX;
|
||||||
|
@ -301,7 +301,7 @@ public class MoreKeysKeyboard extends Keyboard {
|
||||||
for (String moreKeySpec : parentKey.mMoreKeys) {
|
for (String moreKeySpec : parentKey.mMoreKeys) {
|
||||||
final String label = KeySpecParser.getLabel(moreKeySpec);
|
final String label = KeySpecParser.getLabel(moreKeySpec);
|
||||||
// If the label is single letter, minKeyWidth is enough to hold the label.
|
// If the label is single letter, minKeyWidth is enough to hold the label.
|
||||||
if (label != null && Utils.codePointCount(label) > 1) {
|
if (label != null && StringUtils.codePointCount(label) > 1) {
|
||||||
if (paint == null) {
|
if (paint == null) {
|
||||||
paint = new Paint();
|
paint = new Paint();
|
||||||
paint.setAntiAlias(true);
|
paint.setAntiAlias(true);
|
||||||
|
|
|
@ -19,7 +19,7 @@ package com.android.inputmethod.keyboard;
|
||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
|
|
||||||
import com.android.inputmethod.keyboard.Keyboard.Params.TouchPositionCorrection;
|
import com.android.inputmethod.keyboard.Keyboard.Params.TouchPositionCorrection;
|
||||||
import com.android.inputmethod.latin.Utils;
|
import com.android.inputmethod.latin.JniUtils;
|
||||||
import com.android.inputmethod.latin.spellcheck.SpellCheckerProximityInfo;
|
import com.android.inputmethod.latin.spellcheck.SpellCheckerProximityInfo;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
@ -81,7 +81,7 @@ public class ProximityInfo {
|
||||||
|
|
||||||
private long mNativeProximityInfo;
|
private long mNativeProximityInfo;
|
||||||
static {
|
static {
|
||||||
Utils.loadNativeLibrary();
|
JniUtils.loadNativeLibrary();
|
||||||
}
|
}
|
||||||
|
|
||||||
private native long setProximityInfoNative(int maxProximityCharsSize, int displayWidth,
|
private native long setProximityInfoNative(int maxProximityCharsSize, int displayWidth,
|
||||||
|
|
|
@ -22,7 +22,7 @@ import android.text.TextUtils;
|
||||||
import com.android.inputmethod.keyboard.Keyboard;
|
import com.android.inputmethod.keyboard.Keyboard;
|
||||||
import com.android.inputmethod.latin.LatinImeLogger;
|
import com.android.inputmethod.latin.LatinImeLogger;
|
||||||
import com.android.inputmethod.latin.R;
|
import com.android.inputmethod.latin.R;
|
||||||
import com.android.inputmethod.latin.Utils;
|
import com.android.inputmethod.latin.StringUtils;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
@ -150,7 +150,7 @@ public class KeySpecParser {
|
||||||
}
|
}
|
||||||
final String outputText = getOutputTextInternal(moreKeySpec);
|
final String outputText = getOutputTextInternal(moreKeySpec);
|
||||||
if (outputText != null) {
|
if (outputText != null) {
|
||||||
if (Utils.codePointCount(outputText) == 1) {
|
if (StringUtils.codePointCount(outputText) == 1) {
|
||||||
// If output text is one code point, it should be treated as a code.
|
// If output text is one code point, it should be treated as a code.
|
||||||
// See {@link #getCode(Resources, String)}.
|
// See {@link #getCode(Resources, String)}.
|
||||||
return null;
|
return null;
|
||||||
|
@ -165,7 +165,7 @@ public class KeySpecParser {
|
||||||
throw new KeySpecParserError("Empty label: " + moreKeySpec);
|
throw new KeySpecParserError("Empty label: " + moreKeySpec);
|
||||||
}
|
}
|
||||||
// Code is automatically generated for one letter label. See {@link getCode()}.
|
// Code is automatically generated for one letter label. See {@link getCode()}.
|
||||||
return (Utils.codePointCount(label) == 1) ? null : label;
|
return (StringUtils.codePointCount(label) == 1) ? null : label;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int getCode(Resources res, String moreKeySpec) {
|
public static int getCode(Resources res, String moreKeySpec) {
|
||||||
|
@ -184,14 +184,14 @@ public class KeySpecParser {
|
||||||
if (outputText != null) {
|
if (outputText != null) {
|
||||||
// If output text is one code point, it should be treated as a code.
|
// If output text is one code point, it should be treated as a code.
|
||||||
// See {@link #getOutputText(String)}.
|
// See {@link #getOutputText(String)}.
|
||||||
if (Utils.codePointCount(outputText) == 1) {
|
if (StringUtils.codePointCount(outputText) == 1) {
|
||||||
return outputText.codePointAt(0);
|
return outputText.codePointAt(0);
|
||||||
}
|
}
|
||||||
return Keyboard.CODE_OUTPUT_TEXT;
|
return Keyboard.CODE_OUTPUT_TEXT;
|
||||||
}
|
}
|
||||||
final String label = getLabel(moreKeySpec);
|
final String label = getLabel(moreKeySpec);
|
||||||
// Code is automatically generated for one letter label.
|
// Code is automatically generated for one letter label.
|
||||||
if (Utils.codePointCount(label) == 1) {
|
if (StringUtils.codePointCount(label) == 1) {
|
||||||
return label.codePointAt(0);
|
return label.codePointAt(0);
|
||||||
}
|
}
|
||||||
return Keyboard.CODE_OUTPUT_TEXT;
|
return Keyboard.CODE_OUTPUT_TEXT;
|
||||||
|
@ -393,7 +393,7 @@ public class KeySpecParser {
|
||||||
if (size == 0) {
|
if (size == 0) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if (Utils.codePointCount(text) == 1) {
|
if (StringUtils.codePointCount(text) == 1) {
|
||||||
return text.codePointAt(0) == COMMA ? null : new String[] { text };
|
return text.codePointAt(0) == COMMA ? null : new String[] { text };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -104,7 +104,7 @@ public class BinaryDictionary extends Dictionary {
|
||||||
}
|
}
|
||||||
|
|
||||||
static {
|
static {
|
||||||
Utils.loadNativeLibrary();
|
JniUtils.loadNativeLibrary();
|
||||||
}
|
}
|
||||||
|
|
||||||
private native long openNative(String sourceDir, long dictOffset, long dictSize,
|
private native long openNative(String sourceDir, long dictOffset, long dictSize,
|
||||||
|
|
|
@ -164,7 +164,7 @@ public class DictionaryFactory {
|
||||||
final Resources res = context.getResources();
|
final Resources res = context.getResources();
|
||||||
final Locale saveLocale = LocaleUtils.setSystemLocale(res, locale);
|
final Locale saveLocale = LocaleUtils.setSystemLocale(res, locale);
|
||||||
|
|
||||||
final int resourceId = Utils.getMainDictionaryResourceId(res);
|
final int resourceId = getMainDictionaryResourceId(res);
|
||||||
final AssetFileDescriptor afd = res.openRawResourceFd(resourceId);
|
final AssetFileDescriptor afd = res.openRawResourceFd(resourceId);
|
||||||
final boolean hasDictionary = isFullDictionary(afd);
|
final boolean hasDictionary = isFullDictionary(afd);
|
||||||
try {
|
try {
|
||||||
|
@ -182,7 +182,7 @@ public class DictionaryFactory {
|
||||||
final Resources res = context.getResources();
|
final Resources res = context.getResources();
|
||||||
final Locale saveLocale = LocaleUtils.setSystemLocale(res, locale);
|
final Locale saveLocale = LocaleUtils.setSystemLocale(res, locale);
|
||||||
|
|
||||||
final int resourceId = Utils.getMainDictionaryResourceId(res);
|
final int resourceId = getMainDictionaryResourceId(res);
|
||||||
final AssetFileDescriptor afd = res.openRawResourceFd(resourceId);
|
final AssetFileDescriptor afd = res.openRawResourceFd(resourceId);
|
||||||
final Long size = (afd != null && afd.getLength() > PLACEHOLDER_LENGTH)
|
final Long size = (afd != null && afd.getLength() > PLACEHOLDER_LENGTH)
|
||||||
? afd.getLength()
|
? afd.getLength()
|
||||||
|
@ -209,4 +209,14 @@ public class DictionaryFactory {
|
||||||
protected static boolean isFullDictionary(final AssetFileDescriptor afd) {
|
protected static boolean isFullDictionary(final AssetFileDescriptor afd) {
|
||||||
return (afd != null && afd.getLength() > PLACEHOLDER_LENGTH);
|
return (afd != null && afd.getLength() > PLACEHOLDER_LENGTH);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a main dictionary resource id
|
||||||
|
* @return main dictionary resource id
|
||||||
|
*/
|
||||||
|
public static int getMainDictionaryResourceId(Resources res) {
|
||||||
|
final String MAIN_DIC_NAME = "main";
|
||||||
|
String packageName = LatinIME.class.getPackage().getName();
|
||||||
|
return res.getIdentifier(MAIN_DIC_NAME, "raw", packageName);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,41 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2012 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.util.Log;
|
||||||
|
|
||||||
|
import com.android.inputmethod.latin.define.JniLibName;
|
||||||
|
|
||||||
|
public class JniUtils {
|
||||||
|
private static final String TAG = JniUtils.class.getSimpleName();
|
||||||
|
|
||||||
|
private JniUtils() {
|
||||||
|
// This utility class is not publicly instantiable.
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void loadNativeLibrary() {
|
||||||
|
try {
|
||||||
|
System.loadLibrary(JniLibName.JNI_LIB_NAME);
|
||||||
|
} catch (UnsatisfiedLinkError ule) {
|
||||||
|
Log.e(TAG, "Could not load native library " + JniLibName.JNI_LIB_NAME);
|
||||||
|
if (LatinImeLogger.sDBG) {
|
||||||
|
throw new RuntimeException(
|
||||||
|
"Could not load native library " + JniLibName.JNI_LIB_NAME);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -44,8 +44,8 @@ import android.view.HapticFeedbackConstants;
|
||||||
import android.view.KeyEvent;
|
import android.view.KeyEvent;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.view.ViewParent;
|
|
||||||
import android.view.ViewGroup.LayoutParams;
|
import android.view.ViewGroup.LayoutParams;
|
||||||
|
import android.view.ViewParent;
|
||||||
import android.view.inputmethod.CompletionInfo;
|
import android.view.inputmethod.CompletionInfo;
|
||||||
import android.view.inputmethod.EditorInfo;
|
import android.view.inputmethod.EditorInfo;
|
||||||
import android.view.inputmethod.ExtractedText;
|
import android.view.inputmethod.ExtractedText;
|
||||||
|
@ -576,7 +576,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
|
||||||
oldContactsDictionary = null;
|
oldContactsDictionary = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
int mainDicResId = Utils.getMainDictionaryResourceId(res);
|
int mainDicResId = DictionaryFactory.getMainDictionaryResourceId(res);
|
||||||
mSuggest = new Suggest(this, mainDicResId, keyboardLocale);
|
mSuggest = new Suggest(this, mainDicResId, keyboardLocale);
|
||||||
if (mSettingsValues.mAutoCorrectEnabled) {
|
if (mSettingsValues.mAutoCorrectEnabled) {
|
||||||
mSuggest.setAutoCorrectionThreshold(mSettingsValues.mAutoCorrectionThreshold);
|
mSuggest.setAutoCorrectionThreshold(mSettingsValues.mAutoCorrectionThreshold);
|
||||||
|
@ -636,7 +636,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
|
||||||
/* package private */ void resetSuggestMainDict() {
|
/* package private */ void resetSuggestMainDict() {
|
||||||
final String localeStr = mSubtypeSwitcher.getInputLocaleStr();
|
final String localeStr = mSubtypeSwitcher.getInputLocaleStr();
|
||||||
final Locale keyboardLocale = LocaleUtils.constructLocaleFromString(localeStr);
|
final Locale keyboardLocale = LocaleUtils.constructLocaleFromString(localeStr);
|
||||||
int mainDicResId = Utils.getMainDictionaryResourceId(mResources);
|
int mainDicResId = DictionaryFactory.getMainDictionaryResourceId(mResources);
|
||||||
mSuggest.resetMainDict(this, mainDicResId, keyboardLocale);
|
mSuggest.resetMainDict(this, mainDicResId, keyboardLocale);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -745,12 +745,12 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
|
||||||
+ String.format("inputType=0x%08x imeOptions=0x%08x",
|
+ String.format("inputType=0x%08x imeOptions=0x%08x",
|
||||||
editorInfo.inputType, editorInfo.imeOptions));
|
editorInfo.inputType, editorInfo.imeOptions));
|
||||||
}
|
}
|
||||||
if (Utils.inPrivateImeOptions(null, IME_OPTION_NO_MICROPHONE_COMPAT, editorInfo)) {
|
if (StringUtils.inPrivateImeOptions(null, IME_OPTION_NO_MICROPHONE_COMPAT, editorInfo)) {
|
||||||
Log.w(TAG, "Deprecated private IME option specified: "
|
Log.w(TAG, "Deprecated private IME option specified: "
|
||||||
+ editorInfo.privateImeOptions);
|
+ editorInfo.privateImeOptions);
|
||||||
Log.w(TAG, "Use " + getPackageName() + "." + IME_OPTION_NO_MICROPHONE + " instead");
|
Log.w(TAG, "Use " + getPackageName() + "." + IME_OPTION_NO_MICROPHONE + " instead");
|
||||||
}
|
}
|
||||||
if (Utils.inPrivateImeOptions(getPackageName(), IME_OPTION_FORCE_ASCII, editorInfo)) {
|
if (StringUtils.inPrivateImeOptions(getPackageName(), IME_OPTION_FORCE_ASCII, editorInfo)) {
|
||||||
Log.w(TAG, "Deprecated private IME option specified: "
|
Log.w(TAG, "Deprecated private IME option specified: "
|
||||||
+ editorInfo.privateImeOptions);
|
+ editorInfo.privateImeOptions);
|
||||||
Log.w(TAG, "Use EditorInfo.IME_FLAG_FORCE_ASCII flag instead");
|
Log.w(TAG, "Use EditorInfo.IME_FLAG_FORCE_ASCII flag instead");
|
||||||
|
@ -1207,7 +1207,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
|
||||||
if (ic == null) return false;
|
if (ic == null) return false;
|
||||||
final CharSequence lastThree = ic.getTextBeforeCursor(3, 0);
|
final CharSequence lastThree = ic.getTextBeforeCursor(3, 0);
|
||||||
if (lastThree != null && lastThree.length() == 3
|
if (lastThree != null && lastThree.length() == 3
|
||||||
&& Utils.canBeFollowedByPeriod(lastThree.charAt(0))
|
&& StringUtils.canBeFollowedByPeriod(lastThree.charAt(0))
|
||||||
&& lastThree.charAt(1) == Keyboard.CODE_SPACE
|
&& lastThree.charAt(1) == Keyboard.CODE_SPACE
|
||||||
&& lastThree.charAt(2) == Keyboard.CODE_SPACE
|
&& lastThree.charAt(2) == Keyboard.CODE_SPACE
|
||||||
&& mHandler.isAcceptingDoubleSpaces()) {
|
&& mHandler.isAcceptingDoubleSpaces()) {
|
||||||
|
@ -1247,7 +1247,8 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
|
||||||
if (isShowingOptionDialog()) return;
|
if (isShowingOptionDialog()) return;
|
||||||
if (InputMethodServiceCompatWrapper.CAN_HANDLE_ON_CURRENT_INPUT_METHOD_SUBTYPE_CHANGED) {
|
if (InputMethodServiceCompatWrapper.CAN_HANDLE_ON_CURRENT_INPUT_METHOD_SUBTYPE_CHANGED) {
|
||||||
showSubtypeSelectorAndSettings();
|
showSubtypeSelectorAndSettings();
|
||||||
} else if (Utils.hasMultipleEnabledIMEsOrSubtypes(false /* exclude aux subtypes */)) {
|
} else if (SubtypeUtils.hasMultipleEnabledIMEsOrSubtypes(
|
||||||
|
false /* exclude aux subtypes */)) {
|
||||||
showOptionsMenu();
|
showOptionsMenu();
|
||||||
} else {
|
} else {
|
||||||
launchSettings();
|
launchSettings();
|
||||||
|
@ -1263,7 +1264,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
|
||||||
if (isShowingOptionDialog()) return false;
|
if (isShowingOptionDialog()) return false;
|
||||||
switch (requestCode) {
|
switch (requestCode) {
|
||||||
case CODE_SHOW_INPUT_METHOD_PICKER:
|
case CODE_SHOW_INPUT_METHOD_PICKER:
|
||||||
if (Utils.hasMultipleEnabledIMEsOrSubtypes(true /* include aux subtypes */)) {
|
if (SubtypeUtils.hasMultipleEnabledIMEsOrSubtypes(true /* include aux subtypes */)) {
|
||||||
mImm.showInputMethodPicker();
|
mImm.showInputMethodPicker();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -1295,7 +1296,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
|
||||||
final IBinder token = getWindow().getWindow().getAttributes().token;
|
final IBinder token = getWindow().getWindow().getAttributes().token;
|
||||||
if (mShouldSwitchToLastSubtype) {
|
if (mShouldSwitchToLastSubtype) {
|
||||||
final InputMethodSubtypeCompatWrapper lastSubtype = mImm.getLastInputMethodSubtype();
|
final InputMethodSubtypeCompatWrapper lastSubtype = mImm.getLastInputMethodSubtype();
|
||||||
final boolean lastSubtypeBelongsToThisIme = Utils.checkIfSubtypeBelongsToThisIme(
|
final boolean lastSubtypeBelongsToThisIme = SubtypeUtils.checkIfSubtypeBelongsToThisIme(
|
||||||
this, lastSubtype);
|
this, lastSubtype);
|
||||||
if ((includesOtherImes || lastSubtypeBelongsToThisIme)
|
if ((includesOtherImes || lastSubtypeBelongsToThisIme)
|
||||||
&& mImm.switchToLastInputMethod(token)) {
|
&& mImm.switchToLastInputMethod(token)) {
|
||||||
|
@ -1884,7 +1885,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
|
||||||
builder.addTypedWordAndPreviousSuggestions(typedWord, previousSuggestions);
|
builder.addTypedWordAndPreviousSuggestions(typedWord, previousSuggestions);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (Utils.shouldBlockAutoCorrectionBySafetyNet(builder, mSuggest)) {
|
if (Suggest.shouldBlockAutoCorrectionBySafetyNet(builder, mSuggest)) {
|
||||||
builder.setShouldBlockAutoCorrectionBySafetyNet();
|
builder.setShouldBlockAutoCorrectionBySafetyNet();
|
||||||
}
|
}
|
||||||
showSuggestions(builder.build(), typedWord);
|
showSuggestions(builder.build(), typedWord);
|
||||||
|
@ -2486,7 +2487,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
|
||||||
switch (position) {
|
switch (position) {
|
||||||
case 0:
|
case 0:
|
||||||
Intent intent = CompatUtils.getInputLanguageSelectionIntent(
|
Intent intent = CompatUtils.getInputLanguageSelectionIntent(
|
||||||
Utils.getInputMethodId(getPackageName()),
|
SubtypeUtils.getInputMethodId(getPackageName()),
|
||||||
Intent.FLAG_ACTIVITY_NEW_TASK
|
Intent.FLAG_ACTIVITY_NEW_TASK
|
||||||
| Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
|
| Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
|
||||||
| Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
| Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
||||||
|
|
|
@ -343,7 +343,7 @@ public class Settings extends InputMethodSettingsActivity
|
||||||
@Override
|
@Override
|
||||||
public boolean onPreferenceClick(Preference pref) {
|
public boolean onPreferenceClick(Preference pref) {
|
||||||
if (pref == mInputLanguageSelection) {
|
if (pref == mInputLanguageSelection) {
|
||||||
final String imeId = Utils.getInputMethodId(
|
final String imeId = SubtypeUtils.getInputMethodId(
|
||||||
getActivityInternal().getApplicationInfo().packageName);
|
getActivityInternal().getApplicationInfo().packageName);
|
||||||
startActivity(CompatUtils.getInputLanguageSelectionIntent(imeId, 0));
|
startActivity(CompatUtils.getInputLanguageSelectionIntent(imeId, 0));
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -326,9 +326,9 @@ public class SettingsValues {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (mIncludesOtherImesInLanguageSwitchList) {
|
if (mIncludesOtherImesInLanguageSwitchList) {
|
||||||
return Utils.hasMultipleEnabledIMEsOrSubtypes(/* include aux subtypes */false);
|
return SubtypeUtils.hasMultipleEnabledIMEsOrSubtypes(/* include aux subtypes */false);
|
||||||
} else {
|
} else {
|
||||||
return Utils.hasMultipleEnabledSubtypesInThisIme(
|
return SubtypeUtils.hasMultipleEnabledSubtypesInThisIme(
|
||||||
context, /* include aux subtypes */false);
|
context, /* include aux subtypes */false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,198 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2012 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.text.TextUtils;
|
||||||
|
import android.view.inputmethod.EditorInfo;
|
||||||
|
|
||||||
|
import com.android.inputmethod.keyboard.Keyboard;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
|
public class StringUtils {
|
||||||
|
private StringUtils() {
|
||||||
|
// This utility class is not publicly instantiable.
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean canBeFollowedByPeriod(final int codePoint) {
|
||||||
|
// TODO: Check again whether there really ain't a better way to check this.
|
||||||
|
// TODO: This should probably be language-dependant...
|
||||||
|
return Character.isLetterOrDigit(codePoint)
|
||||||
|
|| codePoint == Keyboard.CODE_SINGLE_QUOTE
|
||||||
|
|| codePoint == Keyboard.CODE_DOUBLE_QUOTE
|
||||||
|
|| codePoint == Keyboard.CODE_CLOSING_PARENTHESIS
|
||||||
|
|| codePoint == Keyboard.CODE_CLOSING_SQUARE_BRACKET
|
||||||
|
|| codePoint == Keyboard.CODE_CLOSING_CURLY_BRACKET
|
||||||
|
|| codePoint == Keyboard.CODE_CLOSING_ANGLE_BRACKET;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int codePointCount(String text) {
|
||||||
|
if (TextUtils.isEmpty(text)) return 0;
|
||||||
|
return text.codePointCount(0, text.length());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean containsInCsv(String key, String csv) {
|
||||||
|
if (csv == null)
|
||||||
|
return false;
|
||||||
|
for (String option : csv.split(",")) {
|
||||||
|
if (option.equals(key))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean inPrivateImeOptions(String packageName, String key,
|
||||||
|
EditorInfo editorInfo) {
|
||||||
|
if (editorInfo == null)
|
||||||
|
return false;
|
||||||
|
return containsInCsv(packageName != null ? packageName + "." + key : key,
|
||||||
|
editorInfo.privateImeOptions);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if a and b are equal ignoring the case of the character.
|
||||||
|
* @param a first character to check
|
||||||
|
* @param b second character to check
|
||||||
|
* @return {@code true} if a and b are equal, {@code false} otherwise.
|
||||||
|
*/
|
||||||
|
public static boolean equalsIgnoreCase(char a, char b) {
|
||||||
|
// Some language, such as Turkish, need testing both cases.
|
||||||
|
return a == b
|
||||||
|
|| Character.toLowerCase(a) == Character.toLowerCase(b)
|
||||||
|
|| Character.toUpperCase(a) == Character.toUpperCase(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if a and b are equal ignoring the case of the characters, including if they are
|
||||||
|
* both null.
|
||||||
|
* @param a first CharSequence to check
|
||||||
|
* @param b second CharSequence to check
|
||||||
|
* @return {@code true} if a and b are equal, {@code false} otherwise.
|
||||||
|
*/
|
||||||
|
public static boolean equalsIgnoreCase(CharSequence a, CharSequence b) {
|
||||||
|
if (a == b)
|
||||||
|
return true; // including both a and b are null.
|
||||||
|
if (a == null || b == null)
|
||||||
|
return false;
|
||||||
|
final int length = a.length();
|
||||||
|
if (length != b.length())
|
||||||
|
return false;
|
||||||
|
for (int i = 0; i < length; i++) {
|
||||||
|
if (!equalsIgnoreCase(a.charAt(i), b.charAt(i)))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if a and b are equal ignoring the case of the characters, including if a is null
|
||||||
|
* and b is zero length.
|
||||||
|
* @param a CharSequence to check
|
||||||
|
* @param b character array to check
|
||||||
|
* @param offset start offset of array b
|
||||||
|
* @param length length of characters in array b
|
||||||
|
* @return {@code true} if a and b are equal, {@code false} otherwise.
|
||||||
|
* @throws IndexOutOfBoundsException
|
||||||
|
* if {@code offset < 0 || length < 0 || offset + length > data.length}.
|
||||||
|
* @throws NullPointerException if {@code b == null}.
|
||||||
|
*/
|
||||||
|
public static boolean equalsIgnoreCase(CharSequence a, char[] b, int offset, int length) {
|
||||||
|
if (offset < 0 || length < 0 || length > b.length - offset)
|
||||||
|
throw new IndexOutOfBoundsException("array.length=" + b.length + " offset=" + offset
|
||||||
|
+ " length=" + length);
|
||||||
|
if (a == null)
|
||||||
|
return length == 0; // including a is null and b is zero length.
|
||||||
|
if (a.length() != length)
|
||||||
|
return false;
|
||||||
|
for (int i = 0; i < length; i++) {
|
||||||
|
if (!equalsIgnoreCase(a.charAt(i), b[offset + i]))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove duplicates from an array of strings.
|
||||||
|
*
|
||||||
|
* This method will always keep the first occurence of all strings at their position
|
||||||
|
* in the array, removing the subsequent ones.
|
||||||
|
*/
|
||||||
|
public static void removeDupes(final ArrayList<CharSequence> suggestions) {
|
||||||
|
if (suggestions.size() < 2) return;
|
||||||
|
int i = 1;
|
||||||
|
// Don't cache suggestions.size(), since we may be removing items
|
||||||
|
while (i < suggestions.size()) {
|
||||||
|
final CharSequence cur = suggestions.get(i);
|
||||||
|
// Compare each suggestion with each previous suggestion
|
||||||
|
for (int j = 0; j < i; j++) {
|
||||||
|
CharSequence previous = suggestions.get(j);
|
||||||
|
if (TextUtils.equals(cur, previous)) {
|
||||||
|
removeFromSuggestions(suggestions, i);
|
||||||
|
i--;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void removeFromSuggestions(final ArrayList<CharSequence> suggestions,
|
||||||
|
final int index) {
|
||||||
|
final CharSequence garbage = suggestions.remove(index);
|
||||||
|
if (garbage instanceof StringBuilder) {
|
||||||
|
StringBuilderPool.recycle((StringBuilder)garbage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getFullDisplayName(Locale locale, boolean returnsNameInThisLocale) {
|
||||||
|
if (returnsNameInThisLocale) {
|
||||||
|
return toTitleCase(SubtypeLocale.getFullDisplayName(locale), locale);
|
||||||
|
} else {
|
||||||
|
return toTitleCase(locale.getDisplayName(), locale);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getDisplayLanguage(Locale locale) {
|
||||||
|
return toTitleCase(SubtypeLocale.getFullDisplayName(locale), locale);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getMiddleDisplayLanguage(Locale locale) {
|
||||||
|
return toTitleCase((LocaleUtils.constructLocaleFromString(
|
||||||
|
locale.getLanguage()).getDisplayLanguage(locale)), locale);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getShortDisplayLanguage(Locale locale) {
|
||||||
|
return toTitleCase(locale.getLanguage(), locale);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String toTitleCase(String s, Locale locale) {
|
||||||
|
if (s.length() <= 1) {
|
||||||
|
// TODO: is this really correct? Shouldn't this be s.toUpperCase()?
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
// TODO: fix the bugs below
|
||||||
|
// - This does not work for Greek, because it returns upper case instead of title case.
|
||||||
|
// - It does not work for Serbian, because it fails to account for the "lj" character,
|
||||||
|
// which should be "Lj" in title case and "LJ" in upper case.
|
||||||
|
// - It does not work for Dutch, because it fails to account for the "ij" digraph, which
|
||||||
|
// are two different characters but both should be capitalized as "IJ" as if they were
|
||||||
|
// a single letter.
|
||||||
|
// - It also does not work with unicode surrogate code points.
|
||||||
|
return s.toUpperCase(locale).charAt(0) + s.substring(1);
|
||||||
|
}
|
||||||
|
}
|
|
@ -512,7 +512,7 @@ public class SubtypeSwitcher {
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getInputLanguageName() {
|
public String getInputLanguageName() {
|
||||||
return Utils.getDisplayLanguage(getInputLocale());
|
return StringUtils.getDisplayLanguage(getInputLocale());
|
||||||
}
|
}
|
||||||
|
|
||||||
/////////////////////////////
|
/////////////////////////////
|
||||||
|
|
|
@ -0,0 +1,135 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2012 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 com.android.inputmethod.compat.InputMethodInfoCompatWrapper;
|
||||||
|
import com.android.inputmethod.compat.InputMethodManagerCompatWrapper;
|
||||||
|
import com.android.inputmethod.compat.InputMethodSubtypeCompatWrapper;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class SubtypeUtils {
|
||||||
|
private SubtypeUtils() {
|
||||||
|
// This utility class is not publicly instantiable.
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Cache my InputMethodInfo and/or InputMethodSubtype list.
|
||||||
|
public static boolean checkIfSubtypeBelongsToThisIme(Context context,
|
||||||
|
InputMethodSubtypeCompatWrapper ims) {
|
||||||
|
final InputMethodManagerCompatWrapper imm = InputMethodManagerCompatWrapper.getInstance();
|
||||||
|
if (imm == null) return false;
|
||||||
|
|
||||||
|
final InputMethodInfoCompatWrapper myImi = getInputMethodInfo(context.getPackageName());
|
||||||
|
final List<InputMethodSubtypeCompatWrapper> subtypes =
|
||||||
|
imm.getEnabledInputMethodSubtypeList(myImi, true);
|
||||||
|
for (final InputMethodSubtypeCompatWrapper subtype : subtypes) {
|
||||||
|
if (subtype.equals(ims)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean hasMultipleEnabledIMEsOrSubtypes(
|
||||||
|
final boolean shouldIncludeAuxiliarySubtypes) {
|
||||||
|
final InputMethodManagerCompatWrapper imm = InputMethodManagerCompatWrapper.getInstance();
|
||||||
|
if (imm == null) return false;
|
||||||
|
|
||||||
|
final List<InputMethodInfoCompatWrapper> enabledImis = imm.getEnabledInputMethodList();
|
||||||
|
return hasMultipleEnabledSubtypes(shouldIncludeAuxiliarySubtypes, enabledImis);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean hasMultipleEnabledSubtypesInThisIme(Context context,
|
||||||
|
final boolean shouldIncludeAuxiliarySubtypes) {
|
||||||
|
final InputMethodInfoCompatWrapper myImi = getInputMethodInfo(context.getPackageName());
|
||||||
|
final List<InputMethodInfoCompatWrapper> imiList = Collections.singletonList(myImi);
|
||||||
|
return hasMultipleEnabledSubtypes(shouldIncludeAuxiliarySubtypes, imiList);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean hasMultipleEnabledSubtypes(final boolean shouldIncludeAuxiliarySubtypes,
|
||||||
|
List<InputMethodInfoCompatWrapper> imiList) {
|
||||||
|
final InputMethodManagerCompatWrapper imm = InputMethodManagerCompatWrapper.getInstance();
|
||||||
|
if (imm == null) return false;
|
||||||
|
|
||||||
|
// Number of the filtered IMEs
|
||||||
|
int filteredImisCount = 0;
|
||||||
|
|
||||||
|
for (InputMethodInfoCompatWrapper imi : imiList) {
|
||||||
|
// We can return true immediately after we find two or more filtered IMEs.
|
||||||
|
if (filteredImisCount > 1) return true;
|
||||||
|
final List<InputMethodSubtypeCompatWrapper> subtypes =
|
||||||
|
imm.getEnabledInputMethodSubtypeList(imi, true);
|
||||||
|
// IMEs that have no subtypes should be counted.
|
||||||
|
if (subtypes.isEmpty()) {
|
||||||
|
++filteredImisCount;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
int auxCount = 0;
|
||||||
|
for (InputMethodSubtypeCompatWrapper subtype : subtypes) {
|
||||||
|
if (subtype.isAuxiliary()) {
|
||||||
|
++auxCount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
final int nonAuxCount = subtypes.size() - auxCount;
|
||||||
|
|
||||||
|
// IMEs that have one or more non-auxiliary subtypes should be counted.
|
||||||
|
// If shouldIncludeAuxiliarySubtypes is true, IMEs that have two or more auxiliary
|
||||||
|
// subtypes should be counted as well.
|
||||||
|
if (nonAuxCount > 0 || (shouldIncludeAuxiliarySubtypes && auxCount > 1)) {
|
||||||
|
++filteredImisCount;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (filteredImisCount > 1) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
final List<InputMethodSubtypeCompatWrapper> subtypes =
|
||||||
|
imm.getEnabledInputMethodSubtypeList(null, true);
|
||||||
|
int keyboardCount = 0;
|
||||||
|
// imm.getEnabledInputMethodSubtypeList(null, true) will return the current IME's
|
||||||
|
// both explicitly and implicitly enabled input method subtype.
|
||||||
|
// (The current IME should be LatinIME.)
|
||||||
|
for (InputMethodSubtypeCompatWrapper subtype : subtypes) {
|
||||||
|
if (SubtypeSwitcher.KEYBOARD_MODE.equals(subtype.getMode())) {
|
||||||
|
++keyboardCount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return keyboardCount > 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getInputMethodId(String packageName) {
|
||||||
|
return getInputMethodInfo(packageName).getId();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static InputMethodInfoCompatWrapper getInputMethodInfo(String packageName) {
|
||||||
|
final InputMethodManagerCompatWrapper imm = InputMethodManagerCompatWrapper.getInstance();
|
||||||
|
if (imm == null) {
|
||||||
|
throw new RuntimeException("Input method manager not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
for (final InputMethodInfoCompatWrapper imi : imm.getEnabledInputMethodList()) {
|
||||||
|
if (imi.getPackageName().equals(packageName))
|
||||||
|
return imi;
|
||||||
|
}
|
||||||
|
throw new RuntimeException("Can not find input method id for " + packageName);
|
||||||
|
}
|
||||||
|
}
|
|
@ -108,6 +108,8 @@ public class Suggest implements Dictionary.WordCallback {
|
||||||
private boolean mIsAllUpperCase;
|
private boolean mIsAllUpperCase;
|
||||||
private int mTrailingSingleQuotesCount;
|
private int mTrailingSingleQuotesCount;
|
||||||
|
|
||||||
|
private static final int MINIMUM_SAFETY_NET_CHAR_LENGTH = 4;
|
||||||
|
|
||||||
public Suggest(final Context context, final int dictionaryResId, final Locale locale) {
|
public Suggest(final Context context, final int dictionaryResId, final Locale locale) {
|
||||||
initAsynchronously(context, dictionaryResId, locale);
|
initAsynchronously(context, dictionaryResId, locale);
|
||||||
}
|
}
|
||||||
|
@ -383,7 +385,7 @@ public class Suggest implements Dictionary.WordCallback {
|
||||||
if (typedWord != null) {
|
if (typedWord != null) {
|
||||||
mSuggestions.add(0, typedWord.toString());
|
mSuggestions.add(0, typedWord.toString());
|
||||||
}
|
}
|
||||||
Utils.removeDupes(mSuggestions);
|
StringUtils.removeDupes(mSuggestions);
|
||||||
|
|
||||||
if (DBG) {
|
if (DBG) {
|
||||||
double normalizedScore = mAutoCorrection.getNormalizedScore();
|
double normalizedScore = mAutoCorrection.getNormalizedScore();
|
||||||
|
@ -434,7 +436,7 @@ public class Suggest implements Dictionary.WordCallback {
|
||||||
int pos = 0;
|
int pos = 0;
|
||||||
|
|
||||||
// Check if it's the same word, only caps are different
|
// Check if it's the same word, only caps are different
|
||||||
if (Utils.equalsIgnoreCase(mConsideredWord, word, offset, length)) {
|
if (StringUtils.equalsIgnoreCase(mConsideredWord, word, offset, length)) {
|
||||||
// TODO: remove this surrounding if clause and move this logic to
|
// TODO: remove this surrounding if clause and move this logic to
|
||||||
// getSuggestedWordBuilder.
|
// getSuggestedWordBuilder.
|
||||||
if (suggestions.size() > 0) {
|
if (suggestions.size() > 0) {
|
||||||
|
@ -443,7 +445,7 @@ public class Suggest implements Dictionary.WordCallback {
|
||||||
// frequency to determine the insertion position. This does not ensure strictly
|
// frequency to determine the insertion position. This does not ensure strictly
|
||||||
// correct ordering, but ensures the top score is on top which is enough for
|
// correct ordering, but ensures the top score is on top which is enough for
|
||||||
// removing duplicates correctly.
|
// removing duplicates correctly.
|
||||||
if (Utils.equalsIgnoreCase(currentHighestWord, word, offset, length)
|
if (StringUtils.equalsIgnoreCase(currentHighestWord, word, offset, length)
|
||||||
&& score <= sortedScores[0]) {
|
&& score <= sortedScores[0]) {
|
||||||
pos = 1;
|
pos = 1;
|
||||||
}
|
}
|
||||||
|
@ -558,4 +560,46 @@ public class Suggest implements Dictionary.WordCallback {
|
||||||
}
|
}
|
||||||
mMainDict = null;
|
mMainDict = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Resolve the inconsistencies between the native auto correction algorithms and
|
||||||
|
// this safety net
|
||||||
|
public static boolean shouldBlockAutoCorrectionBySafetyNet(
|
||||||
|
SuggestedWords.Builder suggestedWordsBuilder, Suggest suggest) {
|
||||||
|
// Safety net for auto correction.
|
||||||
|
// Actually if we hit this safety net, it's actually a bug.
|
||||||
|
if (suggestedWordsBuilder.size() <= 1 || suggestedWordsBuilder.isTypedWordValid()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// If user selected aggressive auto correction mode, there is no need to use the safety
|
||||||
|
// net.
|
||||||
|
if (suggest.isAggressiveAutoCorrectionMode()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
final CharSequence typedWord = suggestedWordsBuilder.getWord(0);
|
||||||
|
// If the length of typed word is less than MINIMUM_SAFETY_NET_CHAR_LENGTH,
|
||||||
|
// we should not use net because relatively edit distance can be big.
|
||||||
|
if (typedWord.length() < Suggest.MINIMUM_SAFETY_NET_CHAR_LENGTH) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
final CharSequence suggestionWord = suggestedWordsBuilder.getWord(1);
|
||||||
|
final int typedWordLength = typedWord.length();
|
||||||
|
final int maxEditDistanceOfNativeDictionary =
|
||||||
|
(typedWordLength < 5 ? 2 : typedWordLength / 2) + 1;
|
||||||
|
final int distance = BinaryDictionary.editDistance(
|
||||||
|
typedWord.toString(), suggestionWord.toString());
|
||||||
|
if (DBG) {
|
||||||
|
Log.d(TAG, "Autocorrected edit distance = " + distance
|
||||||
|
+ ", " + maxEditDistanceOfNativeDictionary);
|
||||||
|
}
|
||||||
|
if (distance > maxEditDistanceOfNativeDictionary) {
|
||||||
|
if (DBG) {
|
||||||
|
Log.e(TAG, "Safety net: before = " + typedWord + ", after = " + suggestionWord);
|
||||||
|
Log.e(TAG, "(Error) The edit distance of this correction exceeds limit. "
|
||||||
|
+ "Turning off auto-correction.");
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,6 @@ package com.android.inputmethod.latin;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.content.res.Resources;
|
|
||||||
import android.inputmethodservice.InputMethodService;
|
import android.inputmethodservice.InputMethodService;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.AsyncTask;
|
import android.os.AsyncTask;
|
||||||
|
@ -27,19 +26,9 @@ import android.os.Environment;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.HandlerThread;
|
import android.os.HandlerThread;
|
||||||
import android.os.Process;
|
import android.os.Process;
|
||||||
import android.text.InputType;
|
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.text.format.DateUtils;
|
import android.text.format.DateUtils;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.inputmethod.EditorInfo;
|
|
||||||
|
|
||||||
import com.android.inputmethod.compat.InputMethodInfoCompatWrapper;
|
|
||||||
import com.android.inputmethod.compat.InputMethodManagerCompatWrapper;
|
|
||||||
import com.android.inputmethod.compat.InputMethodSubtypeCompatWrapper;
|
|
||||||
import com.android.inputmethod.compat.InputTypeCompatUtils;
|
|
||||||
import com.android.inputmethod.keyboard.Keyboard;
|
|
||||||
import com.android.inputmethod.keyboard.KeyboardId;
|
|
||||||
import com.android.inputmethod.latin.define.JniLibName;
|
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
@ -51,20 +40,11 @@ import java.io.IOException;
|
||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
import java.nio.channels.FileChannel;
|
import java.nio.channels.FileChannel;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Locale;
|
|
||||||
|
|
||||||
public class Utils {
|
public class Utils {
|
||||||
private static final String TAG = Utils.class.getSimpleName();
|
|
||||||
private static final int MINIMUM_SAFETY_NET_CHAR_LENGTH = 4;
|
|
||||||
private static boolean DBG = LatinImeLogger.sDBG;
|
|
||||||
private static boolean DBG_EDIT_DISTANCE = false;
|
|
||||||
|
|
||||||
private Utils() {
|
private Utils() {
|
||||||
// Intentional empty constructor for utility class.
|
// This utility class is not publicly instantiable.
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -118,166 +98,6 @@ public class Utils {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Move InputMethodSubtype related utility methods to its own utility class.
|
|
||||||
// TODO: Cache my InputMethodInfo and/or InputMethodSubtype list.
|
|
||||||
public static boolean checkIfSubtypeBelongsToThisIme(Context context,
|
|
||||||
InputMethodSubtypeCompatWrapper ims) {
|
|
||||||
final InputMethodManagerCompatWrapper imm = InputMethodManagerCompatWrapper.getInstance();
|
|
||||||
if (imm == null) return false;
|
|
||||||
|
|
||||||
final InputMethodInfoCompatWrapper myImi = Utils.getInputMethodInfo(
|
|
||||||
context.getPackageName());
|
|
||||||
final List<InputMethodSubtypeCompatWrapper> subtypes =
|
|
||||||
imm.getEnabledInputMethodSubtypeList(myImi, true);
|
|
||||||
for (final InputMethodSubtypeCompatWrapper subtype : subtypes) {
|
|
||||||
if (subtype.equals(ims)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean hasMultipleEnabledIMEsOrSubtypes(
|
|
||||||
final boolean shouldIncludeAuxiliarySubtypes) {
|
|
||||||
final InputMethodManagerCompatWrapper imm = InputMethodManagerCompatWrapper.getInstance();
|
|
||||||
if (imm == null) return false;
|
|
||||||
|
|
||||||
final List<InputMethodInfoCompatWrapper> enabledImis = imm.getEnabledInputMethodList();
|
|
||||||
return hasMultipleEnabledSubtypes(shouldIncludeAuxiliarySubtypes, enabledImis);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean hasMultipleEnabledSubtypesInThisIme(Context context,
|
|
||||||
final boolean shouldIncludeAuxiliarySubtypes) {
|
|
||||||
final InputMethodInfoCompatWrapper myImi = Utils.getInputMethodInfo(
|
|
||||||
context.getPackageName());
|
|
||||||
final List<InputMethodInfoCompatWrapper> imiList = Collections.singletonList(myImi);
|
|
||||||
return Utils.hasMultipleEnabledSubtypes(shouldIncludeAuxiliarySubtypes, imiList);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean hasMultipleEnabledSubtypes(final boolean shouldIncludeAuxiliarySubtypes,
|
|
||||||
List<InputMethodInfoCompatWrapper> imiList) {
|
|
||||||
final InputMethodManagerCompatWrapper imm = InputMethodManagerCompatWrapper.getInstance();
|
|
||||||
if (imm == null) return false;
|
|
||||||
|
|
||||||
// Number of the filtered IMEs
|
|
||||||
int filteredImisCount = 0;
|
|
||||||
|
|
||||||
for (InputMethodInfoCompatWrapper imi : imiList) {
|
|
||||||
// We can return true immediately after we find two or more filtered IMEs.
|
|
||||||
if (filteredImisCount > 1) return true;
|
|
||||||
final List<InputMethodSubtypeCompatWrapper> subtypes =
|
|
||||||
imm.getEnabledInputMethodSubtypeList(imi, true);
|
|
||||||
// IMEs that have no subtypes should be counted.
|
|
||||||
if (subtypes.isEmpty()) {
|
|
||||||
++filteredImisCount;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
int auxCount = 0;
|
|
||||||
for (InputMethodSubtypeCompatWrapper subtype : subtypes) {
|
|
||||||
if (subtype.isAuxiliary()) {
|
|
||||||
++auxCount;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
final int nonAuxCount = subtypes.size() - auxCount;
|
|
||||||
|
|
||||||
// IMEs that have one or more non-auxiliary subtypes should be counted.
|
|
||||||
// If shouldIncludeAuxiliarySubtypes is true, IMEs that have two or more auxiliary
|
|
||||||
// subtypes should be counted as well.
|
|
||||||
if (nonAuxCount > 0 || (shouldIncludeAuxiliarySubtypes && auxCount > 1)) {
|
|
||||||
++filteredImisCount;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (filteredImisCount > 1) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
final List<InputMethodSubtypeCompatWrapper> subtypes =
|
|
||||||
imm.getEnabledInputMethodSubtypeList(null, true);
|
|
||||||
int keyboardCount = 0;
|
|
||||||
// imm.getEnabledInputMethodSubtypeList(null, true) will return the current IME's
|
|
||||||
// both explicitly and implicitly enabled input method subtype.
|
|
||||||
// (The current IME should be LatinIME.)
|
|
||||||
for (InputMethodSubtypeCompatWrapper subtype : subtypes) {
|
|
||||||
if (SubtypeSwitcher.KEYBOARD_MODE.equals(subtype.getMode())) {
|
|
||||||
++keyboardCount;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return keyboardCount > 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String getInputMethodId(String packageName) {
|
|
||||||
return getInputMethodInfo(packageName).getId();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static InputMethodInfoCompatWrapper getInputMethodInfo(String packageName) {
|
|
||||||
final InputMethodManagerCompatWrapper imm = InputMethodManagerCompatWrapper.getInstance();
|
|
||||||
if (imm == null) {
|
|
||||||
throw new RuntimeException("Input method manager not found");
|
|
||||||
}
|
|
||||||
|
|
||||||
for (final InputMethodInfoCompatWrapper imi : imm.getEnabledInputMethodList()) {
|
|
||||||
if (imi.getPackageName().equals(packageName))
|
|
||||||
return imi;
|
|
||||||
}
|
|
||||||
throw new RuntimeException("Can not find input method id for " + packageName);
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Resolve the inconsistencies between the native auto correction algorithms and
|
|
||||||
// this safety net
|
|
||||||
public static boolean shouldBlockAutoCorrectionBySafetyNet(
|
|
||||||
SuggestedWords.Builder suggestedWordsBuilder, Suggest suggest) {
|
|
||||||
// Safety net for auto correction.
|
|
||||||
// Actually if we hit this safety net, it's actually a bug.
|
|
||||||
if (suggestedWordsBuilder.size() <= 1 || suggestedWordsBuilder.isTypedWordValid()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// If user selected aggressive auto correction mode, there is no need to use the safety
|
|
||||||
// net.
|
|
||||||
if (suggest.isAggressiveAutoCorrectionMode()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
final CharSequence typedWord = suggestedWordsBuilder.getWord(0);
|
|
||||||
// If the length of typed word is less than MINIMUM_SAFETY_NET_CHAR_LENGTH,
|
|
||||||
// we should not use net because relatively edit distance can be big.
|
|
||||||
if (typedWord.length() < MINIMUM_SAFETY_NET_CHAR_LENGTH) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
final CharSequence suggestionWord = suggestedWordsBuilder.getWord(1);
|
|
||||||
final int typedWordLength = typedWord.length();
|
|
||||||
final int maxEditDistanceOfNativeDictionary =
|
|
||||||
(typedWordLength < 5 ? 2 : typedWordLength / 2) + 1;
|
|
||||||
final int distance = BinaryDictionary.editDistance(
|
|
||||||
typedWord.toString(), suggestionWord.toString());
|
|
||||||
if (DBG) {
|
|
||||||
Log.d(TAG, "Autocorrected edit distance = " + distance
|
|
||||||
+ ", " + maxEditDistanceOfNativeDictionary);
|
|
||||||
}
|
|
||||||
if (distance > maxEditDistanceOfNativeDictionary) {
|
|
||||||
if (DBG) {
|
|
||||||
Log.e(TAG, "Safety net: before = " + typedWord + ", after = " + suggestionWord);
|
|
||||||
Log.e(TAG, "(Error) The edit distance of this correction exceeds limit. "
|
|
||||||
+ "Turning off auto-correction.");
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean canBeFollowedByPeriod(final int codePoint) {
|
|
||||||
// TODO: Check again whether there really ain't a better way to check this.
|
|
||||||
// TODO: This should probably be language-dependant...
|
|
||||||
return Character.isLetterOrDigit(codePoint)
|
|
||||||
|| codePoint == Keyboard.CODE_SINGLE_QUOTE
|
|
||||||
|| codePoint == Keyboard.CODE_DOUBLE_QUOTE
|
|
||||||
|| codePoint == Keyboard.CODE_CLOSING_PARENTHESIS
|
|
||||||
|| codePoint == Keyboard.CODE_CLOSING_SQUARE_BRACKET
|
|
||||||
|| codePoint == Keyboard.CODE_CLOSING_CURLY_BRACKET
|
|
||||||
|| codePoint == Keyboard.CODE_CLOSING_ANGLE_BRACKET;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* package */ static class RingCharBuffer {
|
/* package */ static class RingCharBuffer {
|
||||||
private static RingCharBuffer sRingCharBuffer = new RingCharBuffer();
|
private static RingCharBuffer sRingCharBuffer = new RingCharBuffer();
|
||||||
private static final char PLACEHOLDER_DELIMITER_CHAR = '\uFFFC';
|
private static final char PLACEHOLDER_DELIMITER_CHAR = '\uFFFC';
|
||||||
|
@ -600,147 +420,6 @@ public class Utils {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Move this method to KeyboardSet class.
|
|
||||||
public static int getKeyboardMode(EditorInfo editorInfo) {
|
|
||||||
if (editorInfo == null)
|
|
||||||
return KeyboardId.MODE_TEXT;
|
|
||||||
|
|
||||||
final int inputType = editorInfo.inputType;
|
|
||||||
final int variation = inputType & InputType.TYPE_MASK_VARIATION;
|
|
||||||
|
|
||||||
switch (inputType & InputType.TYPE_MASK_CLASS) {
|
|
||||||
case InputType.TYPE_CLASS_NUMBER:
|
|
||||||
return KeyboardId.MODE_NUMBER;
|
|
||||||
case InputType.TYPE_CLASS_DATETIME:
|
|
||||||
switch (variation) {
|
|
||||||
case InputType.TYPE_DATETIME_VARIATION_DATE:
|
|
||||||
return KeyboardId.MODE_DATE;
|
|
||||||
case InputType.TYPE_DATETIME_VARIATION_TIME:
|
|
||||||
return KeyboardId.MODE_TIME;
|
|
||||||
default: // InputType.TYPE_DATETIME_VARIATION_NORMAL
|
|
||||||
return KeyboardId.MODE_DATETIME;
|
|
||||||
}
|
|
||||||
case InputType.TYPE_CLASS_PHONE:
|
|
||||||
return KeyboardId.MODE_PHONE;
|
|
||||||
case InputType.TYPE_CLASS_TEXT:
|
|
||||||
if (InputTypeCompatUtils.isEmailVariation(variation)) {
|
|
||||||
return KeyboardId.MODE_EMAIL;
|
|
||||||
} else if (variation == InputType.TYPE_TEXT_VARIATION_URI) {
|
|
||||||
return KeyboardId.MODE_URL;
|
|
||||||
} else if (variation == InputType.TYPE_TEXT_VARIATION_SHORT_MESSAGE) {
|
|
||||||
return KeyboardId.MODE_IM;
|
|
||||||
} else if (variation == InputType.TYPE_TEXT_VARIATION_FILTER) {
|
|
||||||
return KeyboardId.MODE_TEXT;
|
|
||||||
} else {
|
|
||||||
return KeyboardId.MODE_TEXT;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return KeyboardId.MODE_TEXT;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean containsInCsv(String key, String csv) {
|
|
||||||
if (csv == null)
|
|
||||||
return false;
|
|
||||||
for (String option : csv.split(",")) {
|
|
||||||
if (option.equals(key))
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean inPrivateImeOptions(String packageName, String key,
|
|
||||||
EditorInfo editorInfo) {
|
|
||||||
if (editorInfo == null)
|
|
||||||
return false;
|
|
||||||
return containsInCsv(packageName != null ? packageName + "." + key : key,
|
|
||||||
editorInfo.privateImeOptions);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a main dictionary resource id
|
|
||||||
* @return main dictionary resource id
|
|
||||||
*/
|
|
||||||
public static int getMainDictionaryResourceId(Resources res) {
|
|
||||||
final String MAIN_DIC_NAME = "main";
|
|
||||||
String packageName = LatinIME.class.getPackage().getName();
|
|
||||||
return res.getIdentifier(MAIN_DIC_NAME, "raw", packageName);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void loadNativeLibrary() {
|
|
||||||
try {
|
|
||||||
System.loadLibrary(JniLibName.JNI_LIB_NAME);
|
|
||||||
} catch (UnsatisfiedLinkError ule) {
|
|
||||||
Log.e(TAG, "Could not load native library " + JniLibName.JNI_LIB_NAME);
|
|
||||||
if (LatinImeLogger.sDBG) {
|
|
||||||
throw new RuntimeException(
|
|
||||||
"Could not load native library " + JniLibName.JNI_LIB_NAME);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns true if a and b are equal ignoring the case of the character.
|
|
||||||
* @param a first character to check
|
|
||||||
* @param b second character to check
|
|
||||||
* @return {@code true} if a and b are equal, {@code false} otherwise.
|
|
||||||
*/
|
|
||||||
public static boolean equalsIgnoreCase(char a, char b) {
|
|
||||||
// Some language, such as Turkish, need testing both cases.
|
|
||||||
return a == b
|
|
||||||
|| Character.toLowerCase(a) == Character.toLowerCase(b)
|
|
||||||
|| Character.toUpperCase(a) == Character.toUpperCase(b);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns true if a and b are equal ignoring the case of the characters, including if they are
|
|
||||||
* both null.
|
|
||||||
* @param a first CharSequence to check
|
|
||||||
* @param b second CharSequence to check
|
|
||||||
* @return {@code true} if a and b are equal, {@code false} otherwise.
|
|
||||||
*/
|
|
||||||
public static boolean equalsIgnoreCase(CharSequence a, CharSequence b) {
|
|
||||||
if (a == b)
|
|
||||||
return true; // including both a and b are null.
|
|
||||||
if (a == null || b == null)
|
|
||||||
return false;
|
|
||||||
final int length = a.length();
|
|
||||||
if (length != b.length())
|
|
||||||
return false;
|
|
||||||
for (int i = 0; i < length; i++) {
|
|
||||||
if (!equalsIgnoreCase(a.charAt(i), b.charAt(i)))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns true if a and b are equal ignoring the case of the characters, including if a is null
|
|
||||||
* and b is zero length.
|
|
||||||
* @param a CharSequence to check
|
|
||||||
* @param b character array to check
|
|
||||||
* @param offset start offset of array b
|
|
||||||
* @param length length of characters in array b
|
|
||||||
* @return {@code true} if a and b are equal, {@code false} otherwise.
|
|
||||||
* @throws IndexOutOfBoundsException
|
|
||||||
* if {@code offset < 0 || length < 0 || offset + length > data.length}.
|
|
||||||
* @throws NullPointerException if {@code b == null}.
|
|
||||||
*/
|
|
||||||
public static boolean equalsIgnoreCase(CharSequence a, char[] b, int offset, int length) {
|
|
||||||
if (offset < 0 || length < 0 || length > b.length - offset)
|
|
||||||
throw new IndexOutOfBoundsException("array.length=" + b.length + " offset=" + offset
|
|
||||||
+ " length=" + length);
|
|
||||||
if (a == null)
|
|
||||||
return length == 0; // including a is null and b is zero length.
|
|
||||||
if (a.length() != length)
|
|
||||||
return false;
|
|
||||||
for (int i = 0; i < length; i++) {
|
|
||||||
if (!equalsIgnoreCase(a.charAt(i), b[offset + i]))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static float getDipScale(Context context) {
|
public static float getDipScale(Context context) {
|
||||||
final float scale = context.getResources().getDisplayMetrics().density;
|
final float scale = context.getResources().getDisplayMetrics().density;
|
||||||
return scale;
|
return scale;
|
||||||
|
@ -751,76 +430,6 @@ public class Utils {
|
||||||
return (int) (dip * scale + 0.5);
|
return (int) (dip * scale + 0.5);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove duplicates from an array of strings.
|
|
||||||
*
|
|
||||||
* This method will always keep the first occurence of all strings at their position
|
|
||||||
* in the array, removing the subsequent ones.
|
|
||||||
*/
|
|
||||||
public static void removeDupes(final ArrayList<CharSequence> suggestions) {
|
|
||||||
if (suggestions.size() < 2) return;
|
|
||||||
int i = 1;
|
|
||||||
// Don't cache suggestions.size(), since we may be removing items
|
|
||||||
while (i < suggestions.size()) {
|
|
||||||
final CharSequence cur = suggestions.get(i);
|
|
||||||
// Compare each suggestion with each previous suggestion
|
|
||||||
for (int j = 0; j < i; j++) {
|
|
||||||
CharSequence previous = suggestions.get(j);
|
|
||||||
if (TextUtils.equals(cur, previous)) {
|
|
||||||
removeFromSuggestions(suggestions, i);
|
|
||||||
i--;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void removeFromSuggestions(final ArrayList<CharSequence> suggestions,
|
|
||||||
final int index) {
|
|
||||||
final CharSequence garbage = suggestions.remove(index);
|
|
||||||
if (garbage instanceof StringBuilder) {
|
|
||||||
StringBuilderPool.recycle((StringBuilder)garbage);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String getFullDisplayName(Locale locale, boolean returnsNameInThisLocale) {
|
|
||||||
if (returnsNameInThisLocale) {
|
|
||||||
return toTitleCase(SubtypeLocale.getFullDisplayName(locale), locale);
|
|
||||||
} else {
|
|
||||||
return toTitleCase(locale.getDisplayName(), locale);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String getDisplayLanguage(Locale locale) {
|
|
||||||
return toTitleCase(SubtypeLocale.getFullDisplayName(locale), locale);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String getMiddleDisplayLanguage(Locale locale) {
|
|
||||||
return toTitleCase((LocaleUtils.constructLocaleFromString(
|
|
||||||
locale.getLanguage()).getDisplayLanguage(locale)), locale);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String getShortDisplayLanguage(Locale locale) {
|
|
||||||
return toTitleCase(locale.getLanguage(), locale);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String toTitleCase(String s, Locale locale) {
|
|
||||||
if (s.length() <= 1) {
|
|
||||||
// TODO: is this really correct? Shouldn't this be s.toUpperCase()?
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
// TODO: fix the bugs below
|
|
||||||
// - This does not work for Greek, because it returns upper case instead of title case.
|
|
||||||
// - It does not work for Serbian, because it fails to account for the "lj" character,
|
|
||||||
// which should be "Lj" in title case and "LJ" in upper case.
|
|
||||||
// - It does not work for Dutch, because it fails to account for the "ij" digraph, which
|
|
||||||
// are two different characters but both should be capitalized as "IJ" as if they were
|
|
||||||
// a single letter.
|
|
||||||
// - It also does not work with unicode surrogate code points.
|
|
||||||
return s.toUpperCase(locale).charAt(0) + s.substring(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class Stats {
|
public static class Stats {
|
||||||
public static void onNonSeparator(final char code, final int x,
|
public static void onNonSeparator(final char code, final int x,
|
||||||
final int y) {
|
final int y) {
|
||||||
|
@ -845,9 +454,4 @@ public class Utils {
|
||||||
LatinImeLogger.logOnAutoCorrectionCancelled();
|
LatinImeLogger.logOnAutoCorrectionCancelled();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int codePointCount(String text) {
|
|
||||||
if (TextUtils.isEmpty(text)) return 0;
|
|
||||||
return text.codePointCount(0, text.length());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,9 +37,9 @@ import com.android.inputmethod.latin.DictionaryFactory;
|
||||||
import com.android.inputmethod.latin.Flag;
|
import com.android.inputmethod.latin.Flag;
|
||||||
import com.android.inputmethod.latin.LocaleUtils;
|
import com.android.inputmethod.latin.LocaleUtils;
|
||||||
import com.android.inputmethod.latin.R;
|
import com.android.inputmethod.latin.R;
|
||||||
|
import com.android.inputmethod.latin.StringUtils;
|
||||||
import com.android.inputmethod.latin.SynchronouslyLoadedContactsDictionary;
|
import com.android.inputmethod.latin.SynchronouslyLoadedContactsDictionary;
|
||||||
import com.android.inputmethod.latin.SynchronouslyLoadedUserDictionary;
|
import com.android.inputmethod.latin.SynchronouslyLoadedUserDictionary;
|
||||||
import com.android.inputmethod.latin.Utils;
|
|
||||||
import com.android.inputmethod.latin.WhitelistDictionary;
|
import com.android.inputmethod.latin.WhitelistDictionary;
|
||||||
import com.android.inputmethod.latin.WordComposer;
|
import com.android.inputmethod.latin.WordComposer;
|
||||||
|
|
||||||
|
@ -47,11 +47,11 @@ import java.lang.ref.WeakReference;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.TreeMap;
|
import java.util.TreeMap;
|
||||||
import java.util.HashSet;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Service for spell checking, using LatinIME's dictionaries and mechanisms.
|
* Service for spell checking, using LatinIME's dictionaries and mechanisms.
|
||||||
|
@ -316,7 +316,7 @@ public class AndroidSpellCheckerService extends SpellCheckerService
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Collections.reverse(mSuggestions);
|
Collections.reverse(mSuggestions);
|
||||||
Utils.removeDupes(mSuggestions);
|
StringUtils.removeDupes(mSuggestions);
|
||||||
if (CAPITALIZE_ALL == capitalizeType) {
|
if (CAPITALIZE_ALL == capitalizeType) {
|
||||||
for (int i = 0; i < mSuggestions.size(); ++i) {
|
for (int i = 0; i < mSuggestions.size(); ++i) {
|
||||||
// get(i) returns a CharSequence which is actually a String so .toString()
|
// get(i) returns a CharSequence which is actually a String so .toString()
|
||||||
|
@ -326,7 +326,7 @@ public class AndroidSpellCheckerService extends SpellCheckerService
|
||||||
} else if (CAPITALIZE_FIRST == capitalizeType) {
|
} else if (CAPITALIZE_FIRST == capitalizeType) {
|
||||||
for (int i = 0; i < mSuggestions.size(); ++i) {
|
for (int i = 0; i < mSuggestions.size(); ++i) {
|
||||||
// Likewise
|
// Likewise
|
||||||
mSuggestions.set(i, Utils.toTitleCase(mSuggestions.get(i).toString(),
|
mSuggestions.set(i, StringUtils.toTitleCase(mSuggestions.get(i).toString(),
|
||||||
locale));
|
locale));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -396,7 +396,7 @@ public class AndroidSpellCheckerService extends SpellCheckerService
|
||||||
final ProximityInfo proximityInfo = ProximityInfo.createSpellCheckerProximityInfo(
|
final ProximityInfo proximityInfo = ProximityInfo.createSpellCheckerProximityInfo(
|
||||||
SpellCheckerProximityInfo.getProximityForScript(script));
|
SpellCheckerProximityInfo.getProximityForScript(script));
|
||||||
final Resources resources = getResources();
|
final Resources resources = getResources();
|
||||||
final int fallbackResourceId = Utils.getMainDictionaryResourceId(resources);
|
final int fallbackResourceId = DictionaryFactory.getMainDictionaryResourceId(resources);
|
||||||
final DictionaryCollection dictionaryCollection =
|
final DictionaryCollection dictionaryCollection =
|
||||||
DictionaryFactory.createDictionaryFromManager(this, locale, fallbackResourceId,
|
DictionaryFactory.createDictionaryFromManager(this, locale, fallbackResourceId,
|
||||||
USE_FULL_EDIT_DISTANCE_FLAG_ARRAY);
|
USE_FULL_EDIT_DISTANCE_FLAG_ARRAY);
|
||||||
|
|
Loading…
Reference in New Issue